pcsxr-1.9.92
[pcsx_rearmed.git] / gui / MemcardDlg.c
1 /*  Pcsx - Pc Psx Emulator
2  *  Copyright (C) 1999-2002  Pcsx Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (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, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <gdk/gdkkeysyms.h>
24 #include <gtk/gtk.h>
25 #include <glade/glade.h>
26 #include <signal.h>
27 #include <sys/time.h>
28
29 #include "Linux.h"
30 #include "../libpcsxcore/sio.h"
31
32 #define MAX_MEMCARD_BLOCKS 15
33
34 static gboolean quit;
35 static unsigned int currentIcon;
36
37 McdBlock Blocks[2][MAX_MEMCARD_BLOCKS]; // Assuming 2 cards, 15 blocks?
38 int IconC[2][MAX_MEMCARD_BLOCKS];
39 enum {
40     CL_ICON,
41     CL_TITLE,
42     CL_STAT,
43     CL_ID,
44     CL_NAME,
45     NUM_CL
46 };
47
48 GtkWidget *GtkCList_McdList1, *GtkCList_McdList2;
49
50 static void AddColumns(GtkTreeView *treeview) {
51         GtkCellRenderer *renderer;
52         GtkTreeViewColumn *column;
53
54         // column for icon
55         renderer = gtk_cell_renderer_pixbuf_new ();
56         column = gtk_tree_view_column_new_with_attributes(_("Icon"),
57                         renderer, "pixbuf", CL_ICON, NULL);
58         gtk_tree_view_append_column(treeview, column);
59
60         // column for title
61         renderer = gtk_cell_renderer_text_new();
62         column = gtk_tree_view_column_new_with_attributes(_("Title"),
63                         renderer, "text", CL_TITLE, NULL);
64         gtk_tree_view_append_column(treeview, column);
65
66         // column for status
67         renderer = gtk_cell_renderer_text_new();
68         column = gtk_tree_view_column_new_with_attributes(_("Status"),
69                         renderer, "text", CL_STAT, NULL);
70         gtk_tree_view_append_column(treeview, column);
71
72         // column for id
73         renderer = gtk_cell_renderer_text_new();
74         column = gtk_tree_view_column_new_with_attributes(_("ID"),
75                         renderer, "text", CL_ID, NULL);
76         gtk_tree_view_append_column(treeview, column);
77
78         // column for Name
79         renderer = gtk_cell_renderer_text_new();
80         column = gtk_tree_view_column_new_with_attributes(_("Name"),
81                         renderer, "text", CL_NAME, NULL);
82         gtk_tree_view_append_column(treeview, column);
83 }
84
85 static GdkPixbuf *SetIcon(GtkWidget *dialog, short *icon, int i) {
86         GdkPixmap *pixmap;
87         GdkImage  *image;
88         GdkVisual *visual;
89         GdkPixbuf *pixbuf;
90         GdkGC     *gc;
91         int x, y, c;
92
93         visual = gdk_window_get_visual(dialog->window);
94
95         if (visual->depth == 8) return NULL;
96
97         image = gdk_image_new(GDK_IMAGE_NORMAL, visual, 32, 32);
98
99         for (y = 0; y < 32; y++) {
100                 for (x = 0; x < 32; x++) {
101                         c = icon[(y>>1) * 16 + (x>>1)];
102                         c = ((c & 0x001f) << 10) | ((c & 0x7c00) >> 10) | (c & 0x03e0);
103                         if (visual->depth == 16)
104                                 c = (c & 0x001f) | ((c & 0x7c00) << 1) | ((c & 0x03e0) << 1);
105                         else if (visual->depth == 24 || visual->depth == 32)
106                                 c = ((c & 0x001f) << 3) | ((c & 0x03e0) << 6) | ((c & 0x7c00) << 9);
107
108                         gdk_image_put_pixel(image, x, y, c);
109                 }
110         }
111
112         pixmap = gdk_pixmap_new(dialog->window, 32, 32, visual->depth);
113
114         gc = gdk_gc_new(pixmap);
115         gdk_draw_image(pixmap, gc, image, 0, 0, 0, 0, 32, 32);
116         gdk_gc_destroy(gc);
117         gdk_image_destroy(image);
118
119         pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_PIXMAP (pixmap), NULL,
120                                                                                 0, 0, 0, 0, -1, -1);
121         g_object_unref(pixmap);
122         
123         return pixbuf;
124 }
125
126 static void LoadListItems(int mcd, GtkWidget *widget) {
127         int i;
128         GladeXML *xml;
129         GtkWidget *List;
130         GtkWidget *dialog;
131         GtkListStore *store;
132         GtkTreeIter iter;
133         GdkPixbuf *pixbuf;
134         gchar *title;
135
136         store = gtk_list_store_new(NUM_CL, GDK_TYPE_PIXBUF, G_TYPE_STRING,
137                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
138
139         xml = glade_get_widget_tree(widget);
140         dialog = glade_xml_get_widget(xml, "McdsDlg");
141
142         if (mcd == 1) List = glade_xml_get_widget(xml, "GtkCList_McdList1");
143         else List = glade_xml_get_widget(xml, "GtkCList_McdList2");
144
145         for (i = 0; i < MAX_MEMCARD_BLOCKS; i++) {
146                 McdBlock *Info;
147                 gchar *state;
148
149                 Info = &Blocks[mcd - 1][i];
150                 IconC[mcd - 1][i] = 0;
151
152                 if ((Info->Flags & 0xF0) == 0xA0) {
153                         if ((Info->Flags & 0xF) >= 1 &&
154                                 (Info->Flags & 0xF) <= 3) {
155                                 state = _("Deleted");
156                         } else
157                                 state = _("Free");
158                 } else if ((Info->Flags & 0xF0) == 0x50)
159                         state = _("Used");
160                 else
161                         state = _("Free");
162
163                 pixbuf = SetIcon(dialog, Info->Icon, i + 1);
164
165                 gtk_list_store_append(store, &iter);
166
167                 title = g_convert(Info->sTitle, strlen(Info->sTitle), "UTF-8",
168                         "Shift-JIS", NULL, NULL, NULL);
169
170                 gtk_list_store_set(store, &iter,
171                                 CL_ICON, pixbuf,
172                                 CL_TITLE, title,
173                                 CL_STAT, state,
174                                 CL_NAME, Info->Name,
175                                 CL_ID, Info->ID,
176                                 -1);
177
178                 g_free(title);
179                 
180                 g_object_unref(pixbuf);
181         }
182
183         gtk_tree_view_set_model(GTK_TREE_VIEW(List), GTK_TREE_MODEL(store));
184         g_object_unref(G_OBJECT(store));
185         gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(List), TRUE);
186         gtk_widget_show(List);
187 }
188
189 static void UpdateFilenameButtons(GtkWidget *widget) {
190         int i;
191         GladeXML *xml;
192         GtkWidget *dialog;
193         const char *filename;
194         gchar *p;
195
196         xml = glade_get_widget_tree(widget);
197         dialog = glade_xml_get_widget(xml, "McdsDlg");
198
199         for (i = 0; i < 2; i++) {
200                 if (i == 0) {
201                         widget = glade_xml_get_widget(xml, "Mcd1Label");
202                         filename = Config.Mcd1;
203                 } else {
204                         widget = glade_xml_get_widget(xml, "Mcd2Label");
205                         filename = Config.Mcd2;
206                 }
207
208                 p = g_path_get_basename(filename);
209                 gtk_label_set_text(GTK_LABEL(widget), p);
210                 g_free(p);
211         }
212 }
213
214 static void LoadMcdDlg(GtkWidget *widget) {
215         int i;
216
217         for (i = 0; i < MAX_MEMCARD_BLOCKS; i++) {
218                 GetMcdBlockInfo(1, i + 1, &Blocks[0][i]);
219                 GetMcdBlockInfo(2, i + 1, &Blocks[1][i]);
220         }
221
222         LoadListItems(1, widget);
223         LoadListItems(2, widget);
224
225         UpdateFilenameButtons(widget);
226 }
227
228 static void OnTreeSelectionChanged(GtkTreeSelection *selection, gpointer user_data);
229
230 static void UpdateListItems(int mcd, GtkWidget *widget) {
231         GladeXML *xml;
232         GtkWidget *List;
233         GtkWidget *dialog;
234         GtkListStore *store;
235         GtkTreeIter iter;
236         GdkPixbuf *pixbuf;
237         short *pIcon;
238         int i;
239         gchar *title;
240
241         xml = glade_get_widget_tree(widget);
242         dialog = glade_xml_get_widget(xml, "McdsDlg");
243
244         if (mcd == 1) List = glade_xml_get_widget(xml, "GtkCList_McdList1");
245         else List = glade_xml_get_widget(xml, "GtkCList_McdList2");
246
247         store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(List)));
248         gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
249
250         for (i = 0; i < MAX_MEMCARD_BLOCKS; i++) {
251                 McdBlock *Info;
252                 gchar *state;
253
254                 Info = &Blocks[mcd - 1][i];
255                 IconC[mcd - 1][i] = 0;
256
257                 if ((Info->Flags & 0xF0) == 0xA0) {
258                         if ((Info->Flags & 0xF) >= 1 &&
259                                 (Info->Flags & 0xF) <= 3) {
260                                 state = _("Deleted");
261                         } else
262                                 state = _("Free");
263                 } else if ((Info->Flags & 0xF0) == 0x50)
264                         state = _("Used");
265                 else
266                         state = _("Free");
267
268                 if (Info->IconCount > 0) {
269                         pIcon = &Info->Icon[(currentIcon % Info->IconCount) * 16 * 16];
270                 } else {
271                         pIcon = Info->Icon;
272                 }
273
274                 pixbuf = SetIcon(dialog, pIcon, i + 1);
275                 title = g_convert(Info->sTitle, strlen(Info->sTitle), "UTF-8",
276                         "Shift-JIS", NULL, NULL, NULL);
277
278                 gtk_list_store_set(store, &iter,
279                                 CL_ICON, pixbuf,
280                                 CL_TITLE, title,
281                                 CL_STAT, state,
282                                 CL_NAME, Info->Name,
283                                 CL_ID, Info->ID,
284                                 -1);
285
286                 g_free(title);
287
288                 g_object_unref(pixbuf);
289                 gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
290         }
291
292         gtk_widget_show(List);
293
294         OnTreeSelectionChanged(gtk_tree_view_get_selection(GTK_TREE_VIEW(List)), (gpointer)mcd);
295 }
296
297 static void UpdateMcdDlg(GtkWidget *widget) {
298         int i;
299
300         for (i = 0; i < MAX_MEMCARD_BLOCKS; i++) {
301                 GetMcdBlockInfo(1, i + 1, &Blocks[0][i]);
302                 GetMcdBlockInfo(2, i + 1, &Blocks[1][i]);
303         }
304
305         UpdateListItems(1, widget);
306         UpdateListItems(2, widget);
307
308         UpdateFilenameButtons(widget);
309 }
310
311 static void OnMcd_Close(GtkDialog *dialog, gint arg1, gpointer user_data) {
312         quit = TRUE;
313         SaveConfig();
314         gtk_widget_destroy(GTK_WIDGET(dialog));
315 }
316
317 static void OnMcd_FileChange(GtkWidget *widget, gpointer user_data) {
318         gint memcard = (int)user_data;
319         gchar *filename;
320         GtkWidget *chooser;
321
322         // Ask for name of memory card
323         chooser = gtk_file_chooser_dialog_new(_("Select A File"),
324             NULL, GTK_FILE_CHOOSER_ACTION_OPEN,
325             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
326             GTK_STOCK_OPEN, GTK_RESPONSE_OK,
327             NULL);
328
329         if (memcard == 1)
330                 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(chooser), Config.Mcd1);
331         else
332                 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(chooser), Config.Mcd2);
333
334         if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) {
335                 gtk_widget_hide(chooser);
336
337                 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
338
339                 if (filename != NULL) {
340                         if (memcard == 1) strncpy(Config.Mcd1, filename, MAXPATHLEN);
341                         else strncpy(Config.Mcd2, filename, MAXPATHLEN);
342
343                         LoadMcd(memcard, filename);
344                         LoadMcdDlg(widget);
345
346                         g_free(filename);
347                 }
348         }
349
350         gtk_widget_destroy(chooser);
351 }
352
353 // format a memory card
354 static void OnMcd_Format(GtkWidget *widget, gpointer user_data) {
355         GladeXML *xml;
356         GtkWidget *message_dialog;
357         gint result;
358         char *str;
359
360         gint memcard = (int)user_data;
361
362         message_dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
363                 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
364                 _("Format this Memory Card?"));
365         gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(message_dialog),
366                 _("If you format the memory card, the card will be empty, and any existing data overwritten."));
367         gtk_dialog_add_buttons(GTK_DIALOG(message_dialog),
368                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
369                 _("Format card"), GTK_RESPONSE_YES, NULL);
370
371         result = gtk_dialog_run(GTK_DIALOG(message_dialog));
372         gtk_widget_destroy(message_dialog);
373
374         if (result == GTK_RESPONSE_YES) {
375                 xml = glade_get_widget_tree(widget);
376
377                 if (memcard == 1) str = Config.Mcd1;
378                 else str = Config.Mcd2;
379
380                 CreateMcd(str);
381                 LoadMcd(memcard, str);
382
383                 UpdateMcdDlg(widget);
384         }
385 }
386
387 // create a new, formatted memory card
388 static void OnMcd_New(GtkWidget *widget, gpointer user_data) {
389         GtkWidget *chooser;
390         gchar *path;
391
392         // Ask for name of new memory card
393         chooser = gtk_file_chooser_dialog_new(_("Create a new Memory Card"),
394             NULL, GTK_FILE_CHOOSER_ACTION_SAVE,
395             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
396             GTK_STOCK_SAVE, GTK_RESPONSE_OK,
397             NULL);
398
399         // Card should be put into $HOME/.pcsx/memcards
400         path = g_build_filename(g_get_home_dir(), ".pcsx", "memcards", NULL);
401         gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), path);
402         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(chooser), _("New Memory Card.mcd"));
403         gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(chooser), TRUE);
404
405         if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) {
406                 gchar *name;
407
408                 gtk_widget_hide(chooser);
409                 name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
410
411                 CreateMcd(name);
412
413                 if ((int)user_data == 1) strncpy(Config.Mcd1, name, MAXPATHLEN);
414                 else strncpy(Config.Mcd2, name, MAXPATHLEN);
415
416                 LoadMcd((int)user_data, name);
417                 LoadMcdDlg(widget);
418
419                 g_free(name);
420         }
421
422         gtk_widget_destroy(chooser);
423         g_free(path);
424 }
425
426 static int copy = 0, copymcd = 0;
427
428 static int GetFreeMemcardSlot(int target_card) {
429         McdBlock *Info;
430         gboolean found = FALSE;
431
432         int i = 0;
433         while (i < 15 && found == FALSE) {
434                 Info = &Blocks[target_card][i];
435                 if (g_ascii_strcasecmp(Info->Title, "") == 0) {
436                         found = TRUE;
437                 } else {
438                         i++;
439                 }
440         }
441
442         if (found == TRUE)
443                 return i;
444
445         // no free slots, try to find a deleted one
446         i = 0;
447         while (i < 15 && found == FALSE) {
448                 Info = &Blocks[target_card][i];
449                 if ((Info->Flags & 0xF0) != 0x50) {
450                         found = TRUE;
451                 } else {
452                         i++;
453                 }
454         }
455
456         if (found == TRUE)
457                 return i;
458
459         return -1;
460 }
461
462 static void CopyMemcardData(char *from, char *to, gint *i, gchar *str) {
463         memcpy(to + (*i + 1) * 128, from + (copy + 1) * 128, 128);
464         SaveMcd((char *)str, to, (*i + 1) * 128, 128);
465         memcpy(to + (*i + 1) * 1024 * 8, from + (copy+1) * 1024 * 8, 1024 * 8);
466         SaveMcd((char *)str, to, (*i + 1) * 1024 * 8, 1024 * 8);
467 }
468
469 static void OnMcd_CopyTo(GtkWidget *widget, gpointer user_data) {
470         gint mcd = (gint)user_data;
471
472         GtkTreeIter iter;
473         GtkTreeModel *model;
474         GtkTreePath *path;
475         gint *i;
476         GladeXML *xml;
477         GtkTreeSelection *treesel;
478         gchar *str;
479         char *source, *destination;
480
481         int first_free_slot;
482
483         xml = glade_get_widget_tree(widget);
484
485         if (mcd == 1)
486                 treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(GtkCList_McdList2));
487         else
488                 treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(GtkCList_McdList1));
489
490         // If the item selected is not reported as a 'Free' slot
491         if (gtk_tree_selection_get_selected(treesel, &model, &iter)) {
492                 path = gtk_tree_model_get_path(model, &iter);
493                 i = gtk_tree_path_get_indices(path);
494                 copy    = *i;
495                 copymcd = mcd;
496                 gtk_tree_path_free(path);
497         }
498
499         // Determine the first free slot in the target memory card
500         first_free_slot = GetFreeMemcardSlot(mcd - 1);
501         if (first_free_slot == -1) {
502                 // No free slots available on the destination card
503                 SysErrorMessage(_("No free space on memory card"),
504                                                 _("There are no free slots available on the target memory card. Please delete a slot first."));
505                 return;
506         }
507
508         xml = glade_get_widget_tree(GtkCList_McdList1);
509
510         if (mcd == 1) {
511                 str = Config.Mcd1;
512                 source = Mcd2Data;
513                 destination = Mcd1Data;
514         } else {
515                 str = Config.Mcd2;
516                 source = Mcd1Data;
517                 destination = Mcd2Data;
518         }
519
520         CopyMemcardData(source, destination, &first_free_slot, str);
521         UpdateMcdDlg(widget);
522 }
523
524 static void OnMemcardDelete(GtkWidget *widget, gpointer user_data) {
525         McdBlock *Info;
526         int i, xor = 0, j;
527         char *data, *ptr;
528         GtkTreeIter iter;
529         GtkTreeModel *model;
530         GtkTreePath *path;
531         gchar *filename;
532         GladeXML *xml;
533         gboolean selected;
534         GtkWidget *tree;
535         GtkTreeSelection *sel;
536
537         gint memcard = (int)user_data;
538
539         xml = glade_get_widget_tree(widget);
540
541         if (memcard == 1) {
542                 tree = glade_xml_get_widget(xml, "GtkCList_McdList1");
543                 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW (tree));
544                 selected = gtk_tree_selection_get_selected (sel, &model, &iter);
545                 data = Mcd1Data;
546                 filename = Config.Mcd1;
547         } else {
548                 tree = glade_xml_get_widget(xml, "GtkCList_McdList2");
549                 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW (tree));
550                 selected = gtk_tree_selection_get_selected(sel, &model, &iter);
551                 data = Mcd2Data;
552                 filename = Config.Mcd2;
553         }
554
555         if (selected) {
556                 path = gtk_tree_model_get_path(model, &iter);
557                 i = *gtk_tree_path_get_indices(path);
558
559                 i++;
560                 ptr = data + i * 128;
561                 Info = &Blocks[memcard - 1][i - 1];
562
563                 if ((Info->Flags & 0xF0) == 0xA0) {
564                         if ((Info->Flags & 0xF) >= 1 &&
565                                 (Info->Flags & 0xF) <= 3) { // deleted
566                                 *ptr = 0x50 | (Info->Flags & 0xF);
567                         } else return;
568                 } else if ((Info->Flags & 0xF0) == 0x50) { // used
569                                 *ptr = 0xA0 | (Info->Flags & 0xF);
570                 } else { return; }
571
572                 for (j = 0; j < 127; j++) xor ^= *ptr++;
573                 *ptr = xor;
574
575                 SaveMcd((char *)filename, data, i * 128, 128);
576                 UpdateMcdDlg(widget);
577         }
578 }
579
580 static void OnTreeSelectionChanged(GtkTreeSelection *selection, gpointer user_data) {
581         GladeXML *xml;
582         GtkTreeIter iter;
583         GtkTreeModel *model;
584         GtkTreePath *path;
585
586         gboolean selected;
587         int i;
588         McdBlock b;
589
590         gint memcard = (int)user_data;
591
592         xml = glade_get_widget_tree(GtkCList_McdList1);
593         selected = gtk_tree_selection_get_selected(selection, &model, &iter);
594
595         if (selected) {
596                 path = gtk_tree_model_get_path(model, &iter);
597                 i = *gtk_tree_path_get_indices(path);
598                 gtk_tree_path_free(path);
599
600                 // If a row was selected, and the row is not blank, we can now enable
601                 // some of the disabled widgets
602                 if (memcard == 1) {
603                         GetMcdBlockInfo(1, i + 1, &b);
604
605                         if ((b.Flags >= 0xA1 && b.Flags <= 0xA3) || ((b.Flags & 0xF0) == 0x50)) {
606                                 gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete1"), TRUE);
607                         } else {
608                                 gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete1"), FALSE);
609                         }
610
611                         if ((b.Flags & 0xF0) == 0x50) {
612                                 gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo2"), TRUE);
613                         } else {
614                                 gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo2"), FALSE);
615                         }
616                 } else {
617                         GetMcdBlockInfo(2, i + 1, &b);
618
619                         if ((b.Flags >= 0xA1 && b.Flags <= 0xA3) || ((b.Flags & 0xF0) == 0x50)) {
620                                 gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete2"), TRUE);
621                         } else {
622                                 gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete2"), FALSE);
623                         }
624
625                         if ((b.Flags & 0xF0) == 0x50) {
626                                 gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo1"), TRUE);
627                         } else {
628                                 gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo1"), FALSE);
629                         }
630                 }
631         } else {
632                 if (memcard == 1) {
633                         gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo2"), FALSE);
634                         gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete1"), FALSE);
635                 } else {
636                         gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo1"), FALSE);
637                         gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete2"), FALSE);
638                 }
639         }
640 }
641
642 gboolean updateFunc(gpointer data) {
643         if (quit) return FALSE;
644         currentIcon++;
645         UpdateListItems(1, GtkCList_McdList1);
646         UpdateListItems(2, GtkCList_McdList2);
647         g_timeout_add(333, updateFunc, 0);
648         return FALSE;
649 }
650
651 void OnConf_Mcds() {
652         GladeXML *xml;
653         GtkWidget *dialog;
654         GtkWidget *widget;
655         GtkTreeSelection *treesel1, *treesel2;
656         gchar *str;
657
658         xml = glade_xml_new(PACKAGE_DATA_DIR "pcsx.glade2", "McdsDlg", NULL);
659
660         if (!xml) {
661                 g_warning("We could not load the interface!");
662                 return;
663         }
664
665         dialog = glade_xml_get_widget(xml, "McdsDlg");
666
667         gtk_window_set_title(GTK_WINDOW(dialog), _("Memory Card Manager"));
668
669         // Assign default memory cards
670         if (!strlen(Config.Mcd1)) {
671                 str = g_strconcat(getenv("HOME"), DEFAULT_MEM_CARD_1, NULL);
672                 strcpy(Config.Mcd1, str);
673                 g_free(str);
674         }
675
676         if (!strlen(Config.Mcd2)) {
677                 str = g_strconcat(getenv("HOME"), DEFAULT_MEM_CARD_2, NULL);
678                 strcpy(Config.Mcd2, str);
679                 g_free(str);
680         }
681
682         GtkCList_McdList1 = glade_xml_get_widget(xml, "GtkCList_McdList1");
683         AddColumns(GTK_TREE_VIEW(GtkCList_McdList1));
684         GtkCList_McdList2 = glade_xml_get_widget(xml, "GtkCList_McdList2");
685         AddColumns(GTK_TREE_VIEW(GtkCList_McdList2));
686
687         treesel1 = gtk_tree_view_get_selection(GTK_TREE_VIEW (GtkCList_McdList1));
688         gtk_tree_selection_set_mode(treesel1, GTK_SELECTION_SINGLE);
689         g_signal_connect_data(G_OBJECT(treesel1), "changed",
690                                                   G_CALLBACK(OnTreeSelectionChanged),
691                                                   (gpointer)1, NULL, G_CONNECT_AFTER);
692
693         treesel2 = gtk_tree_view_get_selection(GTK_TREE_VIEW (GtkCList_McdList2));
694         gtk_tree_selection_set_mode(treesel2, GTK_SELECTION_SINGLE);
695         g_signal_connect_data(G_OBJECT(treesel2), "changed",
696                                                   G_CALLBACK(OnTreeSelectionChanged),
697                                                   (gpointer)2, NULL, G_CONNECT_AFTER);
698
699         LoadMcdDlg(dialog);
700
701         // Setup a handler for when Close or Cancel is clicked
702         g_signal_connect_data(GTK_OBJECT(dialog), "response",
703                         GTK_SIGNAL_FUNC(OnMcd_Close), xml, (GClosureNotify)g_object_unref, G_CONNECT_AFTER);
704
705         widget = glade_xml_get_widget(xml, "GtkButton_Format1");
706         g_signal_connect_data(GTK_OBJECT(widget), "clicked",
707                         GTK_SIGNAL_FUNC(OnMcd_Format), (gpointer)1, NULL, G_CONNECT_AFTER);
708
709         widget = glade_xml_get_widget(xml, "GtkButton_Format2");
710         g_signal_connect_data(GTK_OBJECT(widget), "clicked",
711                         GTK_SIGNAL_FUNC(OnMcd_Format), (gpointer)2, NULL, G_CONNECT_AFTER);
712
713         widget = glade_xml_get_widget(xml, "Mcd1Button");
714         g_signal_connect_data(GTK_OBJECT(widget), "clicked",
715                         GTK_SIGNAL_FUNC(OnMcd_FileChange), (gpointer)1, NULL, G_CONNECT_AFTER);
716
717         widget = glade_xml_get_widget(xml, "Mcd2Button");
718         g_signal_connect_data(GTK_OBJECT(widget), "clicked",
719                         GTK_SIGNAL_FUNC(OnMcd_FileChange), (gpointer)2, NULL, G_CONNECT_AFTER);
720
721         widget = glade_xml_get_widget(xml, "GtkButton_New1");
722         g_signal_connect_data(GTK_OBJECT(widget), "clicked",
723                         GTK_SIGNAL_FUNC(OnMcd_New), (gpointer)1, NULL, G_CONNECT_AFTER);
724
725         widget = glade_xml_get_widget(xml, "GtkButton_New2");
726         g_signal_connect_data(GTK_OBJECT(widget), "clicked",
727                         GTK_SIGNAL_FUNC(OnMcd_New), (gpointer)2, NULL, G_CONNECT_AFTER);
728
729         widget = glade_xml_get_widget(xml, "GtkButton_CopyTo1");
730         g_signal_connect_data(GTK_OBJECT(widget), "clicked",
731                         GTK_SIGNAL_FUNC(OnMcd_CopyTo), (gpointer)1, NULL, G_CONNECT_AFTER);
732         gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE);
733
734         widget = glade_xml_get_widget(xml, "GtkButton_CopyTo2");
735         g_signal_connect_data(GTK_OBJECT(widget), "clicked",
736                         GTK_SIGNAL_FUNC(OnMcd_CopyTo), (gpointer)2, NULL, G_CONNECT_AFTER);
737         gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE);
738
739         widget = glade_xml_get_widget(xml, "GtkButton_Delete1");
740         g_signal_connect_data (GTK_OBJECT (widget), "clicked",
741                         GTK_SIGNAL_FUNC(OnMemcardDelete), (gpointer)1, NULL, G_CONNECT_AFTER);
742         gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE);
743
744         widget = glade_xml_get_widget(xml, "GtkButton_Delete2");
745         g_signal_connect_data (GTK_OBJECT (widget), "clicked",
746                         GTK_SIGNAL_FUNC(OnMemcardDelete), (gpointer)2, NULL, G_CONNECT_AFTER);
747         gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE);
748
749         quit = FALSE;
750         currentIcon = 0;
751
752     g_timeout_add(1, updateFunc, 0);
753
754         while (gtk_events_pending()) {  gtk_main_iteration(); }
755 }