1 /* Hey EMACS -*- linux-c -*- */
2 /* $Id: calc.c 2729 2007-12-16 15:29:16Z roms $ */
3 
4 /*  TiEmu - Tiemu Is an EMUlator
5  *
6  *  Copyright (c) 2000-2001, Thomas Corvazier, Romain Lievin
7  *  Copyright (c) 2001-2003, Romain Lievin
8  *  Copyright (c) 2003, Julien Blache
9  *  Copyright (c) 2004, Romain Li�vin
10  *  Copyright (c) 2005, Romain Li�vin
11  *  Copyright (c) 2005, Julien Blache
12  *  Copyright (c) 2006, Kevin Kofler
13  *
14  *  This program is free software; you can redistribute it and/or modify
15  *  it under the terms of the GNU General Public License as published by
16  *  the Free Software Foundation; either version 2 of the License, or
17  *  (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #  include <config.h>
31 #endif				/*  */
32 
33 #ifdef __WIN32__
34 #include <io.h>
35 #endif
36 #include <stdlib.h>
37 #include <string.h>
38 #include <gtk/gtk.h>
39 #include <glade/glade.h>
40 #include <gdk-pixbuf/gdk-pixbuf.h>
41 
42 #include "intl.h"
43 #include "paths.h"
44 #include "skinops.h"
45 #include "support.h"
46 #include "ti68k_int.h"
47 #include "struct.h"
48 #include "tie_error.h"
49 #include "calc.h"
50 #include "dbg_all.h"
51 #include "screenshot.h"
52 #include "keymap.h"
53 #include "logging.h"
54 #include "gscales.h"
55 
56 #define ALLOW_RESIZE_WIN32
57 
58 GtkWidget *main_wnd = NULL;
59 gboolean explicit_destroy = 0;
60 GtkWidget *area = NULL;
61 
62 SKIN_INFOS skin_infos = { 0 };
63 
64 extern GdkPixbuf*	lcd_mem;
65 extern GdkPixbuf*	lcd;
66 extern GdkPixmap*	pixmap;
67 
68 extern Pc2TiKey*    kbd_keymap;
69 extern const char*	skn_keymap;
70 extern const char	sknKey92[];
71 extern const char	sknKey89[];
72 
73 extern uint32_t*	lcd_bytmap;
74 
75 extern LCD_INFOS	li;
76 extern float		sf;	// scaling factor
77 
78 extern LCD_RECT		ls;
79 extern LCD_RECT		lr;
80 extern SKN_RECT		sr;
81 extern WND_RECT		wr;
82 
83 static guint tid = -1;
84 
85 extern int			shot_cnt;
86 extern int			skip_cnt;
87 
88 // part 1: set scale factor
set_scale(int view_mode)89 static void set_scale(int view_mode)
90 {
91 	if(view_mode == VIEW_NORMAL)
92 	{
93 		options.scale = sf = 1.0;
94 	}
95 	else if(view_mode == VIEW_LARGE)
96 	{
97 		options.scale = sf = 2.0;
98 	}
99 	else if(view_mode == VIEW_FULL)
100 	{
101 		GdkScreen* screen = gdk_screen_get_default();
102 		gint sw = gdk_screen_get_width(screen);
103 		gint sh = gdk_screen_get_height(screen);
104 
105 		sf = (float)sw / lr.w;
106 		sf = (float)sh / lr.h;
107 		//printf("%i %i %f\n", sw, lr.w, sf);
108 		//printf("%i %i %f\n", sh, lr.h, sf);
109 
110 		options.scale = sf = (float)1.0;	// restricted to 3.0, too CPU intensive !
111 	}
112 }
113 
114 // part 2: compute sizes
set_infos(void)115 static void set_infos(void)	// set window & lcd sizes
116 {
117 	// LCD rectangle (source: skin)
118 	ls.x = (int)(sf * skin_infos.lcd_pos.left);
119 	ls.y = (int)(sf * skin_infos.lcd_pos.top);
120 	ls.w = (int)(sf * tihw.lcd_w);
121 	ls.h = (int)(sf * tihw.lcd_h);
122 
123 	// LCD rectangle (target: window)
124 	if(options.skin)
125 	{
126 		lr.x = ls.x;
127 		lr.y = ls.y;
128 	}
129 	else
130 	{
131 		lr.x = 0;
132 		lr.y = 0;
133 	}
134 	lr.w = (int)(sf * tihw.lcd_w);
135 	lr.h = (int)(sf * tihw.lcd_h);
136 
137 
138 	// SKN rectangle
139 	sr.x = sr.y = 0;
140 	sr.w = (int)(sf * skin_infos.width);
141 	sr.h = (int)(sf * skin_infos.height);
142 
143 	// WND rectangle (= LCD or SKN depending on w/ or w/o skin)
144 	wr.x = wr.y = 0;
145 	if(options.skin)
146 	{
147 		wr.w = sr.w;
148 		wr.h = sr.h;
149 	}
150 	else
151 	{
152 		wr.w = lr.w;
153 		wr.h = lr.h;
154 	}
155 
156 #if 0
157 	printf("LCD src: %3i %3i %3i %3i\n", ls.x, ls.y, ls.w, ls.h);
158 	printf("LCD dst: %3i %3i %3i %3i\n", lr.x, lr.y, lr.w, lr.h);
159 	printf("SKN    : %3i %3i %3i %3i\n", sr.x, sr.y, sr.w, sr.h);
160 	printf("WND    : %3i %3i %3i %3i\n", wr.x, wr.y, wr.w, wr.h);
161 #endif
162 }
163 
164 // part 3: set changes on window
set_window(int full_redraw)165 static void set_window(int full_redraw)
166 {
167 	if(main_wnd->window == NULL)
168 		return;
169 
170 	// resize window and drawing area
171 	if(full_redraw)
172 		gtk_window_resize(GTK_WINDOW(main_wnd), wr.w, wr.h);
173 
174 #if defined(__WIN32__) && defined(ALLOW_RESIZE_WIN32)
175 	if(!full_redraw)
176 		gdk_window_resize(main_wnd->window, wr.w, wr.h);
177 #endif
178 
179 	// reallocate backing pixmap
180 	if(pixmap != NULL)
181 	{
182 		// free current backing pixmap
183 		g_object_unref(pixmap);
184 		pixmap = NULL;
185 
186 		// and allocate a new one
187 		pixmap = gdk_pixmap_new(main_wnd->window, wr.w, wr.h, -1);
188 		if(pixmap == NULL)
189 		{
190 			gchar *s = g_strdup_printf("unable to create backing pixmap.\n");
191 			tiemu_error(0, s);
192 			g_free(s);
193 			return;
194 		}
195 	}
196 }
197 
set_constraints(void)198 static void set_constraints(void)
199 {
200 	// Allows resizing of window with a constant aspect ratio.
201 	// This is the right way as used under Linux.
202         // Does not work under Windows thus not enabled.
203 
204 #if !defined(__WIN32__) || !defined(ALLOW_RESIZE_WIN32)
205 	if(1)
206 	{
207 		GdkGeometry geom = { -1 };
208 		GdkWindowHints mask = GDK_HINT_MIN_SIZE | GDK_HINT_ASPECT;
209 		double r = (float)wr.w / wr.h;
210 
211 		geom.min_width = 100;
212 		geom.min_height = 100;
213 
214 		geom.min_aspect = r;
215 		geom.max_aspect = r;
216 		gtk_window_set_geometry_hints(GTK_WINDOW(main_wnd),
217 					      area, &geom, mask);
218 
219 		//printf("set_constraints: %i %i %1.2f\n", wr.w, wr.h, r);
220 	}
221 #endif
222 }
223 
224 // Main wnd by loading glade xml file or by executing glade generated code
display_main_wnd(void)225 gint display_main_wnd(void)
226 {
227 	GladeXML *xml;
228 	gchar *title;
229 
230 	xml = glade_xml_new
231 		(tilp_paths_build_glade("calc-2.glade"), "calc_wnd",
232 		 PACKAGE);
233 	if (!xml)
234 		g_error(_("%s: GUI loading failed!\n"), __FILE__);
235 	glade_xml_signal_autoconnect(xml);
236 
237 	main_wnd = glade_xml_get_widget(xml, "calc_wnd");
238 	area = glade_xml_get_widget(xml, "drawingarea1");
239 
240 	gtk_window_move(GTK_WINDOW(main_wnd), options3.calc.rect.x, options3.calc.rect.y);
241 	set_constraints();
242 	gtk_widget_realize(main_wnd);	// set drawing area valid
243 
244 	// set window title (useful for TIGCC-IDE for instance)
245 	// Note: lpWindowName is "TiEmu (%s)" and lpClassName is "gdkWindowToplevel"
246 	title = g_strdup_printf("TiEmu (%s)", ti68k_calctype_to_string(tihw.calc_type));
247 	gtk_window_set_title(GTK_WINDOW(main_wnd), title);
248 	g_free(title);
249 
250 	return 0;
251 }
252 
253 extern void on_exit_without_saving_state1_activate(GtkMenuItem* item, gpointer data);
254 
255 GLADE_CB void
on_calc_wnd_destroy(GtkObject * object,gpointer user_data)256 on_calc_wnd_destroy                    (GtkObject       *object,
257                                         gpointer         user_data)
258 {
259 	// Uninstall LCD refresh (to avoid earlier use of main_wnd by hid_lcd_update)
260     g_source_remove(tid);
261 
262 	// When GTK called this signal, the widget has already been destroy
263 	// thus set the pointer to a valid value, ie NULL .
264 	main_wnd = NULL;
265 
266 	if(!explicit_destroy)
267 		on_exit_without_saving_state1_activate(NULL, NULL);
268 }
269 
270 extern void redraw_skin(void);
271 
272 GLADE_CB gboolean
on_drawingarea1_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer user_data)273 on_drawingarea1_configure_event        (GtkWidget       *widget,
274                                         GdkEventConfigure *event,
275                                         gpointer         user_data)
276 {
277 	float factor;
278 
279 	// compute scaling factor
280 	if(options.skin)
281 		factor = (float)event->width / (float)skin_infos.width;
282 	else
283 		factor = (float)event->width / (float)tihw.lcd_w;
284 
285 #if 0
286 	printf("on_drawingarea1_configure_event:  x y w h = %i %i %i %i\n",
287 		event->x, event->y, event->width, event->height);
288 	printf("on_drawingarea1_configure_event: f = %1.2f\n", factor);
289 #endif
290 
291 	// if normal or large view then exits
292 	if((factor == 1.0) || (factor == 2.0))
293 		return FALSE;
294 
295 	// set scaling factor
296 	options.scale = sf = factor;
297 	options.view = VIEW_CUSTOM;
298 
299 	// compute sizes
300 	set_infos();
301 
302 	// and set window size
303 	set_window(0);
304 	redraw_skin();
305 
306     return FALSE;
307 }
308 
309 GLADE_CB gboolean
on_drawingarea1_expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer user_data)310 on_drawingarea1_expose_event           (GtkWidget       *widget,
311                                         GdkEventExpose  *event,
312                                         gpointer         user_data)
313 {
314     gdk_draw_pixmap(
315         widget->window,
316 		widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
317 		pixmap,
318 		event->area.x, event->area.y,
319 		event->area.x, event->area.y,
320 		event->area.width, event->area.height);
321 
322 	return FALSE;
323 }
324 
match_skin(int calc_type)325 static int match_skin(int calc_type)
326 {
327 	SKIN_INFOS *sk = &skin_infos;
328 	int ok;
329 	gchar *skin_name, *s;
330 
331 	s = g_strdup(ti68k_calctype_to_string(calc_type));
332 	skin_name = g_ascii_strdown(s, strlen(s));
333 	g_free(s);
334 
335 	if(!strcmp(skin_name, "ti92+"))
336 		skin_name[4] = '\0';
337 
338 #ifdef __IPAQ__
339 	s = g_strconcat("ipaq_", skin_name, NULL);
340 	g_free(skin_name);
341 	skin_name = s;
342 #endif
343 
344 	// filename is "", load default skin
345 	if(!strcmp(g_basename(options.skin_file), ""))
346 	{
347 		g_free(options.skin_file);
348 		options.skin_file = g_strdup_printf("%s%s.skn",
349 					    inst_paths.skin_dir, skin_name);
350 		g_free(skin_name);
351 		return -1;
352 	}
353 
354 	// load skin header
355 	if(skin_read_header(sk, options.skin_file) == -1)
356 	{
357 		g_free(options.skin_file);
358       	options.skin_file = g_strdup_printf("%s%s.skn",
359 					    inst_paths.skin_dir, skin_name);
360 	    g_free(skin_name);
361 	    return -1;
362 	}
363 
364 	// is skin compatible
365 	switch(tihw.calc_type)
366 	{
367 	    case TI92:
368 	    case TI92p:
369             ok = !strcmp((const char *)sk->calc, SKIN_TI92) || !strcmp((const char *)sk->calc, SKIN_TI92P);
370 		break;
371 	    case TI89:
372 	    ok = !strcmp((const char *)sk->calc, SKIN_TI89);
373 		break;
374 	    case TI89t:
375 	    ok = !strcmp((const char *)sk->calc, SKIN_TI89T);
376 		break;
377 	    case V200:
378 	    ok = !strcmp((const char *)sk->calc, SKIN_V200);
379 		break;
380 	    default:
381 	    ok = 0;
382 		break;
383 	}
384 
385 	if(!ok)
386 	{
387 		g_free(options.skin_file);
388       	options.skin_file = g_strdup_printf("%s%s.skn",
389 			inst_paths.skin_dir, skin_name);
390 
391 	    //tiemu_error(0, _("skin incompatible with the current calc model. Falling back to default skin."));
392 	    g_free(skin_name);
393 		return -1;
394 	}
395 
396     g_free(skin_name);
397 	return 0;
398 }
399 
match_keymap(int calc_type)400 static int match_keymap(int calc_type)
401 {
402 	gchar *keys_name, *s;
403     int ct, ok;
404 
405 	s = g_strdup(ti68k_calctype_to_string(calc_type));
406 	keys_name = g_ascii_strdown(s, strlen(s));
407 
408 	if(!strcmp(keys_name, "ti92+") || !strcmp(keys_name, "ti89t"))
409 		keys_name[4] = '\0';
410 	if(!strcmp(keys_name, "v200plt"))
411 		strcpy(keys_name, "ti92");
412 
413 	// filename is "", load default keymap
414 	if(!strcmp(g_basename(options.keys_file), ""))
415 	{
416 		g_free(options.keys_file);
417 		options.keys_file = g_strdup_printf("%s%s.map",
418 					    inst_paths.skin_dir, keys_name);
419 	}
420 
421 	// load keymap header
422     ct = keymap_read_header(options.keys_file);
423 	if(ct == -1)
424 	{
425 		g_free(options.keys_file);
426       	options.keys_file = g_strdup_printf("%s%s.map",
427 					    inst_paths.skin_dir, keys_name);
428 	    g_free(keys_name);
429 	    return -1;
430 	}
431 
432     // is keymap compatible
433 	switch(tihw.calc_type)
434 	{
435 	    case TI92:
436 		case TI92p:
437         case V200:
438             ok = (ct == TI92) || (ct == TI92p) || (ct == V200);
439 		break;
440 	    case TI89:
441         case TI89t:
442             ok = (ct == TI89) || (ct == TI89t);
443 		break;
444 	    default:
445             ok = 0;
446 		break;
447 	}
448 
449 	if(!ok)
450 	{
451 		g_free(options.keys_file);
452       	options.keys_file = g_strdup_printf("%s%s.map",
453 			inst_paths.skin_dir, keys_name);
454 
455 	    //tiemu_error(0, _("keymap incompatible with the current calc model. Falling back to default keymap."));
456 	    g_free(keys_name);
457 		return -1;
458 	}
459 
460     g_free(keys_name);
461 	return 0;
462 }
463 
464 G_LOCK_EXTERN(lcd_flag);
465 extern volatile int lcd_flag;
466 extern volatile int debugger;
467 
hid_refresh(gpointer data)468 static gint hid_refresh (gpointer data)
469 {
470     if(lcd_flag || (tihw.hw_type >= HW2))
471     {
472 		// TI92+: jackycar, TI89: baballe
473 	    hid_update_lcd();
474         G_LOCK(lcd_flag);
475         lcd_flag = 0;
476         G_UNLOCK(lcd_flag);
477 
478 		if(tihw.hw_type >= HW2)
479 			lcd_hook_hw2(TRUE);
480     }
481 
482     return TRUE;
483 }
484 
485 void compute_convtable(void);
486 void compute_grayscale(void);
487 
488 extern void dnd_init(void);
489 extern void dnd_exit(void);
490 
hid_init(void)491 int  hid_init(void)
492 {
493     // Found a PC keyboard keymap
494     match_keymap(tihw.calc_type);
495 
496     // Load kbd keymap
497     if(keymap_load(options.keys_file) == -1)
498     {
499 	    gchar *s = g_strdup_printf("unable to load this keymap: <%s>\n", options.keys_file);
500 	    tiemu_error(0, s);
501 	    g_free(s);
502 	    return -1;
503     }
504 
505     // Found a skin
506 	match_skin(tihw.calc_type);
507 
508     // Load skin (2 parts)
509     if(skin_load(&skin_infos, options.skin_file) == -1)
510     {
511 	    gchar *s = g_strdup_printf("unable to load this skin: <%s>\n", options.skin_file);
512 	    tiemu_error(0, s);
513 	    g_free(s);
514 	    return -1;
515     }
516 
517 	// Set skin keymap depending on calculator type
518     switch(tihw.calc_type)
519     {
520     case TI92:
521     case TI92p:
522     case V200:
523         skn_keymap = sknKey92;
524         break;
525     case TI89:
526     case TI89t:
527       	skn_keymap = sknKey89;
528         break;
529     default:
530         {
531 	  	gchar *s = g_strdup_printf("no skin found for this calc\n");
532 	  	tiemu_error(0, s);
533 	  	g_free(s);
534 	  	return -1;
535         }
536 	}
537 
538 	// Set window/LCD sizes
539 	sf = options.scale;
540 	set_scale(options.view);
541 	set_infos();
542 
543     // Allocate the TI screen buffer
544 	lcd_bytmap = (uint32_t *)malloc(LCDMEM_W * LCDMEM_H);
545 
546     // Allocate the lcd pixbuf
547     lcd_mem = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, LCDMEM_W, LCDMEM_H);
548     if(lcd_mem == NULL)
549     {
550         gchar *s = g_strdup_printf("unable to create LCD pixbuf.\n");
551 	    tiemu_error(0, s);
552 	    g_free(s);
553 	    return -1;
554     }
555 
556 	// Used by TI89 (the LCD view is clipped from memory view)
557 	lcd = gdk_pixbuf_new_subpixbuf(lcd_mem, 0, 0, tihw.lcd_w, tihw.lcd_h);
558 
559 	// Constants for LCD update (speed-up)
560     li.n_channels = gdk_pixbuf_get_n_channels (lcd_mem);
561 	li.width = gdk_pixbuf_get_width (lcd_mem);
562 	li.height = gdk_pixbuf_get_height (lcd_mem);
563 	li.rowstride = gdk_pixbuf_get_rowstride (lcd_mem);
564 	li.pixels = gdk_pixbuf_get_pixels (lcd_mem);
565 
566 	// Create main window
567 	display_main_wnd();
568 
569     // Allocate the backing pixmap (used for drawing and refresh)
570     pixmap = gdk_pixmap_new(main_wnd->window, wr.w, wr.h, -1);
571     if(pixmap == NULL)
572     {
573         gchar *s = g_strdup_printf("unable to create backing pixmap.\n");
574 	    tiemu_error(0, s);
575 	    g_free(s);
576 	    return -1;
577     }
578 
579     // Draw the skin and compute grayscale palette
580 	set_window(1);
581 	redraw_skin();
582   	compute_grayscale();
583 
584     // Init the planar/chunky conversion table for LCD
585   	compute_convtable();
586 
587     // Install LCD refresh: 100 FPS (10 ms)
588     tid = g_timeout_add((params.lcd_rate == -1) ? 50 : params.lcd_rate,
589 		(GtkFunction)hid_refresh, NULL);
590 
591 	explicit_destroy = 0;
592 	gtk_widget_show(main_wnd);	// show wnd here
593 
594 	if(options.view == VIEW_FULL)
595 		gdk_window_fullscreen(main_wnd->window);
596 
597 	lcd_planes[0] = tihw.lcd_adr;
598 	lcd_planebufs[0] = &tihw.ram[tihw.lcd_adr];
599 	ngc = 1;
600 	lcd_changed = 1;
601 
602 	dnd_init();
603 
604     return 0;
605 }
606 
hid_exit(void)607 int  hid_exit(void)
608 {
609 
610     // Uninstall LCD refresh
611     g_source_remove(tid);
612 
613 	// Release resources
614     if(lcd_mem != NULL)
615     {
616         g_object_unref(lcd_mem);
617         lcd_mem = NULL;
618 		g_object_unref(lcd);
619 		lcd = NULL;
620     }
621 
622     if(pixmap != NULL)
623     {
624         g_object_unref(pixmap);
625         pixmap = NULL;
626     }
627 
628     // Destroy window
629 	if(main_wnd)
630 	{
631 		explicit_destroy = !0;
632 		gtk_widget_destroy(main_wnd);
633 	}
634 
635     return 0;
636 }
637 
hid_lcd_rate_set(void)638 void hid_lcd_rate_set(void)
639 {
640 	g_source_remove(tid);
641 
642 	tid = g_timeout_add((params.lcd_rate == -1) ? 50 : params.lcd_rate,
643 		(GtkFunction)hid_refresh, NULL);
644 }
645 
hid_switch_with_skin(void)646 int hid_switch_with_skin(void)
647 {
648     options.skin = 1;
649 	set_infos();
650 	set_constraints();
651 	set_window(1);
652 	redraw_skin();
653 
654     return 0;
655 }
656 
hid_switch_without_skin(void)657 int hid_switch_without_skin(void)
658 {
659     options.skin = 0;
660 	set_infos();
661 	set_constraints();
662 	set_window(1);
663 	redraw_skin();
664 
665     return 0;
666 }
667 
hid_change_skin(const char * filename)668 int hid_change_skin(const char *filename)
669 {
670     int ret1, ret2;
671 
672 	ret1 = hid_exit();
673 	ret2 = hid_init();
674 
675 	return ret1 | ret2;
676 }
677 
hid_switch_fullscreen(void)678 int hid_switch_fullscreen(void)
679 {
680 	if(options.view != VIEW_FULL)
681 	{
682 		set_scale(options.view = VIEW_FULL);
683 		set_infos();
684 		set_window(1);
685 		redraw_skin();
686 		gdk_window_fullscreen(main_wnd->window);
687 	}
688 
689 	return 0;
690 }
691 
hid_switch_normal_view(void)692 int hid_switch_normal_view(void)
693 {
694 	if(options.view != VIEW_NORMAL)
695 	{
696 		set_scale(options.view = VIEW_NORMAL);
697 		set_infos();
698 		set_window(1);
699 		redraw_skin();
700 		gdk_window_unfullscreen(main_wnd->window);
701 	}
702 
703     return 0;
704 }
705 
hid_switch_large_view(void)706 int hid_switch_large_view(void)
707 {
708 	if(options.view != VIEW_LARGE)
709 	{
710 		set_scale(options.view = VIEW_LARGE);
711 		set_infos();
712 		set_window(1);
713 		redraw_skin();
714 		gdk_window_unfullscreen(main_wnd->window);
715 	}
716 
717     return 0;
718 }
719 
hid_screenshot_burst(void)720 int  hid_screenshot_burst(void)
721 {
722 	shot_cnt = options2.shots;
723 	skip_cnt = options2.skips;
724 
725 	return 0;
726 }
727 
hid_screenshot_single(void)728 int  hid_screenshot_single(void)
729 {
730 	gchar *outfile;
731 	gchar *ext = "";
732 	gchar *type = "";
733 
734 	GdkPixbuf *pixbuf = { 0 };
735 	gboolean result = FALSE;
736 	GError *error = NULL;
737 
738 	switch(options2.format)
739 	{
740 		case IMG_JPG: ext = "jpg"; type = "jpeg"; break;
741 		case IMG_PNG: ext = "png"; type = "png";  break;
742 		case IMG_ICO: ext = "ico"; type = "ico";  break;
743  		case IMG_EPS: ext = "eps"; type = "eps";  break;
744  		case IMG_PDF: ext = "pdf"; type = "pdf";  break;
745 		case IMG_BMP: ext = "bmp"; type = "bmp";  break;
746 		default: ext = "png"; type = "png";  break;
747 	}
748 
749 	outfile = g_strdup_printf("%s%s%s%03i.%s", options2.folder, G_DIR_SEPARATOR_S,
750 		options2.file, options2.counter, ext);
751 	tiemu_info(_("screenshot to %s... "), outfile);
752 
753 	if((options2.size == IMG_LCD) && (options2.type == IMG_BW))
754 	{
755 		// get pixbuf from TI memory (LCD buffer)
756 		pixbuf = hid_copy_lcd();
757 	}
758 	else if((options2.size == IMG_LCD) && (options2.type == IMG_COL))
759 	{
760         // get pixbuf from grayscale lcd
761 		pixbuf = gdk_pixbuf_copy(lcd);
762 	}
763 	else if((options2.size == IMG_SKIN) && (options2.type == IMG_COL))
764 	{
765 		// get pixbuf from backing pixmap
766 		pixbuf = gdk_pixbuf_get_from_drawable(NULL, pixmap, NULL, 0, 0, 0, 0, wr.w, wr.h);
767 	}
768 	else
769 	{
770 		tiemu_warning(_("unsupported screenshot options combination, screenshot aborted."));
771 		return 0;
772        }
773 
774 	switch (options2.format)
775 	{
776 	case IMG_EPS:
777 		result = tiemu_screen_write_eps(outfile, pixbuf, &error);
778 		break;
779 	case IMG_PDF:
780 		result = tiemu_screen_write_pdf(outfile, pixbuf, &error);
781 		break;
782 	default:
783 		result = gdk_pixbuf_save(pixbuf, outfile, type, &error, NULL);
784 		break;
785 	}
786 
787 	if(options2.clipboard)
788 	{
789 		GtkClipboard *clipboard;
790 
791 		clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
792 		gtk_clipboard_set_image(clipboard, pixbuf);
793 	}
794 
795 	if (result == FALSE)
796 	{
797 		tiemu_warning(_("failed to save pixbuf file: %s: %s"), outfile, error->message);
798 		g_error_free(error);
799 	}
800 	g_object_unref(pixbuf);
801 
802 	tiemu_info(_("done!"));
803 	options2.counter++;
804 
805 	return 0;
806 }
807 
808 GLADE_CB gboolean
on_calc_wnd_window_state_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)809 on_calc_wnd_window_state_event         (GtkWidget       *widget,
810                                         GdkEvent        *event,
811                                         gpointer         user_data)
812 {
813     return FALSE;
814 }
815