1 /*
2  * TilEm II
3  *
4  * Copyright (c) 2010-2011 Thibault Duponchelle
5  * Copyright (c) 2010-2012 Benjamin Moody
6  *
7  * This program is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <gtk/gtk.h>
27 #include <glib/gstdio.h>
28 #include <ticalcs.h>
29 #include <tilem.h>
30 
31 #include "gui.h"
32 #include "files.h"
33 #include "msgbox.h"
34 
35 /* Set size hints for the toplevel window */
set_size_hints(GtkWidget * widget,gpointer data)36 static void set_size_hints(GtkWidget *widget, gpointer data)
37 {
38 	TilemEmulatorWindow *ewin = data;
39 
40 	/* Don't use gtk_window_set_geometry_hints() (which would
41 	   appear to do what we want) because, in addition to setting
42 	   the hints we want, that function causes GTK+ to argue with
43 	   the window manager.
44 
45 	   Instead, we call this function after the check-resize
46 	   signal (which is when GTK+ itself would normally set the
47 	   hints.)
48 
49 	   FIXME: check that this works as desired on Win32/Quartz. */
50 
51 	if (gtk_widget_get_window(widget))
52 		gdk_window_set_geometry_hints(gtk_widget_get_window(widget),
53 		                              &ewin->geomhints,
54 		                              ewin->geomhintmask);
55 }
56 
window_state_changed(G_GNUC_UNUSED GtkWidget * w,GdkEventWindowState * event,gpointer data)57 static void window_state_changed(G_GNUC_UNUSED GtkWidget *w,
58                                  GdkEventWindowState *event, gpointer data)
59 {
60 	TilemEmulatorWindow *ewin = data;
61 	ewin->window_state = event->new_window_state;
62 }
63 
window_maximized(TilemEmulatorWindow * ewin)64 static gboolean window_maximized(TilemEmulatorWindow *ewin)
65 {
66 	return (ewin->window_state & (GDK_WINDOW_STATE_MAXIMIZED
67 	                              | GDK_WINDOW_STATE_FULLSCREEN));
68 }
69 
screen_repaint(GtkWidget * w,GdkEventExpose * ev G_GNUC_UNUSED,TilemEmulatorWindow * ewin)70 static gboolean screen_repaint(GtkWidget *w, GdkEventExpose *ev G_GNUC_UNUSED,
71                                TilemEmulatorWindow *ewin)
72 {
73 	GtkAllocation alloc;
74 	GdkWindow *win;
75 	GtkStyle *style;
76 
77 	gtk_widget_get_allocation(w, &alloc);
78 
79 	/* If image buffer is not the correct size, allocate a new one */
80 
81 	if (!ewin->lcd_image_buf
82 	    || alloc.width != ewin->lcd_image_width
83 	    || alloc.height != ewin->lcd_image_height) {
84 		ewin->lcd_image_width = alloc.width;
85 		ewin->lcd_image_height = alloc.height;
86 		g_free(ewin->lcd_image_buf);
87 		ewin->lcd_image_buf = g_new(byte, alloc.width * alloc.height);
88 	}
89 
90 	/* Draw LCD contents into the image buffer */
91 
92 	g_mutex_lock(ewin->emu->lcd_mutex);
93 	ewin->emu->lcd_update_pending = FALSE;
94 	tilem_draw_lcd_image_indexed(ewin->emu->lcd_buffer,
95 	                             ewin->lcd_image_buf,
96 	                             alloc.width, alloc.height, alloc.width,
97 	                             (ewin->lcd_smooth_scale
98 	                              ? TILEM_SCALE_SMOOTH
99 	                              : TILEM_SCALE_FAST));
100 	g_mutex_unlock(ewin->emu->lcd_mutex);
101 
102 	/* Render buffer to the screen */
103 
104 	win = gtk_widget_get_window(w);
105 	style = gtk_widget_get_style(w);
106 	gdk_draw_indexed_image(win, style->fg_gc[GTK_STATE_NORMAL], 0, 0,
107 	                       alloc.width, alloc.height, GDK_RGB_DITHER_NONE,
108 	                       ewin->lcd_image_buf, alloc.width,
109 	                       ewin->lcd_cmap);
110 	return TRUE;
111 }
112 
113 /* Set the color palette for drawing the emulated LCD. */
screen_restyle(GtkWidget * w,GtkStyle * oldstyle G_GNUC_UNUSED,TilemEmulatorWindow * ewin)114 static void screen_restyle(GtkWidget* w, GtkStyle* oldstyle G_GNUC_UNUSED,
115                            TilemEmulatorWindow* ewin)
116 {
117 	dword* palette;
118 	GtkStyle *style;
119 	int r_dark, g_dark, b_dark;
120 	int r_light, g_light, b_light;
121 	double gamma = 2.2;
122 
123 	if (!ewin->skin) {
124 		/* no skin -> use standard GTK colors */
125 
126 		style = gtk_widget_get_style(w);
127 
128 		r_dark = style->text[GTK_STATE_NORMAL].red / 257;
129 		g_dark = style->text[GTK_STATE_NORMAL].green / 257;
130 		b_dark = style->text[GTK_STATE_NORMAL].blue / 257;
131 
132 		r_light = style->base[GTK_STATE_NORMAL].red / 257;
133 		g_light = style->base[GTK_STATE_NORMAL].green / 257;
134 		b_light = style->base[GTK_STATE_NORMAL].blue / 257;
135 	}
136 	else {
137 		/* use skin colors */
138 
139 		r_dark = ((ewin->skin->lcd_black >> 16) & 0xff);
140 		g_dark = ((ewin->skin->lcd_black >> 8) & 0xff);
141 		b_dark = (ewin->skin->lcd_black & 0xff);
142 
143 		r_light = ((ewin->skin->lcd_white >> 16) & 0xff);
144 		g_light = ((ewin->skin->lcd_white >> 8) & 0xff);
145 		b_light = (ewin->skin->lcd_white & 0xff);
146 	}
147 
148 	/* Generate a new palette, and convert it into GDK format */
149 
150 	if (ewin->lcd_cmap)
151 		gdk_rgb_cmap_free(ewin->lcd_cmap);
152 
153 	palette = tilem_color_palette_new(r_light, g_light, b_light,
154 					  r_dark, g_dark, b_dark, gamma);
155 	ewin->lcd_cmap = gdk_rgb_cmap_new(palette, 256);
156 	tilem_free(palette);
157 
158 	gtk_widget_queue_draw(ewin->lcd);
159 }
160 
skin_size_allocate(GtkWidget * widget,GtkAllocation * alloc,gpointer data)161 static void skin_size_allocate(GtkWidget *widget, GtkAllocation *alloc,
162                                gpointer data)
163 {
164 	TilemEmulatorWindow *ewin = data;
165 	int rawwidth, rawheight, scaledwidth, scaledheight;
166 	int lcdleft, lcdright, lcdtop, lcdbottom;
167 	double rx, ry, r;
168 
169 	g_return_if_fail(ewin->skin != NULL);
170 
171 	rawwidth = gdk_pixbuf_get_width(ewin->skin->raw);
172 	rawheight = gdk_pixbuf_get_height(ewin->skin->raw);
173 
174 	rx = (double) alloc->width / rawwidth;
175 	ry = (double) alloc->height / rawheight;
176 	r = MIN(rx, ry);
177 
178 	scaledwidth = rawwidth * r;
179 	scaledheight = rawheight * r;
180 
181 	if (ewin->skin->width == scaledwidth
182 	    && ewin->skin->height == scaledheight)
183 		return;
184 
185 	ewin->skin->width = scaledwidth;
186 	ewin->skin->height = scaledheight;
187 	ewin->skin->sx = ewin->skin->sy = 1.0 / r;
188 
189 	if (ewin->skin->image)
190 		g_object_unref(ewin->skin->image);
191 	ewin->skin->image = gdk_pixbuf_scale_simple(ewin->skin->raw,
192 	                                            scaledwidth,
193 	                                            scaledheight,
194 	                                            GDK_INTERP_BILINEAR);
195 
196 	gtk_image_set_from_pixbuf(GTK_IMAGE(ewin->background),
197 	                          ewin->skin->image);
198 
199 	lcdleft = ewin->skin->lcd_pos.left * r + 0.5;
200 	lcdright = ewin->skin->lcd_pos.right * r + 0.5;
201 	lcdtop = ewin->skin->lcd_pos.top * r + 0.5;
202 	lcdbottom = ewin->skin->lcd_pos.bottom * r + 0.5;
203 
204 	gtk_widget_set_size_request(ewin->lcd,
205 	                            MAX(lcdright - lcdleft, 1),
206 	                            MAX(lcdbottom - lcdtop, 1));
207 
208 	gtk_layout_move(GTK_LAYOUT(widget), ewin->lcd,
209 	                lcdleft, lcdtop);
210 
211 	ewin->zoom_factor = r / ewin->base_zoom;
212 
213 	if (ewin->zoom_factor <= 1.0)
214 		ewin->zoom_factor = 1.0;
215 }
216 
noskin_size_allocate(G_GNUC_UNUSED GtkWidget * widget,GtkAllocation * alloc,gpointer data)217 static void noskin_size_allocate(G_GNUC_UNUSED GtkWidget *widget,
218                                  GtkAllocation *alloc, gpointer data)
219 {
220 	TilemEmulatorWindow *ewin = data;
221 	int lcdwidth, lcdheight;
222 
223 	g_return_if_fail(ewin->emu->calc != NULL);
224 
225 	lcdwidth = ewin->emu->calc->hw.lcdwidth;
226 	lcdheight = ewin->emu->calc->hw.lcdheight;
227 
228 	if (alloc->width > alloc->height)
229 		ewin->zoom_factor = (gdouble) alloc->width / lcdwidth;
230 	else
231 		ewin->zoom_factor = (gdouble) alloc->height / lcdheight;
232 
233 	if (ewin->zoom_factor <= 1.0)
234 		ewin->zoom_factor = 1.0;
235 }
236 
237 /* Used when you load another skin */
redraw_screen(TilemEmulatorWindow * ewin)238 void redraw_screen(TilemEmulatorWindow *ewin)
239 {
240 	GtkWidget *pImage;
241 	GtkWidget *emuwin;
242 	int lcdwidth, lcdheight;
243 	int screenwidth, screenheight;
244 	int minwidth, minheight, defwidth, defheight,
245 		curwidth, curheight;
246 	double sx, sy, s, a1, a2;
247 	GError *err = NULL;
248 
249 	if (ewin->skin) {
250 		skin_unload(ewin->skin);
251 		g_free(ewin->skin);
252 	}
253 
254 	if (ewin->skin_disabled || !ewin->skin_file_name) {
255 		ewin->skin = NULL;
256 	}
257 	else {
258 		ewin->skin = g_new0(SKIN_INFOS, 1);
259 		if (skin_load(ewin->skin, ewin->skin_file_name, &err)) {
260 			skin_unload(ewin->skin);
261 			ewin->skin = NULL;
262 		}
263 	}
264 
265 	if (ewin->emu->calc) {
266 		lcdwidth = ewin->emu->calc->hw.lcdwidth;
267 		lcdheight = ewin->emu->calc->hw.lcdheight;
268 	}
269 	else {
270 		lcdwidth = lcdheight = 1;
271 	}
272 
273 	if (ewin->lcd)
274 		gtk_widget_destroy(ewin->lcd);
275 	if (ewin->background)
276 		gtk_widget_destroy(ewin->background);
277 	if (ewin->layout)
278 		gtk_widget_destroy(ewin->layout);
279 
280 	/* create LCD widget */
281 	ewin->lcd = gtk_drawing_area_new();
282 	gtk_widget_set_double_buffered(ewin->lcd, FALSE);
283 
284 	/* create background image and layout */
285 	if (ewin->skin) {
286 		ewin->layout = gtk_layout_new(NULL, NULL);
287 
288 		pImage = gtk_image_new();
289 		gtk_layout_put(GTK_LAYOUT(ewin->layout), pImage, 0, 0);
290 		ewin->background = pImage;
291 
292 		screenwidth = (ewin->skin->lcd_pos.right
293 		               - ewin->skin->lcd_pos.left);
294 		screenheight = (ewin->skin->lcd_pos.bottom
295 		                - ewin->skin->lcd_pos.top);
296 
297 		gtk_widget_set_size_request(ewin->lcd,
298 		                            screenwidth, screenheight);
299 		gtk_layout_put(GTK_LAYOUT(ewin->layout), ewin->lcd,
300 		               ewin->skin->lcd_pos.left,
301 		               ewin->skin->lcd_pos.top);
302 
303 		g_signal_connect(ewin->layout, "size-allocate",
304 		                 G_CALLBACK(skin_size_allocate), ewin);
305 
306 		emuwin = ewin->layout;
307 
308 		defwidth = ewin->skin->width;
309 		defheight = ewin->skin->height;
310 
311 		sx = (double) lcdwidth / screenwidth;
312 		sy = (double) lcdheight / screenheight;
313 		s = MAX(sx, sy);
314 		minwidth = defwidth * s + 0.5;
315 		minheight = defheight * s + 0.5;
316 		ewin->base_zoom = s;
317 	}
318 	else {
319 		ewin->layout = NULL;
320 		ewin->background = NULL;
321 
322 		emuwin = ewin->lcd;
323 
324 		g_signal_connect(ewin->lcd, "size-allocate",
325 		                 G_CALLBACK(noskin_size_allocate), ewin);
326 
327 		defwidth = minwidth = lcdwidth;
328 		defheight = minheight = lcdheight;
329 		ewin->base_zoom = 1.0;
330 	}
331 
332 	curwidth = defwidth * ewin->base_zoom * ewin->zoom_factor + 0.5;
333 	curheight = defheight * ewin->base_zoom * ewin->zoom_factor + 0.5;
334 
335 	gtk_widget_set_can_focus(emuwin, TRUE);
336 
337 	gtk_widget_add_events(emuwin, (GDK_BUTTON_PRESS_MASK
338 	                               | GDK_BUTTON_RELEASE_MASK
339 	                               | GDK_BUTTON1_MOTION_MASK
340 	                               | GDK_POINTER_MOTION_HINT_MASK
341 				       | GDK_DROP_FINISHED
342 				       | GDK_DRAG_MOTION));
343 
344 	g_signal_connect(ewin->lcd, "expose-event",
345 	                 G_CALLBACK(screen_repaint), ewin);
346 	g_signal_connect(ewin->lcd, "style-set",
347 	                 G_CALLBACK(screen_restyle), ewin);
348 
349 	g_signal_connect(emuwin, "button-press-event",
350 	                 G_CALLBACK(mouse_press_event), ewin);
351 	g_signal_connect(emuwin, "motion-notify-event",
352 	                 G_CALLBACK(pointer_motion_event), ewin);
353 	g_signal_connect(emuwin, "button-release-event",
354 	                 G_CALLBACK(mouse_release_event), ewin);
355 	g_signal_connect(emuwin, "popup-menu",
356 	                 G_CALLBACK(popup_menu_event), ewin);
357 
358 	/* FIXME: this is rather broken; GTK_DEST_DEFAULT_ALL sends a
359 	   successful "finished" message to any drop that matches the
360 	   list of targets.  Files/URIs we can't accept should be
361 	   rejected, and we shouldn't send the "finished" message
362 	   until it's actually finished. */
363 	gtk_drag_dest_set(emuwin, GTK_DEST_DEFAULT_ALL,
364 	                  NULL, 0, GDK_ACTION_COPY);
365 	gtk_drag_dest_add_uri_targets(emuwin);
366 	g_signal_connect(emuwin, "drag-data-received",
367 	                 G_CALLBACK(drag_data_received), ewin);
368 
369 
370 	/* Hint calculation assumes the emulator is the only thing in
371 	   the window; if other widgets are added, this will have to
372 	   change accordingly
373 	*/
374 	ewin->geomhints.min_width = minwidth;
375 	ewin->geomhints.min_height = minheight;
376 	a1 = (double) minwidth / minheight;
377 	a2 = (double) defwidth / defheight;
378 	ewin->geomhints.min_aspect = MIN(a1, a2) - 0.0001;
379 	ewin->geomhints.max_aspect = MAX(a1, a2) + 0.0001;
380 	ewin->geomhintmask = (GDK_HINT_MIN_SIZE | GDK_HINT_ASPECT);
381 
382 	/* If the window is already realized, set the hints now, so
383 	   that the WM will see the new hints before we try to resize
384 	   the window */
385 	set_size_hints(ewin->window, ewin);
386 
387 	gtk_widget_set_size_request(emuwin, minwidth, minheight);
388 	gtk_container_add(GTK_CONTAINER(ewin->window), emuwin);
389 
390 	if (!window_maximized(ewin))
391 		gtk_window_resize(GTK_WINDOW(ewin->window),
392 		                  curwidth, curheight);
393 
394 	gtk_widget_show_all(emuwin);
395 
396 	if (err) {
397 		messagebox01(GTK_WINDOW(ewin->window), GTK_MESSAGE_ERROR,
398 		             "Unable to load skin", "%s", err->message);
399 		g_error_free(err);
400 	}
401 }
402 
window_destroy(G_GNUC_UNUSED GtkWidget * w,gpointer data)403 static void window_destroy(G_GNUC_UNUSED GtkWidget *w, gpointer data)
404 {
405 	TilemEmulatorWindow *ewin = data;
406 
407 	if (!window_maximized(ewin))
408 		tilem_config_set("settings",
409 		                 "zoom/r", ewin->zoom_factor,
410 		                 NULL);
411 
412 	ewin->window = ewin->layout = ewin->lcd = ewin->background = NULL;
413 }
414 
tilem_emulator_window_new(TilemCalcEmulator * emu)415 TilemEmulatorWindow *tilem_emulator_window_new(TilemCalcEmulator *emu)
416 {
417 	TilemEmulatorWindow *ewin;
418 
419 	g_return_val_if_fail(emu != NULL, NULL);
420 
421 	ewin = g_slice_new0(TilemEmulatorWindow);
422 	ewin->emu = emu;
423 
424 	tilem_config_get("settings",
425 	                 "skin_disabled/b", &ewin->skin_disabled,
426 	                 "smooth_scaling/b=1", &ewin->lcd_smooth_scale,
427 	                 "zoom/r=2.0", &ewin->zoom_factor,
428 	                 NULL);
429 
430 	if (ewin->zoom_factor <= 1.0)
431 		ewin->zoom_factor = 1.0;
432 
433 	/* Create the window */
434 	ewin->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
435 
436 	g_signal_connect(ewin->window, "window-state-event",
437 	                 G_CALLBACK(window_state_changed), ewin);
438 	g_signal_connect(ewin->window, "destroy",
439 	                 G_CALLBACK(window_destroy), ewin);
440 
441 	g_signal_connect_after(ewin->window, "check-resize",
442 	                       G_CALLBACK(set_size_hints), ewin);
443 
444 	gtk_widget_add_events(ewin->window, (GDK_KEY_PRESS_MASK
445 	                                      | GDK_KEY_RELEASE_MASK));
446 
447 	g_signal_connect(ewin->window, "key-press-event",
448 	                 G_CALLBACK(key_press_event), ewin);
449 	g_signal_connect(ewin->window, "key-release-event",
450 	                 G_CALLBACK(key_release_event), ewin);
451 
452 	build_menu(ewin);
453 
454 	tilem_emulator_window_calc_changed(ewin);
455 
456 	return ewin;
457 }
458 
tilem_emulator_window_free(TilemEmulatorWindow * ewin)459 void tilem_emulator_window_free(TilemEmulatorWindow *ewin)
460 {
461 	g_return_if_fail(ewin != NULL);
462 
463 	if (ewin->lcd)
464 		gtk_widget_destroy(ewin->lcd);
465 	if (ewin->background)
466 		gtk_widget_destroy(ewin->background);
467 	if (ewin->layout)
468 		gtk_widget_destroy(ewin->layout);
469 	if (ewin->window)
470 		gtk_widget_destroy(ewin->window);
471 	if (ewin->popup_menu)
472 		gtk_widget_destroy(ewin->popup_menu);
473 	if (ewin->actions)
474 		g_object_unref(ewin->actions);
475 
476 	g_free(ewin->lcd_image_buf);
477 
478 	g_free(ewin->skin_file_name);
479 	if (ewin->skin) {
480 		skin_unload(ewin->skin);
481 		g_free(ewin->skin);
482 	}
483 
484 	if (ewin->lcd_cmap)
485 		gdk_rgb_cmap_free(ewin->lcd_cmap);
486 
487 	g_slice_free(TilemEmulatorWindow, ewin);
488 }
489 
tilem_emulator_window_set_skin(TilemEmulatorWindow * ewin,const char * filename)490 void tilem_emulator_window_set_skin(TilemEmulatorWindow *ewin,
491                                     const char *filename)
492 {
493 	g_return_if_fail(ewin != NULL);
494 
495 	g_free(ewin->skin_file_name);
496 	if (filename)
497 		ewin->skin_file_name = g_strdup(filename);
498 	else
499 		ewin->skin_file_name = NULL;
500 	redraw_screen(ewin);
501 }
502 
503 /* Switch between skin and LCD-only mode */
tilem_emulator_window_set_skin_disabled(TilemEmulatorWindow * ewin,gboolean disabled)504 void tilem_emulator_window_set_skin_disabled(TilemEmulatorWindow *ewin,
505                                              gboolean disabled)
506 {
507 	g_return_if_fail(ewin != NULL);
508 
509 	if (ewin->skin_disabled != !!disabled) {
510 		ewin->skin_disabled = !!disabled;
511 		redraw_screen(ewin);
512 	}
513 }
514 
tilem_emulator_window_calc_changed(TilemEmulatorWindow * ewin)515 void tilem_emulator_window_calc_changed(TilemEmulatorWindow *ewin)
516 {
517 	const char *model;
518 	char *name = NULL, *path;
519 
520 	g_return_if_fail(ewin != NULL);
521 	g_return_if_fail(ewin->emu != NULL);
522 
523 	g_free(ewin->skin_file_name);
524 	ewin->skin_file_name = NULL;
525 
526 	if (!ewin->emu->calc)
527 		return;
528 
529 	model = ewin->emu->calc->hw.name;
530 
531 	tilem_config_get(model,
532 	                 "skin/f", &name,
533 	                 NULL);
534 
535 	if (!name)
536 		name = g_strdup_printf("%s.skn", model);
537 
538 	if (!g_path_is_absolute(name)) {
539 		path = get_shared_file_path("skins", name, NULL);
540 		tilem_emulator_window_set_skin(ewin, path);
541 		g_free(path);
542 	}
543 	else {
544 		tilem_emulator_window_set_skin(ewin, name);
545 	}
546 
547 	g_free(name);
548 }
549 
tilem_emulator_window_refresh_lcd(TilemEmulatorWindow * ewin)550 void tilem_emulator_window_refresh_lcd(TilemEmulatorWindow *ewin)
551 {
552 	g_return_if_fail(ewin != NULL);
553 	if (ewin->lcd)
554 		gtk_widget_queue_draw(ewin->lcd);
555 }
556 
557 
558 
559 
560 /* Display the lcd image into the terminal */
display_lcdimage_into_terminal(TilemEmulatorWindow * ewin)561 void display_lcdimage_into_terminal(TilemEmulatorWindow *ewin)
562 {
563 
564 	int width, height;
565 	guchar* lcddata;
566 	int x, y;
567 	char c;
568 	width = ewin->emu->calc->hw.lcdwidth;
569 	height = ewin->emu->calc->hw.lcdheight;
570 	FILE* lcd_content_file;
571 	/* Alloc mmem */
572 	lcddata = g_new(guchar, (width / 8) * height);
573 
574 	/* Get the lcd content using the function 's pointer from Benjamin's core */
575 	(*ewin->emu->calc->hw.get_lcd)(ewin->emu->calc, lcddata);
576 
577 	/* Print a little demo just for fun;) */
578 	printf("\n\n\n");
579 	printf("	 r     rr    r  rrrrr  rrr  r     rrrrr r   r  rr    r    rr     r                      \n");
580 	printf("  r     r     r     r     r     r   r     r     rr rr    r    r     r     r     r     r     r   \n");
581 	printf("   r   r      r    r      r     r   r     r     r r r   r      r    r      r     r     r     r  \n");
582 	printf("rrrrr r      r     r      r     r   r     rrrr  r r r  r       r     r      r rrrrr rrrrr rrrrr \n");
583 	printf("   r   r      r    r      r     r   r     r     r   r  rrr     r    r      r     r     r     r  \n");
584 	printf("  r     r     r     r     r     r   r     r     r   r         r     r     r     r     r     r   \n");
585 	printf("	 r     rr    r    r    rrr  rrrrr rrrrr r   r        r    rr     r                      \n");
586 	printf("\n(Here is just a sample...)\n\n");
587 
588 	/* Request user to know which char user wants */
589 
590 	printf("Which char to display FOR BLACK?\n");
591 	scanf("%c", &c); /* Choose wich char for the black */
592 
593 	//printf("Which char to display FOR GRAY ?\n");
594 	//scanf("%c", &b); /* Choose wich char for the black */
595 
596 	lcd_content_file = g_fopen("lcd_content.txt", "w");
597 
598 	printf("\n\n\n### LCD CONTENT ###\n\n\n\n");
599 	for (y = 0; y < height; y++) {
600 		for (x = 0; x < width; x++) {
601 			/*printf("%d ", lcddata[y * width + x]); */
602 			if (lcddata[(y * width + x) / 8] & (0x80 >> (x % 8))) {
603 				printf("%c", c);
604 				if(lcd_content_file != NULL)
605 					fprintf(lcd_content_file,"%c", c);
606 			} else {
607 				printf("%c", ' ');
608 				if(lcd_content_file != NULL)
609 					fprintf(lcd_content_file,"%c", ' ');
610 			}
611 		}
612 		printf("\n");
613 		if(lcd_content_file != NULL)
614 			fprintf(lcd_content_file,"%c", '\n');
615 	}
616 	if(lcd_content_file != NULL) {
617 		fclose(lcd_content_file);
618 		printf("\n### END ###\n\nSaved into lcd_content.txt\n");
619 	}
620 
621 }
622