#include <stdlib.h> /* for srand48() */
#include <unistd.h> /* for "access()" */
#include <stdio.h>
#include <limits.h> /* for POSIX_PATH_MAX */
#include <Xatom.h>
#include <Xfuncs.h> /* handles bzero redefine stuff */
#include <Xos.h>
#include <Intrinsic.h>
#include <StringDefs.h>
#include <Shell.h>
#include <Xaw/Command.h>
#include <Xaw/Label.h>
#include <Xaw/Form.h>
#include <Composite.h>
#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();
}
syntax highlighted by Code2HTML, v. 0.9.1