#include /* for srand48() */ #include /* for "access()" */ #include #include /* for POSIX_PATH_MAX */ #include #include /* handles bzero redefine stuff */ #include #include #include #include #include #include #include #include #include "defs.h" #include "externs.h" #include "game.h" #include "grades.h" #include "options.h" #include "searchwidgets.h" #include "widgets.h" #include "timeout.h" #include "icon_xbm" int lowfrequency=0,highfrequency=0; char *usefile=NULL; /* global pointer that indicates if usefile is * AVAILABLE, not neccessarily that it is used */ char usefilename[100]; Atom wm_message,delete_message; /* * This array has "fallback resources", in case * the normal "KDrill" resource file is not present. * Note that it is an either/or situation. * If there is a KDrill app-resources file on the system, * these fallback resources WILL NOT BE LOOKED AT !!! * * If you add something to this list, consider adding it to * SaveConfig() as well!! * And dont forget that you have to use SetXtrmXXXX() routines * to have the values available for SaveConfig() also!! * */ static char *fallback[] = { "KDrill.options_popupx: 0", "KDrill.options_popupy: -200", "KDrill.search_popupx: 400", /* should really be precise, but... */ "KDrill.search_popupy: 0", "KDrill.notallT: 0", "KDrill.noBell: 0", "KDrill.nousefile: 1", "KDrill.usefile: .kanjiusefile", DICTLOCATION, /* change this value in Imakefile !!*/ EDICTLOCATION, /* change this value in Imakefile !!*/ RADLOCATION, /* change this value in Imakefile !!*/ "KDrill.kanjifont: -jis-*--24*jisx0208*", "KDrill.smallkanji: -jis-*--16*jisx0208*", "KDrill.englishfont: fixed", "KDrill.gradelevel: 0", "KDrill.guessmode: english", "KDrill.questionmode: kanji", "KDrill.romajiswitch: 0", "KDrill.lowfrequency: 0", "KDrill.highfrequency: 0", "KDrill.timersec: 7", "KDrill.logfile: kdrill.log", NULL }; /* command line arguments should set the appropriate resources.. so we can * pull them out when wanted */ static XrmOptionDescRec optionDescList[] = { {"-notallT", ".notallT",XrmoptionNoArg,"1"}, {"-usefile", ".usefile", XrmoptionSepArg,(caddr_t) NULL}, {"-nousefile", ".nousefile", XrmoptionNoArg, "1"}, {"-kdictfile", ".kdictfile", XrmoptionSepArg,(caddr_t) NULL}, {"-edictfile", ".edictfile", XrmoptionSepArg,(caddr_t) NULL}, {"-radkfile", ".radkfile", XrmoptionSepArg,(caddr_t) NULL}, {"-englishfont",".englishfont", XrmoptionSepArg,(caddr_t) NULL}, {"-kanjifont", ".kanjifont", XrmoptionSepArg,(caddr_t) NULL}, {"-smallkanji", ".smallkanji", XrmoptionSepArg,(caddr_t) NULL}, {"-noBell", ".noBell", XrmoptionNoArg, "1"}, {"-guessmode", ".guessmode", XrmoptionSepArg,(caddr_t) NULL}, {"-questionmode",".questionmode",XrmoptionSepArg,(caddr_t) NULL}, {"-romajiswitch", ".romajiswitch", XrmoptionNoArg,"1"}, {"-showinorder", ".showinorder", XrmoptionNoArg,"1"}, {"-gradelevel", ".gradelevel", XrmoptionSepArg,(caddr_t) NULL}, {"-lowfrequency", ".lowfrequency",XrmoptionSepArg,(caddr_t) NULL}, {"-highfrequency", ".highfrequency",XrmoptionSepArg,(caddr_t) NULL}, {"-logfile", ".logfile", XrmoptionSepArg,(caddr_t) NULL}, }; /* handle_delete * Its sole purpose is to handle WM_DELETE messages. * These days, we want to only CLOSE windows that aren't the * main one. * */ void handle_delete(Widget w,XtPointer closure,XEvent *event,Boolean *cont) { XClientMessageEvent *cevent = (XClientMessageEvent *) event; puts("DEBUG: handle_delete called !!\n"); if(cevent->type != ClientMessage) return; if(cevent->message_type != wm_message) return; if(cevent->data.l[0] != delete_message) return; if(w == toplevel){ quit(NULL, NULL, NULL); } #ifdef DEBUG puts("In handle_delete..."); if(XtIsTopLevelShell(w)){ puts(" IS a top level shell"); } if(XtIsShell(w)){ puts(" IS a shell"); } if(XtIsTransientShell(w)){ puts(" IS a 'transient' shell"); } if(XtIsTopLevelShell(XtParent(w))){ puts(" PARENT is a top level shell"); } if(XtIsShell(XtParent(w))){ puts(" PARENT is a shell"); } if(XtIsTransientShell(XtParent(w))){ puts(" PARENT is a 'transient' shell"); } #endif /* DEBUG */ /* Problem here: there are three types of windows we have to deal with: "Option window" type (shell, transient) multi-match window (toplevel, shell) seach window (toplevel, shell: but DIFFERENT from multi somehow) XtPopdown works for the first two, but only UnmapWidget works for last kind. The only difference I can see, is that the search window has "toplevel" as its parent, which is not strictly speaking just a window. It is what XtVaAppInitialize() returns. It CONTAINS a window, but is not merely a window. searchwindow is made that way, to remain open, when the main window is iconified. I *could* just special-case it. But i hate special cases. */ XtPopdown(w); if(isMapped(w)){ /* if it is still showing.. try harder! */ XtUnmapWidget(w); } } /* initgc: * Initialises global gc values. * We don't really need this any more. But * GC's are good to have, I suppose. */ void initgc(){ gc = XCreateGC(display,mainwindow,0,NULL); cleargc = XCreateGC(display,mainwindow,0,NULL); XSetForeground(display,gc,black); XSetBackground(display,gc,white); XSetForeground(display,cleargc,white); XSetBackground(display,cleargc,black); } /* GetOptions * get resource and command line options. * (The nice thing is that thanks to Xt, commandline options * get auto-translated to resources already */ void GetOptions(){ int tmpnumber; char tmpstr[100]; /* set grade bits appropriately */ GetXtrmString("gradelevel","Gradelevel",tmpstr); parsegrades(tmpstr); switchKanaEnglish = !GetXtrmBoolean("notallT","NotallT"); /* default of nousefile is FALSE. which means * useUsefile defaults to TRUE */ useUsefile = !GetXtrmBoolean("nousefile","Nousefile"); doBell = !GetXtrmBoolean("noBell","NoBell"); showinorder = GetXtrmBoolean("showinorder","Showinorder"); lowfrequency = GetXtrmNumber("lowfrequency","Lowfrequency"); if((lowfrequency <0) || (lowfrequency >=MAXTRANSLATIONSALLOWED)) lowfrequency = 0; highfrequency = GetXtrmNumber("highfrequency","Highfrequency"); if((highfrequency <0) || (highfrequency >=MAXTRANSLATIONSALLOWED)) highfrequency = 0; tmpnumber = GetXtrmNumber("timersec","Timersec"); setTimeoutLen(tmpnumber); GetXtrmString("guessmode", "Guessmode", tmpstr); if(strcmp(tmpstr, "english")==0){ choicesmode = GUESS_ENGLISH; }else if(strcmp(tmpstr, "kanji")==0){ choicesmode = GUESS_KANJI; } else{ choicesmode = GUESS_KANA; } GetXtrmString("questionmode", "Questionmode", tmpstr); if(strcmp(tmpstr, "english")==0){ questionmode=GUESS_ENGLISH; } else if (strcmp(tmpstr, "kanji")==0){ questionmode=GUESS_KANJI; } else{ questionmode=GUESS_KANA; } if( GetXtrmBoolean("romajiswitch","Romajiswitch")) romajiswitch = 1; } /* this routine is solely for internalizing various * "Atoms" neccessary to handle the stupid WM_DELETE_WINDOW * message */ void setup_deletewindow(Widget winwidget) { /* Must wait for the window to actually appear. sigh.*/ XFlush(display); XSync(display,False); /* This should be redundant, but... */ if(wm_message==(Atom)NULL){ wm_message=XInternAtom(display,"WM_PROTOCOLS",False); delete_message=XInternAtom(display,"WM_DELETE_WINDOW",False); if (wm_message == (Atom) NULL) { perror("unable to create wm_message property"); exit(1); } if (delete_message == (Atom) NULL) { perror("unable to create delete property"); exit(1); } } XtAddEventHandler(winwidget, NoEventMask, True, handle_delete, (XtPointer)NULL); XtAugmentTranslations(winwidget, AllAccel); /* I haven't figured out why we would be called when this is 0. * Seems to be a strange bug in X. sigh. */ if(XtWindow(winwidget)==0){ /*printf("XtWindow is %d\n",XtWindow(winwidget));*/ return; } XChangeProperty(display, XtWindow(winwidget), wm_message, XA_ATOM, 32, PropModeReplace, (unsigned char *) &delete_message, 1); } #ifndef _POSIX_PATH_MAX #define _POSIX_PATH_MAX 1024 #endif /* If we have the appropriate functions (X11R6?) * load up our own special user-specific xresources file * We need the global 'display' set */ void init_xdb() { char XFileName[_POSIX_PATH_MAX]; XrmDatabase globaldb; sprintf(XFileName,"%s/.kdrill", homedir); globaldb=XrmGetDatabase(display); /* override "global" prefs with user specific ones */ /* That way, we try to keep working, even if prefs file * is screwed up */ XrmCombineFileDatabase(XFileName, &globaldb, True); } /* initstuffs: * calls the various init routines to setup * GCs, fonts, dictionaries, and widgets * (But initializing the translations is done later) */ static Pixmap iconpixmap; void initstuffs(int *argc,char *argv[]) { srand48 (time(NULL)); bzero(translations, sizeof(struct translationstruct *) * MAXTRANSLATIONSALLOWED); lowestkanji = highestkanji = 0; homedir = (char *) getenv("HOME"); if(homedir == NULL){ puts("WARNING: no 'HOME' environment variable"); puts("Faking with '.' instead"); homedir="."; } toplevel = XtVaAppInitialize(&Context,"KDrill", optionDescList,XtNumber(optionDescList), argc,argv,fallback, NULL,NULL); if(*argc >1){ usage(); } display = XtDisplay(toplevel); if(display == NULL) perror("NULL DISPLAY"); #ifndef NOXRMSAVE init_xdb(); #endif /*NOXRMSAVE*/ /* Get command line options... yeah, we should do this in a * struct, in one go... but some things need to be initalized * later */ white = XWhitePixel(display,0); black = XBlackPixel(display,0); GetOptions(); MakeWidgets(); XtRealizeWidget(toplevel); mainwindow = XtWindow(toplevel); if(mainwindow == 0) perror("NULL WINDOW"); setup_deletewindow(toplevel); iconpixmap = XCreateBitmapFromData(display,mainwindow, (char *)icon_xbm_bits, icon_xbm_width,icon_xbm_height); XtVaSetValues(toplevel,XtNiconName,"kdrill", XtNiconPixmap,iconpixmap,NULL); /* Why doesnt this work? It should... ? */ XtVaSetValues(search_popup,XtNiconName,"kdrill_search", XtNiconPixmap,iconpixmap,NULL); initgc(); }