GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-flicker-gui.c
1/*
2 * gnc-flicker-gui.c --
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, contact:
16 *
17 * Free Software Foundation Voice: +1-617-542-5942
18 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
19 * Boston, MA 02110-1301, USA gnu@gnu.org
20 */
21
29#include <config.h>
30
31#include <gtk/gtk.h>
32#include <glib/gi18n.h>
33
34#include "dialog-utils.h"
35#include "gnc-flicker-gui.h"
36#include "gnc-state.h"
37#include "gnc-ui.h"
38
39#define GNC_PREFS_GROUP "dialogs.flicker"
40#define GNC_STATE_SECTION "Flicker"
41#define STATE_KEY_BAR_WIDTH "barwidth"
42#define STATE_KEY_DELAY "delay"
43
44#define BAR_WIDTH 44 /* Width of the flicker bars */
45#define BAR_HEIGHT 200 /* Height of the flicker bars */
46#define MARGIN 12 /* Distance between the flicker bars */
47#define DELAY 50 /* Pause between the flickering painting */
48
49static guint flicker_data (char const *challenge);
50static gboolean time_handler (GtkWidget *widget);
51static void do_marker_drawing (cairo_t *cr);
52static void draw_bit (cairo_t *cr, _Bool bit, int i);
53static void do_flicker_drawing (GtkWidget *widget, cairo_t *cr);
54static void do_flicker_load_state (GtkWidget *dialog);
55static void do_flicker_store_state (GtkWidget *dialog);
56static gboolean on_flicker_challenge_draw (GtkWidget *widget, cairo_t *cr,
57 gpointer user_data);
58static void on_flicker_challenge_map (GtkWidget *widget);
59static void on_flicker_challenge_destroy (GtkWidget *widget, gpointer user_data);
60static gboolean on_flicker_marker_draw (GtkWidget *widget, cairo_t *cr,
61 gpointer user_data);
62static void on_flicker_marker_map (GtkWidget *widget);
63static void on_spin_barwidth_value_changed (GtkSpinButton *spin, GtkWidget *widget);
64static void on_spin_delay_value_changed (GtkSpinButton *spin, GtkWidget *widget);
65static void on_dialog_destroy (GtkWidget *dialog, gpointer user_data);
66
67/* structured data for the flicker variables */
69 const char *challenge;
70 guint challenge_length;
71 guint margin; /* Distance between bars */
72 guint barwidth; /* Bar width */
73 guint barheight; /* Bar height */
74 guint x_barpos; /* x-value for the position of the bar */
75 guint y_barpos; /* y-value for the position of the bar */
76 guint x_drawpos; /* x-value of the first painting position */
77 guint y_drawpos; /* y-value of the first painting position */
78 guint height; /* Height of the drawing area */
79 guint width; /* Width of the drawing area */
80 guint delay; /* Waiting time between frames in milliseconds */
81 guint halfbyteid;
82 guint clock;
83 guint interval;
84 gboolean change_interval;
85};
86static struct Flickerdraw flickerdraw;
87
88static GncFlickerGui *flickergui = NULL;
89static _Bool bitarray[255][5];
90
91/* this function will return number corresponding 0,1,2..,9,A,B,C,D,E,F */
92static guint
93get_num (const char ch)
94{
95 int num =0;
96 if (ch >= '0' && ch <= '9')
97 num = ch - 0x30;
98 else
99 {
100 switch (ch)
101 {
102 case 'A': case 'a': num = 10; break;
103 case 'B': case 'b': num = 11; break;
104 case 'C': case 'c': num = 12; break;
105 case 'D': case 'd': num = 13; break;
106 case 'E': case 'e': num = 14; break;
107 case 'F': case 'f': num = 15; break;
108 default: num = 0;
109 }
110 }
111 /* The bank challenge has been verified by Aqbanking,
112 * so I assume that no error can occur. */
113 return num;
114}
115
116/* convert the bank challenge into the 5 bits for the flicker data */
117static guint
118flicker_data (const char *challenge)
119{
120 /* bitfield is a clock bit and a 4-bit code with the bits reversed
121 (bit 1 is the least significant and bit 4 the most
122 so 0x1 is 1000 and 0x8 is 0001) */
123 static const _Bool bits[16][5] =
124 {
125 {0, 0, 0, 0, 0}, {0, 1, 0, 0, 0}, {0, 0, 1, 0, 0}, {0, 1, 1, 0, 0},
126 {0, 0, 0, 1, 0}, {0, 1, 0, 1, 0}, {0, 0, 1, 1, 0}, {0, 1, 1, 1, 0},
127 {0, 0, 0, 0, 1}, {0, 1, 0, 0, 1}, {0, 0, 1, 0, 1}, {0, 1, 1, 0, 1},
128 {0, 0, 0, 1, 1}, {0, 1, 0, 1, 1}, {0, 0, 1, 1, 1}, {0, 1, 1, 1, 1}
129 };
130
131 /* prepend synchronization identifier */
132 char* code = g_strdup_printf ("0FFF%s", challenge);
133 guint challenge_length = strlen (code);
134
135 /* Swap the position of the bits in pairs throughout the bank challenge
136 (low-order nibble first). */
137 for (guint i = 0; i < challenge_length; i += 2)
138 {
139 guint val1 = get_num (code[i]);
140 guint val2 = get_num (code[i+1]);
141
142 memcpy (&bitarray[i], bits[val2], sizeof(bits[val2]));
143 memcpy (&bitarray[i+1], bits[val1], sizeof(bits[val1]));
144 }
145 g_free (code);
146
147 return challenge_length;
148}
149
150/* A timer for redrawing the flickering painting, is started here and
151 * called up again when the "Delay" value is changed */
152static gboolean
153time_handler (GtkWidget *widget)
154{
155 /* Change of waiting time */
156 if (flickerdraw.change_interval)
157 {
158 g_source_remove (flickerdraw.interval);
159 flickerdraw.interval = g_timeout_add (flickerdraw.delay,
160 (GSourceFunc) time_handler,
161 (gpointer) widget);
162 flickerdraw.change_interval = FALSE;
163 return FALSE;
164 }
165 gtk_widget_queue_draw (widget);
166
167 return TRUE;
168}
169
170/* Show the colored triangle as a pointer for the position of the TAN generator */
171static void
172do_marker_drawing (cairo_t *cr)
173{
174 guint pos1;
175 guint pos2;
176
177 /* Initialize the drawing area to black */
178 cairo_set_source_rgb (cr, 0, 0, 0);
179 cairo_paint (cr);
180
181 cairo_set_source_rgb (cr, 0.9, 0.1, 0.1);
182 /* draw the left triangle */
183 pos1 = flickerdraw.x_drawpos + flickerdraw.barwidth / 2;
184 cairo_move_to (cr, pos1, 20);
185 cairo_line_to (cr, pos1 + 10, 2);
186 cairo_line_to (cr, pos1 - 10, 2);
187 cairo_close_path (cr);
188 cairo_stroke_preserve (cr);
189 cairo_fill (cr);
190
191 /* draw the right triangle */
192 pos2 = flickerdraw.x_drawpos + 4 * flickerdraw.margin + 4 * flickerdraw.barwidth +
193 flickerdraw.barwidth / 2;
194 cairo_move_to (cr, pos2, 20);
195 cairo_line_to (cr, pos2 + 10, 2);
196 cairo_line_to (cr, pos2 - 10, 2);
197 cairo_close_path (cr);
198 cairo_stroke_preserve (cr);
199 cairo_fill (cr);
200}
201
202/* draws the 5 flickering bars of the bank data into the drawing area */
203static void
204draw_bit (cairo_t *cr, _Bool bit, int i)
205{
206 if (bit & 1)
207 cairo_set_source_rgb (cr, 1, 1, 1);
208 else
209 cairo_set_source_rgb (cr, 0, 0, 0);
210
211 flickerdraw.x_barpos = flickerdraw.x_drawpos + i * flickerdraw.margin +
212 i * flickerdraw.barwidth;
213 cairo_rectangle (cr, flickerdraw.x_barpos, flickerdraw.y_barpos,
214 flickerdraw.barwidth, flickerdraw.barheight);
215 cairo_fill (cr);
216}
217
218/* Prepares the drawing area for the flicker graphic. */
219static void
220do_flicker_drawing (GtkWidget *widget, cairo_t *cr)
221{
222 /* Always align the flicker display in the middle of the drawing area */
223 flickerdraw.width = gtk_widget_get_allocated_width (widget);
224
225 /* Start position of the first bar */
226 flickerdraw.x_drawpos = (flickerdraw.width - 4 * flickerdraw.margin -
227 5 * flickerdraw.barwidth) / 2;
228
229 /* Initialize the drawing area to black */
230 cairo_set_source_rgb (cr, 0, 0, 0);
231 cairo_paint (cr);
232
233 /* paint the flicker graphic */
234 bitarray[flickerdraw.halfbyteid][0] = flickerdraw.clock;
235 draw_bit (cr, flickerdraw.clock, 0);
236 for (int i = 1; i <= 4; i++)
237 draw_bit (cr, bitarray[flickerdraw.halfbyteid][i], i);
238
239 /* Each flicker point is drawn twice. Once with clock = 1 and once with clock = 0 */
240 if (!flickerdraw.clock)
241 {
242 flickerdraw.clock = 1;
243 flickerdraw.halfbyteid++;
244 if (flickerdraw.halfbyteid >= flickerdraw.challenge_length)
245 flickerdraw.halfbyteid = 0;
246 }
247 else if (flickerdraw.clock)
248 flickerdraw.clock = 0;
249}
250
251/* Load the state of the GUI (Size of the Dialog, Value of the Spinbutton) */
252static void
253do_flicker_load_state (GtkWidget *dialog)
254{
255 /* Load the values in the spin button */
256 GKeyFile *state_file = gnc_state_get_current ();
257
258 if (g_key_file_has_key (state_file, GNC_STATE_SECTION, STATE_KEY_BAR_WIDTH, NULL))
259 flickerdraw.barwidth = g_key_file_get_integer (state_file,
260 GNC_STATE_SECTION,
261 STATE_KEY_BAR_WIDTH, NULL);
262 else
263 flickerdraw.barwidth = BAR_WIDTH;
264
265 if (g_key_file_has_key (state_file, GNC_STATE_SECTION, STATE_KEY_DELAY, NULL))
266 flickerdraw.delay = g_key_file_get_integer (state_file,
267 GNC_STATE_SECTION,
268 STATE_KEY_DELAY, NULL);
269 else
270 flickerdraw.delay = DELAY;
271
272 /* Load window size and position */
273 gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW (dialog),
275}
276
277/* Stores the state of the GUI (Size of the Dialog, Value of the Spinbutton) */
278static void
279do_flicker_store_state (GtkWidget *dialog)
280{
281 /* Save the values in the spin button */
282 GKeyFile *state_file = gnc_state_get_current ();
283
284 if (flickerdraw.barwidth != BAR_WIDTH)
285 g_key_file_set_integer (state_file, GNC_STATE_SECTION,
286 STATE_KEY_BAR_WIDTH, flickerdraw.barwidth);
287 else if (g_key_file_has_key (state_file, GNC_STATE_SECTION,
288 STATE_KEY_BAR_WIDTH, NULL))
289 g_key_file_remove_key (state_file, GNC_STATE_SECTION,
290 STATE_KEY_BAR_WIDTH, NULL);
291
292 if (flickerdraw.delay != DELAY)
293 g_key_file_set_integer (state_file, GNC_STATE_SECTION,
294 STATE_KEY_DELAY, flickerdraw.delay);
295 else if (g_key_file_has_key (state_file, GNC_STATE_SECTION,
296 STATE_KEY_DELAY, NULL))
297 g_key_file_remove_key (state_file, GNC_STATE_SECTION,
298 STATE_KEY_DELAY, NULL);
299
300 /* Save window size and position */
301 gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW (dialog));
302}
303
304/* This signal is emitted when the drawing area "flicker challenge" is visible */
305static void
306on_flicker_challenge_map (GtkWidget *widget)
307{
308 flickerdraw.challenge_length = flicker_data (flickerdraw.challenge);
309
310 /* Set the height of the drawing area */
311 flickerdraw.height = flickerdraw.barheight + 2 * flickerdraw.y_barpos;
312 gtk_widget_set_size_request (widget, -1, flickerdraw.height);
313
314 /* Call up the time function and start the flicker display */
315 flickerdraw.interval = g_timeout_add (flickerdraw.delay,
316 (GSourceFunc) time_handler,
317 (gpointer) widget);
318}
319
320/* Initialize the drawingarea to black and paint the flickerchallenge */
321static gboolean
322on_flicker_challenge_draw (GtkWidget *widget, cairo_t *cr,
323 __attribute__((unused)) gpointer user_data)
324{
325 do_flicker_drawing (widget, cr);
326
327 return FALSE;
328}
329
330/* called when the drawing area is destroyed */
331static void
332on_flicker_challenge_destroy (GtkWidget *widget,
333 __attribute__((unused)) gpointer user_data)
334{
335 /* remove the timeout function */
336 g_source_remove (flickerdraw.interval);
337}
338
339/* Initialize the drawing area "flicker marker" in black and draw the marker for
340 * the position of the TAN-Generator */
341static gboolean
342on_flicker_marker_draw (__attribute__((unused)) GtkWidget *widget, cairo_t *cr,
343 __attribute__((unused)) gpointer data)
344{
345 do_marker_drawing (cr);
346
347 return FALSE;
348}
349
350/* This signal is emitted when the drawing area "flicker marker" is visible */
351static void
352on_flicker_marker_map (GtkWidget *widget)
353{
354 /* Set the height of the drawing area */
355 gtk_widget_set_size_request (widget, -1, flickerdraw.y_barpos);
356}
357
358/* The value for "Field width" has been changed on the spin button and the
359 * flicker display is updated */
360static void
361on_spin_barwidth_value_changed (GtkSpinButton *spin, GtkWidget *widget)
362{
363 flickerdraw.barwidth = gtk_spin_button_get_value_as_int (spin);
364 flickerdraw.x_drawpos = (flickerdraw.width - 4 * flickerdraw.margin -
365 5 * flickerdraw.barwidth) / 2;
366
367 /* Moving the position triangles */
368 gtk_widget_queue_draw (widget);
369}
370
371/* The value for "waiting time" was changed on the spin button and
372 * the speed of the flickering display is updated */
373static void
374on_spin_delay_value_changed (GtkSpinButton *spin, GtkWidget *widget)
375{
376 flickerdraw.delay = gtk_spin_button_get_value_as_int (spin);
377
378 flickerdraw.change_interval = TRUE;
379 time_handler (widget);
380}
381
382static void
383on_dialog_destroy (GtkWidget *dialog, __attribute__((unused)) gpointer user_data)
384{
385 /* Store window size and initial setting values */
386 do_flicker_store_state (dialog);
387}
388
389/* The widgets for the GUI are prepared and the first parameters are set */
390void
391ini_flicker_gui (const char *pChallenge, GncFlickerGui *gui)
392{
393 /* Establish reference to the dialog widgets created in gnc_gwen_gui */
394 flickergui = gui;
395
396 /* Load window size and initial setting values */
397 do_flicker_load_state (GTK_WIDGET (flickergui->dialog));
398
399 /* Initialize application */
400 flickerdraw.barheight = BAR_HEIGHT;
401 flickerdraw.margin = MARGIN;
402 flickerdraw.y_barpos = 20; /* First painting position */
403 flickerdraw.halfbyteid = 0;
404 flickerdraw.clock = 1;
405
406 flickerdraw.challenge = pChallenge;
407
408 g_signal_connect (GTK_WINDOW (flickergui->dialog), "destroy",
409 G_CALLBACK (on_dialog_destroy), NULL);
410
411 g_signal_connect (GTK_WIDGET (flickergui->flicker_challenge), "map",
412 G_CALLBACK (on_flicker_challenge_map), NULL);
413 g_signal_connect (GTK_WIDGET (flickergui->flicker_challenge), "draw",
414 G_CALLBACK (on_flicker_challenge_draw), NULL);
415 g_signal_connect (GTK_WIDGET (flickergui->flicker_challenge), "destroy",
416 G_CALLBACK (on_flicker_challenge_destroy), NULL);
417
418 g_signal_connect (GTK_WIDGET (flickergui->flicker_marker), "map",
419 G_CALLBACK (on_flicker_marker_map), NULL);
420 g_signal_connect (GTK_WIDGET (flickergui->flicker_marker), "draw",
421 G_CALLBACK (on_flicker_marker_draw), NULL);
422
423 flickergui->adj_barwidth = gtk_adjustment_new (0.0, 10.0, 80.0, 1.0, 10.0, 0.0);
424 gtk_spin_button_set_adjustment (flickergui->spin_barwidth, flickergui->adj_barwidth);
425 gtk_spin_button_set_value (GTK_SPIN_BUTTON (flickergui->spin_barwidth),
426 flickerdraw.barwidth);
427 g_signal_connect (GTK_WIDGET (flickergui->spin_barwidth), "value-changed",
428 G_CALLBACK (on_spin_barwidth_value_changed),
429 flickergui->flicker_marker);
430 gtk_widget_set_focus_on_click (GTK_WIDGET (flickergui->spin_barwidth), FALSE);
431
432 flickergui->adj_delay = gtk_adjustment_new (0.0, 10.0, 100.0, 10.0, 10.0, 0.0);
433 gtk_spin_button_set_adjustment (flickergui->spin_delay, flickergui->adj_delay);
434 gtk_spin_button_set_value (GTK_SPIN_BUTTON (flickergui->spin_delay),
435 flickerdraw.delay);
436 g_signal_connect (GTK_WIDGET (flickergui->spin_delay), "value-changed",
437 G_CALLBACK (on_spin_delay_value_changed),
438 flickergui->flicker_challenge);
439 gtk_widget_set_focus_on_click (GTK_WIDGET (flickergui->spin_delay), FALSE);
440
441 gtk_widget_grab_focus (GTK_WIDGET (flickergui->input_entry));
442}
GUI callbacks for Flicker and ChipTAN(optisch)
Functions to load, save and get gui state.
void ini_flicker_gui(const char *pChallenge, GncFlickerGui *gui)
Initialize the dialog and drawing area.
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition gnc-state.c:248