Crossfire Client, Branch  R11627
xutil.c
Go to the documentation of this file.
00001 const char *rcsid_x11_xutil_c =
00002     "$Id: xutil.c 9201 2008-06-01 17:32:45Z anmaster $";
00003 /*
00004     Crossfire client, a client program for the crossfire program.
00005 
00006     Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 
00022     The author can be reached via e-mail to crossfire-devel@real-time.com
00023 */
00024 
00025 /* This contains various 'support' functions.  These functions will probably
00026  * go mostly unaltered between different toolkits, as long as X11 is still
00027  * used.
00028  */
00029 
00030 #include <client.h>
00031 #include <item.h>
00032 #include <config.h>
00033 #include <p_cmd.h>
00034 
00035 #ifdef HAVE_LIBXPM
00036 #include <X11/xpm.h>
00037 #endif
00038 
00039 #include <X11/Xlib.h>
00040 #include <X11/Xutil.h>
00041 #include <X11/keysym.h>
00042 
00043 #include "def-keys.h"
00044 #include "x11proto.h"
00045 #include "x11.h"
00046 
00047 
00048 static const char * const colorname[] = {
00049 "Black",                /* 0  */
00050 "White",                /* 1  */
00051 "Navy",                 /* 2  */
00052 "Red",                  /* 3  */
00053 "Chocolate",            /* 4  was Orange, but impossible to read on DarkSeaGreen */
00054 "DodgerBlue",           /* 5  */
00055 "DarkOrange2",          /* 6  */
00056 "SeaGreen",             /* 7  */
00057 "DarkSeaGreen",         /* 8  */
00058 "Grey80",               /* 9  */        /* Used for window background color */
00059 "Sienna",               /* 10 */
00060 "Gold",                 /* 11 */
00061 "Khaki"                 /* 12 */
00062 };
00063 
00064 struct {
00065     char    *name;
00066     uint32  checksum;
00067     Pixmap  pixmap, mask;
00068 } private_cache[MAXPIXMAPNUM];
00069 
00070 int use_private_cache=0, last_face_num=0;
00071 
00072 
00073 /******************************************************************************
00074  *
00075  * Code related to face caching.
00076  *
00077  *****************************************************************************/
00078 
00079 typedef struct Keys {
00080     uint8       flags;
00081     sint8       direction;
00082     KeySym      keysym;
00083     char        *command;
00084     struct Keys *next;
00085 } Key_Entry;
00086 
00087 /***********************************************************************
00088  *
00089  * Key board input translations are handled here.  We don't deal with
00090  * the events, but rather KeyCodes and KeySyms.
00091  *
00092  * It would be nice to deal with only KeySyms, but many keyboards
00093  * have keys that do not correspond to a KeySym, so we do need to
00094  * support KeyCodes.
00095  *
00096  ***********************************************************************/
00097 
00098 
00099 static KeyCode firekey[2], runkey[2], commandkey, *bind_keycode, prevkey, nextkey,
00100     completekey;
00101 static KeySym firekeysym[2], runkeysym[2], commandkeysym,*bind_keysym,
00102     prevkeysym, nextkeysym, completekeysym;
00103 static int bind_flags=0;
00104 static char bind_buf[MAX_BUF];
00105 
00106 #define KEYF_NORMAL     0x01    /* Used in normal mode */
00107 #define KEYF_FIRE       0x02    /* Used in fire mode */
00108 #define KEYF_RUN        0x04    /* Used in run mode */
00109 #define KEYF_MODIFIERS  0x07    /* Mask for actual keyboard modifiers, */
00110                                 /* not action modifiers */
00111 #define KEYF_EDIT       0x08    /* Line editor */
00112 #define KEYF_STANDARD   0x10    /* For standard (built in) key definitions */
00113 
00114 extern const char * const directions[9];
00115 
00116 /* Key codes can only be from 8-255 (at least according to
00117  * the X11 manual.  This is easier than using a hash
00118  * table, quicker, and doesn't use much more space.
00119  */
00120 
00121 #define MAX_KEYCODE 255
00122 static Key_Entry *keys[256];
00123 
00124 /* Can be set when user is moving to new machine type */
00125 uint8 updatekeycodes=FALSE;
00126 
00127 #ifndef GDK_XUTIL
00128 /* Initializes the data for image caching */
00129 void init_cache_data(void)
00130 {
00131     int i;
00132     Pixmap  ptmp;
00133 #include "pixmaps/question.111"
00134 
00135 
00136     /* Currently, we can cache in all face modes currently supported,
00137      * so I removed the code that did checks on that.
00138      */
00139 
00140     pixmaps[0] = malloc(sizeof(struct PixmapInfo));
00141     pixmaps[0]->mask=None;
00142     ptmp=XCreateBitmapFromData(display,DefaultRootWindow(display),
00143                                 question_bits,question_width,question_height);
00144 
00145     /* In xpm mode, XCopyArea is used from this data, so we need to copy
00146      * the image into an pixmap of appropriate depth.
00147      */
00148     pixmaps[0]->pixmap=XCreatePixmap(display, win_root, image_size, image_size,
00149         DefaultDepth(display,DefaultScreen(display)));
00150     pixmaps[0]->width = 1;
00151     pixmaps[0]->height = 1;
00152     XCopyPlane(display, ptmp, pixmaps[0]->pixmap, gc_game,
00153                0,0,image_size,image_size,0,0,1);
00154     XFreePixmap(display, ptmp);
00155 
00156     /* Initialize all the images to be of the same value. */
00157     for (i=1; i<MAXPIXMAPNUM; i++)  {
00158         pixmaps[i]=pixmaps[0];
00159     }
00160 
00161     init_common_cache_data();
00162 
00163 }
00164 #endif
00165 
00166 /* Rotate right from bsd sum. */
00167 #define ROTATE_RIGHT(c) if ((c) & 01) (c) = ((c) >>1) + 0x80000000; else (c) >>= 1;
00168 
00169 /*#define CHECKSUM_DEBUG*/
00170 
00171 
00172 void allocate_colors(Display *disp, Window w, long screen_num,
00173         Colormap *colormap, XColor discolor[16]) {
00174   int i, tried = 0, depth=0;
00175   Status status;
00176   Visual *vis;
00177   XColor exactcolor;
00178 
00179   vis = DefaultVisual(disp,screen_num);
00180   if (vis->class >= StaticColor) {
00181     *colormap = DefaultColormap(disp,screen_num);
00182     depth = DefaultDepth(disp,screen_num);
00183   }
00184   else {
00185     *colormap = DefaultColormap(disp,screen_num);
00186     printf("You have a black and white terminal.\n");
00187     printf("These are no longer supported by cfclient.\n");
00188     return;
00189   }
00190 try_private:
00191   if (depth > 3) {
00192     unsigned long pixels[13];
00193     for (i=0; i<13; i++){
00194       status = XLookupColor(disp,*colormap, colorname[i],&exactcolor,
00195                             &discolor[i]);
00196       if (!status){
00197         printf("Can't find colour %s.\n", colorname[i]);
00198         break;
00199       }
00200       status = XAllocColor(disp,*colormap,&discolor[i]);
00201       if (!status) {
00202         if (!tried) {
00203           printf( "Not enough colours. Trying a private colourmap.\n");
00204           XFreeColors(disp, *colormap, pixels, i-1, 0);
00205           *colormap = XCreateColormap(disp, w, vis, AllocNone);
00206           XSetWindowColormap(disp, w, *colormap);
00207           tried = 1;
00208           goto try_private;
00209         } else break;
00210       }
00211       pixels[i] = discolor[i].pixel;
00212     }
00213   }
00214 }
00215 
00216 /* Updates the keys array with the keybinding that is passed.  All the
00217  * arguments are pretty self explanatory.  flags is the various state
00218  * that the keyboard is in.
00219  * This function is common to both gdk and x11 client
00220  */
00221 static void insert_key(KeySym keysym, KeyCode keycode, int flags, char *command)
00222 {
00223 
00224     Key_Entry *newkey;
00225     int i, direction=-1;
00226 
00227 #if 0
00228     /* This is at least a meaningless check on my system that results in
00229      * a compile warning (always false result), so may was well comment it
00230      * out - MSW 2005-02-09
00231      */
00232     if (keycode>MAX_KEYCODE) {
00233         LOG(LOG_WARNING,"x11::insert_key", "keycode that is passed is greater than 255.");
00234         keycode=0;      /* hopefully the rest of the data is OK */
00235     }
00236 #endif
00237     if (keys[keycode]==NULL) {
00238         keys[keycode]=malloc(sizeof(Key_Entry));
00239         keys[keycode]->command=NULL;
00240         keys[keycode]->next=NULL;
00241     }
00242     newkey=keys[keycode];
00243 
00244     /* Try to find out if the command is a direction command.  If so, we
00245      * then want to keep track of this fact, so in fire or run mode,
00246      * things work correctly.
00247      */
00248     for (i=0; i<9; i++)
00249         if (!strcmp(command, directions[i])) {
00250                 direction=i;
00251                 break;
00252         }
00253 
00254     if (keys[keycode]->command!=NULL) {
00255         /* if keys[keycode]->command is not null, then newkey is
00256          * the same as keys[keycode]->command.
00257          */
00258         while (newkey->next!=NULL)
00259             newkey = newkey->next;
00260         newkey->next = malloc(sizeof(Key_Entry));
00261         newkey = newkey->next;
00262         /* This is the only initializing we need to do - the other fields
00263          * will get filled in by the passed parameters
00264          */
00265         newkey->next = NULL;
00266     }
00267     newkey->keysym = keysym;
00268     newkey->flags = flags;
00269     newkey->command = strdup_local(command);
00270     newkey->direction = direction;
00271 }
00272 
00273 
00274 #ifdef GDK_XUTIL
00275 #define display GDK_DISPLAY()
00276 #endif
00277 
00278 /* This function is common to both gdk and x11 client */
00279 
00280 void parse_keybind_line(char *buf, int line, int standard)
00281 {
00282     char *cp, *cpnext;
00283     KeySym keysym;
00284     KeyCode keycode;
00285     int flags;
00286 
00287     if (buf[0]=='#' || buf[0]=='\n') return;
00288     if ((cpnext = strchr(buf,' '))==NULL) {
00289         LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted.", line,buf);
00290         return;
00291     }
00292     /* Special keybinding line */
00293     if (buf[0] == '!') {
00294         char *cp1;
00295         while (*cpnext == ' ') ++cpnext;
00296         cp = strchr(cpnext, ' ');
00297         if (!cp) {
00298             LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf);
00299             return;
00300         }
00301         *cp++ = 0;  /* Null terminate it */
00302         cp1 = strchr(cp, ' ');
00303         if (!cp1) {
00304             LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf);
00305             return;
00306         }
00307         *cp1 ++ = 0;/* Null terminate it */
00308         keycode = atoi(cp1);
00309         keysym = XStringToKeysym(cp);
00310         /* As of now, all these keys must have keysyms */
00311         if (keysym == NoSymbol) {
00312             LOG(LOG_WARNING,"x11::parse_keybind_line","Could not convert %s into keysym", cp);
00313             return;
00314         }
00315         if (!strcmp(cpnext,"commandkey")) {
00316             commandkeysym = keysym;
00317             commandkey = keycode;
00318             return;
00319         }
00320         if (!strcmp(cpnext,"firekey0")) {
00321             firekeysym[0] = keysym;
00322             firekey[0] = keycode;
00323             return;
00324         }
00325         if (!strcmp(cpnext,"firekey1")) {
00326             firekeysym[1] = keysym;
00327             firekey[1] = keycode;
00328             return;
00329         }
00330         if (!strcmp(cpnext,"runkey0")) {
00331             runkeysym[0] = keysym;
00332             runkey[0] = keycode;
00333             return;
00334         }
00335         if (!strcmp(cpnext,"runkey1")) {
00336             runkeysym[1] = keysym;
00337             runkey[1] = keycode;
00338             return;
00339         }
00340         if (!strcmp(cpnext,"completekey")) {
00341             completekeysym = keysym;
00342             completekey = keycode;
00343             return;
00344         }
00345         if (!strcmp(cpnext,"nextkey")) {
00346             nextkeysym = keysym;
00347             nextkey = keycode;
00348             return;
00349         }
00350         if (!strcmp(cpnext,"prevkey")) {
00351             prevkeysym = keysym;
00352             prevkey = keycode;
00353             return;
00354         }
00355     }
00356     if (standard) standard=KEYF_STANDARD;
00357     else standard=0;
00358 
00359     *cpnext++ = '\0';
00360     keysym = XStringToKeysym(buf);
00361     cp = cpnext;
00362     if ((cpnext = strchr(cp,' '))==NULL) {
00363         LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line, cp);
00364         return;
00365     }
00366     *cpnext++ = '\0';
00367 
00368     /* If we can, convert the keysym into a keycode.  */
00369     keycode = atoi(cp);
00370     cp = cpnext;
00371     if ((cpnext = strchr(cp,' '))==NULL) {
00372         LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line, cp);
00373         return;
00374     }
00375     *cpnext++ = '\0';
00376     flags = 0;
00377     while (*cp!='\0') {
00378         switch (*cp) {
00379         case 'A':
00380                 flags |= KEYF_NORMAL | KEYF_FIRE | KEYF_RUN;
00381                 break;
00382         case 'N':
00383                 flags |= KEYF_NORMAL;
00384                 break;
00385         case 'F':
00386                 flags |= KEYF_FIRE;
00387                 break;
00388         case 'R':
00389                 flags |= KEYF_RUN;
00390                 break;
00391         case 'E':
00392                 flags |= KEYF_EDIT;
00393                 break;
00394         case 'S':
00395                 flags |= KEYF_STANDARD;
00396                 break;
00397         default:
00398             LOG(LOG_WARNING,"x11::parse_keybind_line","Unknown flag (%c) line %d in key binding file",
00399                 *cp, line);
00400         }
00401         cp++;
00402     }
00403 
00404     /* This gets tricky - if we are reading the keycodes from the built
00405      * in defaults and keycodes are specified there, we want to honor them.
00406      */
00407     if ((keysym!=NoSymbol) &&
00408         (( (keycode == 1) && standard) || (flags&KEYF_STANDARD) || updatekeycodes)) {
00409 
00410         keycode = XKeysymToKeycode(display, keysym);
00411 
00412         /* It is possible that we get a keysym that we can not convert
00413          * into a keycode (such a case might be binding the key on
00414          * one system, and later trying to run on another system that
00415          * doesn't have that key.
00416          * While the client will not be able to use it this invocation,
00417          * it may be able to use it in the future.  As such, don't throw
00418          * it away, but at least print a warning message.
00419          */
00420         if (keycode==0) {
00421             LOG(LOG_WARNING,"x11::parse_keybind_line","could not convert keysym %s into keycode, ignoring",
00422                 buf);
00423         }
00424     }
00425     /* Rest of the line is the actual command.  Lets kill the newline */
00426     cpnext[strlen(cpnext)-1]='\0';
00427     if (strlen(cpnext)>(sizeof(bind_buf)-1)){
00428         cpnext[sizeof(bind_buf)-1]='\0';
00429         LOG(LOG_WARNING,"gtk::parse_keybind_line","Had to truncate a too long command");
00430     }
00431     insert_key(keysym, keycode, flags | standard, cpnext);
00432 }
00433 
00434 /* This code is common to both x11 and gdk client */
00435 static void init_default_keybindings(void)
00436 {
00437   char buf[MAX_BUF];
00438   int i;
00439 
00440   for(i=0;i< sizeof(def_keys)/sizeof(char *);i++) {
00441     strcpy(buf,def_keys[i]);
00442     parse_keybind_line(buf,i,1);
00443   }
00444 }
00445 
00446 
00447 /* This reads in the keybindings, and initializes any special values.
00448  * called by init_windows.
00449  */
00450 /* This function is common to both x11 and gdk client */
00451 
00452 void init_keys(void)
00453 {
00454     int i, line=0;
00455     FILE *fp;
00456     char buf[BIG_BUF];
00457 
00458     commandkeysym = XK_apostrophe;
00459     commandkey =XKeysymToKeycode(display,XK_apostrophe);
00460     if (!commandkey) {
00461       commandkeysym =XK_acute;
00462       commandkey =XKeysymToKeycode(display, XK_acute);
00463     }
00464     firekeysym[0] =XK_Shift_L;
00465     firekey[0] =XKeysymToKeycode(display, XK_Shift_L);
00466     firekeysym[1] =XK_Shift_R;
00467     firekey[1] =XKeysymToKeycode(display, XK_Shift_R);
00468     runkeysym[0]  =XK_Control_L;
00469     runkey[0]  =XKeysymToKeycode(display, XK_Control_L);
00470     runkeysym[1]  =XK_Control_R;
00471     runkey[1]  =XKeysymToKeycode(display, XK_Control_R);
00472 
00473     completekeysym = XK_Tab;
00474     completekey = XKeysymToKeycode(display, XK_Tab);
00475     /* Don't set these to anything by default.  At least on sun
00476      * keyboards, the keysym for up on both the keypad and arrow
00477      * keys is the same, so player needs to rebind this so we get proper
00478      * keycode.  Very unfriendly to log in and not be able to move north/south.
00479      */
00480     nextkeysym = NoSymbol;
00481     nextkey = 0;
00482     prevkeysym = NoSymbol;
00483     prevkey = 0;
00484 
00485     for (i=0; i<=MAX_KEYCODE; i++) {
00486         keys[i] = NULL;
00487     }
00488 
00489     /* We now try to load the keybindings.  First place to look is the
00490      * users home directory, "~/.crossfire/keys".  Using a directory
00491      * seems like a good idea, in the future, additional stuff may be
00492      * stored.
00493      *
00494      * The format is described in the def_keys file.  Note that this file
00495      * is the same as what it was in the server distribution.  To convert
00496      * bindings in character files to this format, all that needs to be done
00497      * is remove the 'key ' at the start of each line.
00498      *
00499      * We need at least one of these keybinding files to exist - this is
00500      * where the various commands are defined.  In theory, we actually
00501      * don't need to have any of these defined -- the player could just
00502      * bind everything.  Probably not a good idea, however.
00503      */
00504 
00505     sprintf(buf,"%s/.crossfire/keys", getenv("HOME"));
00506     if ((fp=fopen(buf,"r"))==NULL) {
00507         LOG(LOG_INFO,"x11::init_keys","Could not open ~/.crossfire/keys, trying to load global bindings");
00508         if (client_libdir==NULL) {
00509             init_default_keybindings();
00510             return;
00511         }
00512         sprintf(buf,"%s/def_keys", client_libdir);
00513         if ((fp=fopen(buf,"r"))==NULL) {
00514             init_default_keybindings();
00515             return;
00516         }
00517     }
00518     while (fgets(buf, BIG_BUF, fp)) {
00519         line++;
00520         parse_keybind_line(buf,line,0);
00521     }
00522     fclose(fp);
00523 }
00524 
00525 /* The only things we actually care about is the run and fire keys.
00526  * Other key releases are not important.
00527  * If it is the release of a run or fire key, we tell the client
00528  * to stop firing or running.  In some cases, it is possible that we
00529  * actually are not running or firing, and in such cases, the server
00530  * will just ignore the command.
00531  */
00532 
00533 /* This code is used by gdk and x11 client, but has
00534  *  a fair number of #ifdefs to get the right
00535  * behavioiur
00536  */
00537 void parse_key_release(KeyCode kc, KeySym ks) {
00538 
00539     /* Only send stop firing/running commands if we are in actual
00540      * play mode.  Something smart does need to be done when the character
00541      * enters a non play mode with fire or run mode already set, however.
00542      */
00543 
00544     if (kc==firekey[0] || ks==firekeysym[0] ||
00545         kc==firekey[1] || ks==firekeysym[1]) {
00546                 cpl.fire_on=0;
00547 #ifdef GDK_XUTIL
00548                 clear_fire();
00549                 gtk_label_set (GTK_LABEL(fire_label),"    ");
00550 #else
00551                 stop_fire();
00552                 draw_message_window(0);
00553 #endif
00554         }
00555     else if (kc==runkey[0] || ks==runkeysym[0] ||
00556         kc==runkey[1] || ks==runkeysym[1]) {
00557                 cpl.run_on=0;
00558                 if (use_config[CONFIG_ECHO]) draw_info("stop run",NDI_BLACK);
00559 #ifdef GDK_XUTIL
00560                 clear_run();
00561                 gtk_label_set (GTK_LABEL(run_label),"   ");
00562 #else
00563                 stop_run();
00564                 draw_message_window(0);
00565 #endif
00566         }
00567     /* Firing is handled on server side.  However, to keep more like the
00568      * old version, if you release the direction key, you want the firing
00569      * to stop.  This should do that.
00570      */
00571     else if (cpl.fire_on)
00572         stop_fire();
00573 }
00574 
00575 /* This parses a keypress.  It should only be called when in Playing
00576  * mode.
00577  */
00578 void parse_key(char key, KeyCode keycode, KeySym keysym, int repeated)
00579 {
00580     Key_Entry *keyentry, *first_match=NULL;
00581     int present_flags=0;
00582     char buf[MAX_BUF];
00583 
00584     if (keycode == commandkey && keysym==commandkeysym) {
00585         draw_prompt(">");
00586         cpl.input_state = Command_Mode;
00587         cpl.no_echo=FALSE;
00588         return;
00589     }
00590     if (keycode == firekey[0] || keysym==firekeysym[0] ||
00591         keycode == firekey[1] || keysym==firekeysym[1]) {
00592                 cpl.fire_on=1;
00593 #ifdef GDK_XUTIL
00594                 gtk_label_set (GTK_LABEL(fire_label),"Fire");
00595 #else
00596                 draw_message_window(0);
00597 #endif
00598                 return;
00599         }
00600     if (keycode == runkey[0] || keysym==runkeysym[0] ||
00601         keycode==runkey[1] || keysym==runkeysym[1]) {
00602                 cpl.run_on=1;
00603 #ifdef GDK_XUTIL
00604                 gtk_label_set (GTK_LABEL(run_label),"Run");
00605 #else
00606                 draw_message_window(0);
00607 #endif
00608                 return;
00609         }
00610 
00611     if (cpl.run_on) present_flags |= KEYF_RUN;
00612     if (cpl.fire_on) present_flags |= KEYF_FIRE;
00613     if (present_flags ==0) present_flags = KEYF_NORMAL;
00614 
00615     keyentry = keys[keycode];
00616     while (keyentry!=NULL) {
00617         if ((keyentry->keysym!=NoSymbol && keyentry->keysym!=keysym) ||
00618             (!(keyentry->flags & present_flags))) {
00619                 keyentry=keyentry->next;
00620                 continue;
00621             }
00622         first_match = keyentry;
00623         /* Try to find a prefect match */
00624         if ((keyentry->flags & KEYF_MODIFIERS)!= present_flags) {
00625                 keyentry=keyentry->next;
00626                 continue;
00627         }
00628         else break;
00629     }
00630     if (first_match!=NULL) {
00631         char buf[MAX_BUF];
00632 
00633         if (first_match->flags & KEYF_EDIT) {
00634             strcpy(cpl.input_text, first_match->command);
00635             cpl.input_state = Command_Mode;
00636 #ifdef GDK_XUTIL
00637             snprintf(buf, sizeof(buf), "%s", cpl.input_text);
00638             gtk_entry_set_text(GTK_ENTRY(entrytext),buf);
00639             gtk_widget_grab_focus (GTK_WIDGET(entrytext));
00640 #else
00641             snprintf(buf, sizeof(buf), ">%s", cpl.input_text);
00642             draw_prompt(buf);
00643 #endif
00644             return;
00645         }
00646 
00647         if (first_match->direction>=0) {
00648             if (cpl.fire_on) {
00649                 snprintf(buf, sizeof(buf), "fire %s", first_match->command);
00650                 fire_dir(first_match->direction);
00651             }
00652             else if (cpl.run_on) {
00653                 run_dir(first_match->direction);
00654                 snprintf(buf, sizeof(buf), "run %s", first_match->command);
00655             }
00656             else if (!repeated) {
00657                 strcpy(buf,first_match->command);
00658                 extended_command(first_match->command);
00659             }
00660             else
00661                 snprintf(buf, sizeof(buf), "move %s (ignored)", first_match->command);
00662             if (use_config[CONFIG_ECHO]) draw_info(buf,NDI_BLACK);
00663         }
00664         else {
00665             if (use_config[CONFIG_ECHO]) draw_info(first_match->command,NDI_BLACK);
00666             extended_command(first_match->command);
00667         }
00668         return;
00669     }
00670     if (key>='0' && key<='9') {
00671         cpl.count = cpl.count*10 + (key-'0');
00672         if (cpl.count>100000) cpl.count%=100000;
00673 #ifdef GDK_XUTIL
00674         gtk_spin_button_set_value (GTK_SPIN_BUTTON(counttext), (float) cpl.count );
00675 #endif
00676         return;
00677     }
00678     snprintf(buf, sizeof(buf), "Key unused (%s%s%s)",
00679           (cpl.fire_on? "Fire&": ""),
00680           (cpl.run_on ? "Run&" : ""),
00681           keysym==NoSymbol? "unknown": XKeysymToString(keysym));
00682     draw_info(buf,NDI_BLACK);
00683     cpl.count=0;
00684 }
00685 
00686 
00687 /* This returns a character string desribing the key. */
00688 /* If save_mode is true, it means that the format used for saving
00689  * the information is used, instead of the usual format for displaying
00690  * the information in a friendly manner.
00691  */
00692 static char * get_key_info(Key_Entry *key, KeyCode kc, int save_mode)
00693 {
00694     /* bind buf is the maximum space allowed for a
00695      * binded command. We will add additional datas to
00696      * it so we increase by MAX_BUF*/
00697     static char buf[MAX_BUF+sizeof(bind_buf)];
00698     char buff[MAX_BUF];
00699     int bi=0;
00700 
00701     if ((key->flags & KEYF_MODIFIERS) == KEYF_MODIFIERS)
00702         buff[bi++] ='A';
00703     else {
00704         if (key->flags & KEYF_NORMAL)
00705           buff[bi++] ='N';
00706         if (key->flags & KEYF_FIRE)
00707           buff[bi++] ='F';
00708         if (key->flags & KEYF_RUN)
00709           buff[bi++] ='R';
00710     }
00711     if (key->flags & KEYF_EDIT)
00712         buff[bi++] ='E';
00713     if (key->flags & KEYF_STANDARD)
00714         buff[bi++] ='S';
00715 
00716     buff[bi]='\0';
00717     if (save_mode) {
00718         if(key->keysym == NoSymbol) {
00719           snprintf(buf, sizeof(buf), "(null) %i %s %s",
00720                 kc,buff, key->command);
00721         }
00722         else {
00723           snprintf(buf, sizeof(buf), "%s %i %s %s",
00724                     XKeysymToString(key->keysym), kc,
00725                     buff, key->command);
00726         }
00727     }
00728     else {
00729         if(key->keysym == NoSymbol) {
00730           snprintf(buf, sizeof(buf), "key (null) (%i) %s %s",
00731                 kc,buff, key->command);
00732         }
00733         else {
00734           snprintf(buf, sizeof(buf), "key %s (%i) %s %s",
00735                     XKeysymToString(key->keysym), kc,
00736                     buff, key->command);
00737         }
00738     }
00739     return buf;
00740 }
00741 
00742 /* Shows all the keybindings.  allbindings me we also show the standard
00743  * (default) keybindings.
00744  */
00745 
00746 static void show_keys(int allbindings)
00747 {
00748   int i, count=1;
00749   Key_Entry *key;
00750   char buf[MAX_BUF];
00751 
00752   snprintf(buf, sizeof(buf), "Commandkey %s (%d)",
00753           commandkeysym==NoSymbol?"unknown":XKeysymToString(commandkeysym),
00754           commandkey);
00755   draw_info(buf,NDI_BLACK);
00756   snprintf(buf, sizeof(buf), "Firekeys 1: %s (%d), 2: %s (%d)",
00757           firekeysym[0]==NoSymbol?"unknown":XKeysymToString(firekeysym[0]), firekey[0],
00758           firekeysym[1]==NoSymbol?"unknown":XKeysymToString(firekeysym[1]), firekey[1]);
00759   draw_info(buf,NDI_BLACK);
00760   snprintf(buf, sizeof(buf), "Runkeys 1: %s (%d), 2: %s (%d)",
00761           runkeysym[0]==NoSymbol?"unknown":XKeysymToString(runkeysym[0]), runkey[0],
00762           runkeysym[1]==NoSymbol?"unknown":XKeysymToString(runkeysym[1]), runkey[1]);
00763   draw_info(buf,NDI_BLACK);
00764 
00765   snprintf(buf, sizeof(buf), "Command Completion Key %s (%d)",
00766           completekeysym==NoSymbol?"unknown":XKeysymToString(completekeysym),
00767           completekey);
00768   draw_info(buf,NDI_BLACK);
00769 
00770   snprintf(buf, sizeof(buf), "Next Command in History Key %s (%d)",
00771           nextkeysym==NoSymbol?"unknown":XKeysymToString(nextkeysym),
00772           nextkey);
00773   draw_info(buf,NDI_BLACK);
00774 
00775   snprintf(buf, sizeof(buf), "Previous Command in History Key %s (%d)",
00776           prevkeysym==NoSymbol?"unknown":XKeysymToString(prevkeysym),
00777           prevkey);
00778   draw_info(buf,NDI_BLACK);
00779 
00780 
00781   /* Perhaps we should start at 8, so that we only show 'active'
00782    * keybindings?
00783    */
00784   for (i=0; i<=MAX_KEYCODE; i++) {
00785     for (key=keys[i]; key!=NULL; key =key->next) {
00786         if (key->flags & KEYF_STANDARD && !allbindings) continue;
00787 
00788         snprintf(buf, sizeof(buf), "%3d %s", count, get_key_info(key, i, 0));
00789         draw_info(buf,NDI_BLACK);
00790         count++;
00791     }
00792   }
00793 }
00794 
00795 
00796 
00797 
00798 void bind_key(const char *params)
00799 {
00800   char buf[MAX_BUF];
00801 
00802   if (!params) {
00803     draw_info("Usage: bind [-nfre] {<commandline>/commandkey/firekey{1/2}/runkey{1/2}/",NDI_BLACK);
00804     draw_info("           completekey/nextkey/prevkey}",NDI_BLACK);
00805     return;
00806   }
00807 
00808   /* Skip over any spaces we may have */
00809   while (*params==' ') params++;
00810 
00811   if (!strcmp(params, "commandkey")) {
00812     bind_keycode = &commandkey;
00813     bind_keysym = &commandkeysym;
00814     draw_info("Push key to bind new commandkey.",NDI_BLACK);
00815     cpl.input_state = Configure_Keys;
00816     return;
00817   }
00818   if (!strcmp(params, "firekey1")) {
00819     bind_keycode = &firekey[0];
00820     bind_keysym = & firekeysym[0];
00821     draw_info("Push key to bind new firekey 1.",NDI_BLACK);
00822     cpl.input_state = Configure_Keys;
00823     return;
00824   }
00825   if (!strcmp(params, "firekey2")) {
00826     bind_keycode = &firekey[1];
00827     bind_keysym = & firekeysym[1];
00828     draw_info("Push key to bind new firekey 2.",NDI_BLACK);
00829     cpl.input_state = Configure_Keys;
00830     return;
00831   }
00832   if (!strcmp(params, "runkey1")) {
00833     bind_keycode = &runkey[0];
00834     bind_keysym = &runkeysym[0];
00835     draw_info("Push key to bind new runkey 1.",NDI_BLACK);
00836     cpl.input_state = Configure_Keys;
00837     return;
00838   }
00839   if (!strcmp(params, "runkey2")) {
00840     bind_keycode = &runkey[1];
00841     bind_keysym = &runkeysym[1];
00842     draw_info("Push key to bind new runkey 2.",NDI_BLACK);
00843     cpl.input_state = Configure_Keys;
00844     return;
00845   }
00846 
00847   if (!strcmp(params, "completekey")) {
00848     bind_keycode = &completekey;
00849     bind_keysym = &completekeysym;
00850     draw_info("Push key to bind new command completeion key",NDI_BLACK);
00851     cpl.input_state = Configure_Keys;
00852     return;
00853   }
00854 
00855   if (!strcmp(params, "prevkey")) {
00856     bind_keycode = &prevkey;
00857     bind_keysym = &prevkeysym;
00858     draw_info("Push key to bind new previous command in history key.",NDI_BLACK);
00859     cpl.input_state = Configure_Keys;
00860     return;
00861   }
00862 
00863   if (!strcmp(params, "nextkey")) {
00864     bind_keycode = &nextkey;
00865     bind_keysym = &nextkeysym;
00866     draw_info("Push key to bind new next command in history key.",NDI_BLACK);
00867     cpl.input_state = Configure_Keys;
00868     return;
00869   }
00870 
00871 
00872   if (params[0] != '-')
00873     bind_flags =KEYF_MODIFIERS;
00874   else {
00875     bind_flags =0;
00876     bind_keysym=NULL;
00877     bind_keycode=NULL;
00878     for (params++; *params != ' '; params++)
00879       switch (*params) {
00880       case 'n':
00881         bind_flags |= KEYF_NORMAL;
00882         break;
00883       case 'f':
00884         bind_flags |= KEYF_FIRE;
00885         break;
00886       case 'r':
00887         bind_flags |= KEYF_RUN;
00888         break;
00889       case 'e':
00890         bind_flags |= KEYF_EDIT;
00891         break;
00892       case '\0':
00893         draw_info("Try unbind to remove bindings..",NDI_BLACK);
00894         return;
00895       default:
00896         snprintf(buf, sizeof(buf), "Unknown flag to bind: '%c'", *params);
00897         draw_info(buf,NDI_BLACK);
00898         return;
00899       }
00900     params++;
00901   }
00902 
00903   if (!(bind_flags & KEYF_MODIFIERS))
00904     bind_flags |= KEYF_MODIFIERS;
00905 
00906   if (!params[0]) {
00907     draw_info("Try unbind to remove bindings..",NDI_BLACK);
00908     return;
00909   }
00910 
00911   strncpy(bind_buf, params, sizeof(bind_buf)-1);
00912   bind_buf[sizeof(bind_buf)-1]=0;
00913   if (strlen(params) >= sizeof(bind_buf)) {
00914     draw_info("Keybinding too long! Truncated:",NDI_RED);
00915     draw_info(bind_buf,NDI_RED);
00916   }
00917 
00918   snprintf(buf, sizeof(buf), "Push key to bind '%s'.", bind_buf);
00919   draw_info(buf,NDI_BLACK);
00920   bind_keycode=NULL;
00921   cpl.input_state = Configure_Keys;
00922   return;
00923 }
00924 
00925 
00926 /* This is a recursive function that saves all the entries for a particular
00927  * entry.  We save the first element first, and then go through
00928  * and save the rest of the elements.  In this way, the ordering of the key
00929  * entries in the
00930  * file remains the same.
00931  */
00932 
00933 static void save_individual_key(FILE *fp, Key_Entry *key, KeyCode kc)
00934 {
00935     if (key==NULL) return;
00936     fprintf(fp, "%s\n", get_key_info(key, kc, 1));
00937     save_individual_key(fp, key->next, kc);
00938 }
00939 
00940 static void save_keys(void)
00941 {
00942     char buf[MAX_BUF], buf2[MAX_BUF];
00943     int i;
00944     FILE *fp;
00945 
00946     sprintf(buf,"%s/.crossfire/keys", getenv("HOME"));
00947     if (make_path_to_file(buf)==-1) {
00948         LOG(LOG_WARNING,"x11::save_keys","Could not create %s", buf);
00949         return;
00950     }
00951     if ((fp=fopen(buf,"w"))==NULL) {
00952         snprintf(buf2, sizeof(buf2), "Could not open %s, key bindings not saved\n", buf);
00953         draw_info(buf2,NDI_BLACK);
00954         return;
00955     }
00956     if (commandkeysym != XK_apostrophe && commandkeysym != NoSymbol) {
00957         fprintf(fp, "! commandkey %s %d\n",
00958                 XKeysymToString(commandkeysym), commandkey);
00959     }
00960     if (firekeysym[0] != XK_Shift_L && firekeysym[0] != NoSymbol) {
00961         fprintf(fp, "! firekey0 %s %d\n",
00962                 XKeysymToString(firekeysym[0]), firekey[0]);
00963     }
00964     if (firekeysym[1] != XK_Shift_R && firekeysym[1] != NoSymbol) {
00965         fprintf(fp, "! firekey1 %s %d\n",
00966                 XKeysymToString(firekeysym[1]), firekey[1]);
00967     }
00968     if (runkeysym[0] != XK_Control_L && runkeysym[0] != NoSymbol) {
00969         fprintf(fp, "! runkey0 %s %d\n",
00970                 XKeysymToString(runkeysym[0]), runkey[0]);
00971     }
00972     if (runkeysym[1] != XK_Control_R && runkeysym[1] != NoSymbol) {
00973         fprintf(fp, "! runkey1 %s %d\n",
00974                 XKeysymToString(runkeysym[1]), runkey[1]);
00975     }
00976     if (completekeysym != XK_Tab && completekeysym != NoSymbol) {
00977         fprintf(fp, "! completekey %s %d\n",
00978                 XKeysymToString(completekeysym), completekey);
00979     }
00980     /* No defaults for these, so if it is set to anything, assume its valid */
00981     if (nextkeysym != NoSymbol) {
00982         fprintf(fp, "! nextkey %s %d\n",
00983                 XKeysymToString(nextkeysym), nextkey);
00984     }
00985     if (prevkeysym != NoSymbol) {
00986         fprintf(fp, "! prevkey %s %d\n",
00987                 XKeysymToString(prevkeysym), prevkey);
00988     }
00989 
00990     for (i=0; i<=MAX_KEYCODE; i++) {
00991         save_individual_key(fp, keys[i], i);
00992     }
00993     fclose(fp);
00994     /* Should probably check return value on all writes to be sure, but... */
00995     draw_info("key bindings successfully saved.",NDI_BLACK);
00996 }
00997 
00998 void configure_keys(KeyCode k, KeySym keysym)
00999 {
01000   char buf[MAX_BUF];
01001 
01002   if (bind_keycode==NULL) {
01003     if(k == firekey[0] || k == firekey[1]) {
01004         cpl.fire_on =1;
01005         draw_message_window(0);
01006         return;
01007     }
01008     if(k == runkey[0] || k == runkey[1]) {
01009         cpl.run_on =1;
01010         draw_message_window(0);
01011         return;
01012     }
01013   }
01014   cpl.input_state = Playing;
01015   /* Try to be clever - take into account shift/control keys being
01016    * held down when binding keys - in this way, player does not have to use
01017    * -f and -r flags to bind for many simple binds.
01018    */
01019 
01020   if ((cpl.fire_on || cpl.run_on) && (bind_flags & KEYF_MODIFIERS)==KEYF_MODIFIERS) {
01021         bind_flags &= ~KEYF_MODIFIERS;
01022         if (cpl.fire_on) bind_flags |= KEYF_FIRE;
01023         if (cpl.run_on) bind_flags |= KEYF_RUN;
01024   }
01025 
01026   if (bind_keycode!=NULL) {
01027         *bind_keycode = k;
01028         *bind_keysym=keysym;
01029   }
01030   else {
01031         insert_key(keysym, k, bind_flags, bind_buf);
01032   }
01033 
01034   snprintf(buf, sizeof(buf), "Binded to key '%s' (%i)",
01035           keysym==NoSymbol?"unknown":XKeysymToString(keysym), (int)k);
01036   draw_info(buf,NDI_BLACK);
01037   cpl.fire_on=0;
01038   cpl.run_on=0;
01039   draw_message_window(0);
01040 
01041   /* Do this each time a new key is bound.  This way, we are never actually
01042    * storing any information that needs to be saved when the connection
01043    * dies or the player quits.
01044    */
01045   save_keys();
01046   return;
01047 }
01048 
01049 static void unbind_usage(void)
01050 {
01051     draw_info("Usage: unbind <entry_number> or",NDI_BLACK);
01052     draw_info("Usage: unbind [-a] [-g] to show existing bindings", NDI_BLACK);
01053     draw_info("    -a shows all (global) bindings", NDI_BLACK);
01054     draw_info("    -g unbinds a global binding", NDI_BLACK);
01055 }
01056 
01057 void unbind_key(const char *params)
01058 {
01059     int count=0, keyentry, onkey,global=0;
01060     Key_Entry *key, *tmp;
01061     char buf[MAX_BUF];
01062 
01063     if (params==NULL || params[0]=='\0') {
01064         show_keys(0);
01065         return;
01066     }
01067 
01068     /* Skip over any spaces we may have */
01069     while (*params==' ') params++;
01070 
01071     if (!strcmp(params,"-a")) {
01072         show_keys(1);
01073         return;
01074     }
01075     if (!strncmp(params,"-g",2)) {
01076         global=1;
01077         if (!(params=strchr(params,' ')))  {
01078             unbind_usage();
01079             return;
01080         }
01081     }
01082     if ((keyentry=atoi(params))==0) {
01083         unbind_usage();
01084         return;
01085     }
01086 
01087     for (onkey=0; onkey<=MAX_KEYCODE; onkey++) {
01088         for (key=keys[onkey]; key; key =key->next) {
01089             if (global || !(key->flags&KEYF_STANDARD)) count++;
01090             /* We found the key we want to unbind */
01091             if (keyentry==count) {
01092 
01093                 /* If it is the first entry, it is easy */
01094                 if (key == keys[onkey]) {
01095                     keys[onkey] = key->next;
01096                     goto unbinded;
01097                 }
01098                 /* Otherwise, we need to figure out where in the link list
01099                  * the entry is.
01100                  */
01101                 for (tmp=keys[onkey]; tmp->next!=NULL; tmp=tmp->next) {
01102                     if (tmp->next == key) {
01103                         tmp->next =key->next;
01104                         goto unbinded;
01105                     }
01106                 }
01107                 LOG(LOG_ERROR,"x11::unbind_key","found number entry, but could not find actual key");
01108             }
01109         }
01110     }
01111     /* Makes things look better to draw the blank line */
01112     draw_info("",NDI_BLACK);
01113     draw_info("No such entry. Try 'unbind' with no options to find entry.",NDI_BLACK);
01114     return;
01115 
01116     /*
01117      * Found. Now remove it.
01118      */
01119 
01120 unbinded:
01121 
01122     snprintf(buf, sizeof(buf), "Removed binding: %3d %s", count, get_key_info(key, onkey, 0));
01123 
01124 
01125     draw_info(buf,NDI_BLACK);
01126     free(key->command);
01127     free(key);
01128     save_keys();
01129 }
01130 
01131 
01132 /* try to find a face in our private cache.  We return the face
01133  * number if we find one, -1 for no face match
01134  */
01135 int  find_face_in_private_cache(char *face, int checksum)
01136 {
01137     int i;
01138 
01139     for (i=1; i<=last_face_num; i++)
01140         if (!strcmp(face, private_cache[i].name)) {
01141             return i;
01142         }
01143     return -1;
01144 }
01145 
01146 
01147 void image_update_download_status(int start, int end, int total)
01148 {
01149     char buf[MAX_BUF];
01150 
01151     snprintf(buf, sizeof(buf), "Downloaded %d of %d images", start, total);
01152 
01153     draw_info(buf,NDI_BLUE);
01154 }
01155 
01156 /* Start of map handling code.
01157  * For the most part, this actually is not window system specific,
01158  * but certainly how the client wants to store this may vary.
01159  *
01160  * At least in the gtk and x11 clients, 95+% of this code
01161  * is the same - the only think I think is different is
01162  * that the gtk will call sdl_scroll.  This should
01163  * probably be moved into the common area.
01164  */
01165 
01166 #define MAXFACES 5
01167 #define MAXPIXMAPNUM 10000
01168 
01169 
01170 /*
01171  * Added for fog of war. Current size of the map structure in memory.
01172  * We assume a rectangular map so this is the length of one side.
01173  * command.c needs to know about this so not static
01174  * FIX ME: Don't assume rectangle
01175  */
01176 
01177 PlayerPosition pl_pos;
01178 
01179 
01185 void reset_map(void)
01186 {
01187 }
01188 
01189 /* x11 client doesn't do smoothing, so don't need to do anything with this */
01190 void addsmooth(uint16 face, uint16 smooth_face)
01191 {
01192 }
01193 
01194 /* X11 client doesn't care about this */
01195 void client_tick(uint32 tick)
01196 {
01197 }
01198 
01202 void client_pickup(uint32 pickup)
01203 {
01204 }