xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

ddxLoad.c (15314B)


      1 /************************************************************
      2 Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
      3 
      4 Permission to use, copy, modify, and distribute this
      5 software and its documentation for any purpose and without
      6 fee is hereby granted, provided that the above copyright
      7 notice appear in all copies and that both that copyright
      8 notice and this permission notice appear in supporting
      9 documentation, and that the name of Silicon Graphics not be
     10 used in advertising or publicity pertaining to distribution
     11 of the software without specific prior written permission.
     12 Silicon Graphics makes no representation about the suitability
     13 of this software for any purpose. It is provided "as is"
     14 without any express or implied warranty.
     15 
     16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
     17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
     19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
     20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
     22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
     23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
     24 
     25 ********************************************************/
     26 
     27 #ifdef HAVE_DIX_CONFIG_H
     28 #include <dix-config.h>
     29 #endif
     30 
     31 #include <xkb-config.h>
     32 
     33 #include <stdio.h>
     34 #include <ctype.h>
     35 #include <X11/X.h>
     36 #include <X11/Xos.h>
     37 #include <X11/Xproto.h>
     38 #include <X11/keysym.h>
     39 #include <X11/extensions/XKM.h>
     40 #include "inputstr.h"
     41 #include "scrnintstr.h"
     42 #include "windowstr.h"
     43 #define	XKBSRV_NEED_FILE_FUNCS
     44 #include <xkbsrv.h>
     45 #include <X11/extensions/XI.h>
     46 #include "xkb.h"
     47 
     48 #define	PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports:\""
     49 #define	ERROR_PREFIX	"\"> \""
     50 #define	POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X server\""
     51 #define	POST_ERROR_MSG2 "\"End of messages from xkbcomp\""
     52 
     53 #if defined(WIN32)
     54 #define PATHSEPARATOR "\\"
     55 #else
     56 #define PATHSEPARATOR "/"
     57 #endif
     58 
     59 static unsigned
     60 LoadXKM(unsigned want, unsigned need, const char *keymap, XkbDescPtr *xkbRtrn);
     61 
     62 static void
     63 OutputDirectory(char *outdir, size_t size)
     64 {
     65     const char *directory = NULL;
     66     const char *pathsep = "";
     67     int r = -1;
     68 
     69 #ifndef WIN32
     70     /* Can we write an xkm and then open it too? */
     71     if (access(XKM_OUTPUT_DIR, W_OK | X_OK) == 0) {
     72         directory = XKM_OUTPUT_DIR;
     73         if (XKM_OUTPUT_DIR[strlen(XKM_OUTPUT_DIR) - 1] != '/')
     74             pathsep = "/";
     75     }
     76 #else
     77     directory = Win32TempDir();
     78     pathsep = "\\";
     79 #endif
     80 
     81     if (directory)
     82         r = snprintf(outdir, size, "%s%s", directory, pathsep);
     83     if (r < 0 || r >= size) {
     84         assert(strlen("/tmp/") < size);
     85         strcpy(outdir, "/tmp/");
     86     }
     87 }
     88 
     89 /**
     90  * Callback invoked by XkbRunXkbComp. Write to out to talk to xkbcomp.
     91  */
     92 typedef void (*xkbcomp_buffer_callback)(FILE *out, void *userdata);
     93 
     94 /**
     95  * Start xkbcomp, let the callback write into xkbcomp's stdin. When done,
     96  * return a strdup'd copy of the file name we've written to.
     97  */
     98 static char *
     99 RunXkbComp(xkbcomp_buffer_callback callback, void *userdata)
    100 {
    101     FILE *out;
    102     char *buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX];
    103 
    104     const char *emptystring = "";
    105     char *xkbbasedirflag = NULL;
    106     const char *xkbbindir = emptystring;
    107     const char *xkbbindirsep = emptystring;
    108 
    109 #ifdef WIN32
    110     /* WIN32 has no popen. The input must be stored in a file which is
    111        used as input for xkbcomp. xkbcomp does not read from stdin. */
    112     char tmpname[PATH_MAX];
    113     const char *xkmfile = tmpname;
    114 #else
    115     const char *xkmfile = "-";
    116 #endif
    117 
    118     snprintf(keymap, sizeof(keymap), "server-%s", display);
    119 
    120     OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
    121 
    122 #ifdef WIN32
    123     strcpy(tmpname, Win32TempDir());
    124     strcat(tmpname, "\\xkb_XXXXXX");
    125     (void) mktemp(tmpname);
    126 #endif
    127 
    128     if (XkbBaseDirectory != NULL) {
    129         if (asprintf(&xkbbasedirflag, "\"-R%s\"", XkbBaseDirectory) == -1)
    130             xkbbasedirflag = NULL;
    131     }
    132 
    133     if (XkbBinDirectory != NULL) {
    134         int ld = strlen(XkbBinDirectory);
    135         int lps = strlen(PATHSEPARATOR);
    136 
    137         xkbbindir = XkbBinDirectory;
    138 
    139         if ((ld >= lps) && (strcmp(xkbbindir + ld - lps, PATHSEPARATOR) != 0)) {
    140             xkbbindirsep = PATHSEPARATOR;
    141         }
    142     }
    143 
    144     if (asprintf(&buf,
    145                  "\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" "
    146                  "-em1 %s -emp %s -eml %s \"%s%s.xkm\"",
    147                  xkbbindir, xkbbindirsep,
    148                  ((xkbDebugFlags < 2) ? 1 :
    149                   ((xkbDebugFlags > 10) ? 10 : (int) xkbDebugFlags)),
    150                  xkbbasedirflag ? xkbbasedirflag : "", xkmfile,
    151                  PRE_ERROR_MSG, ERROR_PREFIX, POST_ERROR_MSG1,
    152                  xkm_output_dir, keymap) == -1)
    153         buf = NULL;
    154 
    155     free(xkbbasedirflag);
    156 
    157     if (!buf) {
    158         LogMessage(X_ERROR,
    159                    "XKB: Could not invoke xkbcomp: not enough memory\n");
    160         return NULL;
    161     }
    162 
    163 #ifndef WIN32
    164     out = Popen(buf, "w");
    165 #else
    166     out = fopen(tmpname, "w");
    167 #endif
    168 
    169     if (out != NULL) {
    170         /* Now write to xkbcomp */
    171         (*callback)(out, userdata);
    172 
    173 #ifndef WIN32
    174         if (Pclose(out) == 0)
    175 #else
    176         if (fclose(out) == 0 && System(buf) >= 0)
    177 #endif
    178         {
    179             if (xkbDebugFlags)
    180                 DebugF("[xkb] xkb executes: %s\n", buf);
    181             free(buf);
    182 #ifdef WIN32
    183             unlink(tmpname);
    184 #endif
    185             return xnfstrdup(keymap);
    186         }
    187         else {
    188             LogMessage(X_ERROR, "Error compiling keymap (%s) executing '%s'\n",
    189                        keymap, buf);
    190         }
    191 #ifdef WIN32
    192         /* remove the temporary file */
    193         unlink(tmpname);
    194 #endif
    195     }
    196     else {
    197 #ifndef WIN32
    198         LogMessage(X_ERROR, "XKB: Could not invoke xkbcomp\n");
    199 #else
    200         LogMessage(X_ERROR, "Could not open file %s\n", tmpname);
    201 #endif
    202     }
    203     free(buf);
    204     return NULL;
    205 }
    206 
    207 typedef struct {
    208     XkbDescPtr xkb;
    209     XkbComponentNamesPtr names;
    210     unsigned int want;
    211     unsigned int need;
    212 } XkbKeymapNamesCtx;
    213 
    214 static void
    215 xkb_write_keymap_for_names_cb(FILE *out, void *userdata)
    216 {
    217     XkbKeymapNamesCtx *ctx = userdata;
    218 #ifdef DEBUG
    219     if (xkbDebugFlags) {
    220         ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
    221         XkbWriteXKBKeymapForNames(stderr, ctx->names, ctx->xkb, ctx->want, ctx->need);
    222     }
    223 #endif
    224     XkbWriteXKBKeymapForNames(out, ctx->names, ctx->xkb, ctx->want, ctx->need);
    225 }
    226 
    227 static Bool
    228 XkbDDXCompileKeymapByNames(XkbDescPtr xkb,
    229                            XkbComponentNamesPtr names,
    230                            unsigned want,
    231                            unsigned need, char *nameRtrn, int nameRtrnLen)
    232 {
    233     char *keymap;
    234     Bool rc = FALSE;
    235     XkbKeymapNamesCtx ctx = {
    236         .xkb = xkb,
    237         .names = names,
    238         .want = want,
    239         .need = need
    240     };
    241 
    242     keymap = RunXkbComp(xkb_write_keymap_for_names_cb, &ctx);
    243 
    244     if (keymap) {
    245         if(nameRtrn)
    246             strlcpy(nameRtrn, keymap, nameRtrnLen);
    247 
    248         free(keymap);
    249         rc = TRUE;
    250     } else if (nameRtrn)
    251         *nameRtrn = '\0';
    252 
    253     return rc;
    254 }
    255 
    256 typedef struct {
    257     const char *keymap;
    258     size_t len;
    259 } XkbKeymapString;
    260 
    261 static void
    262 xkb_write_keymap_string_cb(FILE *out, void *userdata)
    263 {
    264     XkbKeymapString *s = userdata;
    265     fwrite(s->keymap, s->len, 1, out);
    266 }
    267 
    268 static unsigned int
    269 XkbDDXLoadKeymapFromString(DeviceIntPtr keybd,
    270                           const char *keymap, int keymap_length,
    271                           unsigned int want,
    272                           unsigned int need,
    273                           XkbDescPtr *xkbRtrn)
    274 {
    275     unsigned int have;
    276     char *map_name;
    277     XkbKeymapString map = {
    278         .keymap = keymap,
    279         .len = keymap_length
    280     };
    281 
    282     *xkbRtrn = NULL;
    283 
    284     map_name = RunXkbComp(xkb_write_keymap_string_cb, &map);
    285     if (!map_name) {
    286         LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
    287         return 0;
    288     }
    289 
    290     have = LoadXKM(want, need, map_name, xkbRtrn);
    291     free(map_name);
    292 
    293     return have;
    294 }
    295 
    296 static FILE *
    297 XkbDDXOpenConfigFile(const char *mapName, char *fileNameRtrn, int fileNameRtrnLen)
    298 {
    299     char buf[PATH_MAX], xkm_output_dir[PATH_MAX];
    300     FILE *file;
    301 
    302     buf[0] = '\0';
    303     if (mapName != NULL) {
    304         OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
    305         if ((XkbBaseDirectory != NULL) && (xkm_output_dir[0] != '/')
    306 #ifdef WIN32
    307             && (!isalpha(xkm_output_dir[0]) || xkm_output_dir[1] != ':')
    308 #endif
    309             ) {
    310             if (snprintf(buf, PATH_MAX, "%s/%s%s.xkm", XkbBaseDirectory,
    311                          xkm_output_dir, mapName) >= PATH_MAX)
    312                 buf[0] = '\0';
    313         }
    314         else {
    315             if (snprintf(buf, PATH_MAX, "%s%s.xkm", xkm_output_dir, mapName)
    316                 >= PATH_MAX)
    317                 buf[0] = '\0';
    318         }
    319         if (buf[0] != '\0')
    320             file = fopen(buf, "rb");
    321         else
    322             file = NULL;
    323     }
    324     else
    325         file = NULL;
    326     if ((fileNameRtrn != NULL) && (fileNameRtrnLen > 0)) {
    327         strlcpy(fileNameRtrn, buf, fileNameRtrnLen);
    328     }
    329     return file;
    330 }
    331 
    332 static unsigned
    333 LoadXKM(unsigned want, unsigned need, const char *keymap, XkbDescPtr *xkbRtrn)
    334 {
    335     FILE *file;
    336     char fileName[PATH_MAX];
    337     unsigned missing;
    338 
    339     file = XkbDDXOpenConfigFile(keymap, fileName, PATH_MAX);
    340     if (file == NULL) {
    341         LogMessage(X_ERROR, "Couldn't open compiled keymap file %s\n",
    342                    fileName);
    343         return 0;
    344     }
    345     missing = XkmReadFile(file, need, want, xkbRtrn);
    346     if (*xkbRtrn == NULL) {
    347         LogMessage(X_ERROR, "Error loading keymap %s\n", fileName);
    348         fclose(file);
    349         (void) unlink(fileName);
    350         return 0;
    351     }
    352     else {
    353         DebugF("Loaded XKB keymap %s, defined=0x%x\n", fileName,
    354                (*xkbRtrn)->defined);
    355     }
    356     fclose(file);
    357     (void) unlink(fileName);
    358     return (need | want) & (~missing);
    359 }
    360 
    361 unsigned
    362 XkbDDXLoadKeymapByNames(DeviceIntPtr keybd,
    363                         XkbComponentNamesPtr names,
    364                         unsigned want,
    365                         unsigned need,
    366                         XkbDescPtr *xkbRtrn, char *nameRtrn, int nameRtrnLen)
    367 {
    368     XkbDescPtr xkb;
    369 
    370     *xkbRtrn = NULL;
    371     if ((keybd == NULL) || (keybd->key == NULL) ||
    372         (keybd->key->xkbInfo == NULL))
    373         xkb = NULL;
    374     else
    375         xkb = keybd->key->xkbInfo->desc;
    376     if ((names->keycodes == NULL) && (names->types == NULL) &&
    377         (names->compat == NULL) && (names->symbols == NULL) &&
    378         (names->geometry == NULL)) {
    379         LogMessage(X_ERROR, "XKB: No components provided for device %s\n",
    380                    keybd->name ? keybd->name : "(unnamed keyboard)");
    381         return 0;
    382     }
    383     else if (!XkbDDXCompileKeymapByNames(xkb, names, want, need,
    384                                          nameRtrn, nameRtrnLen)) {
    385         LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
    386         return 0;
    387     }
    388 
    389     return LoadXKM(want, need, nameRtrn, xkbRtrn);
    390 }
    391 
    392 Bool
    393 XkbDDXNamesFromRules(DeviceIntPtr keybd,
    394                      const char *rules_name,
    395                      XkbRF_VarDefsPtr defs, XkbComponentNamesPtr names)
    396 {
    397     char buf[PATH_MAX];
    398     FILE *file;
    399     Bool complete;
    400     XkbRF_RulesPtr rules;
    401 
    402     if (!rules_name)
    403         return FALSE;
    404 
    405     if (snprintf(buf, PATH_MAX, "%s/rules/%s", XkbBaseDirectory, rules_name)
    406         >= PATH_MAX) {
    407         LogMessage(X_ERROR, "XKB: Rules name is too long\n");
    408         return FALSE;
    409     }
    410 
    411     file = fopen(buf, "r");
    412     if (!file) {
    413         LogMessage(X_ERROR, "XKB: Couldn't open rules file %s\n", buf);
    414         return FALSE;
    415     }
    416 
    417     rules = XkbRF_Create();
    418     if (!rules) {
    419         LogMessage(X_ERROR, "XKB: Couldn't create rules struct\n");
    420         fclose(file);
    421         return FALSE;
    422     }
    423 
    424     if (!XkbRF_LoadRules(file, rules)) {
    425         LogMessage(X_ERROR, "XKB: Couldn't parse rules file %s\n", rules_name);
    426         fclose(file);
    427         XkbRF_Free(rules, TRUE);
    428         return FALSE;
    429     }
    430 
    431     memset(names, 0, sizeof(*names));
    432     complete = XkbRF_GetComponents(rules, defs, names);
    433     fclose(file);
    434     XkbRF_Free(rules, TRUE);
    435 
    436     if (!complete)
    437         LogMessage(X_ERROR, "XKB: Rules returned no components\n");
    438 
    439     return complete;
    440 }
    441 
    442 static Bool
    443 XkbRMLVOtoKcCGST(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
    444                  XkbComponentNamesPtr kccgst)
    445 {
    446     XkbRF_VarDefsRec mlvo;
    447 
    448     mlvo.model = rmlvo->model;
    449     mlvo.layout = rmlvo->layout;
    450     mlvo.variant = rmlvo->variant;
    451     mlvo.options = rmlvo->options;
    452 
    453     return XkbDDXNamesFromRules(dev, rmlvo->rules, &mlvo, kccgst);
    454 }
    455 
    456 /**
    457  * Compile the given RMLVO keymap and return it. Returns the XkbDescPtr on
    458  * success or NULL on failure. If the components compiled are not a superset
    459  * or equal to need, the compilation is treated as failure.
    460  */
    461 static XkbDescPtr
    462 XkbCompileKeymapForDevice(DeviceIntPtr dev, XkbRMLVOSet * rmlvo, int need)
    463 {
    464     XkbDescPtr xkb = NULL;
    465     unsigned int provided;
    466     XkbComponentNamesRec kccgst = { 0 };
    467     char name[PATH_MAX];
    468 
    469     if (XkbRMLVOtoKcCGST(dev, rmlvo, &kccgst)) {
    470         provided =
    471             XkbDDXLoadKeymapByNames(dev, &kccgst, XkmAllIndicesMask, need, &xkb,
    472                                     name, PATH_MAX);
    473         if ((need & provided) != need) {
    474             if (xkb) {
    475                 XkbFreeKeyboard(xkb, 0, TRUE);
    476                 xkb = NULL;
    477             }
    478         }
    479     }
    480 
    481     XkbFreeComponentNames(&kccgst, FALSE);
    482     return xkb;
    483 }
    484 
    485 static XkbDescPtr
    486 KeymapOrDefaults(DeviceIntPtr dev, XkbDescPtr xkb)
    487 {
    488     XkbRMLVOSet dflts;
    489 
    490     if (xkb)
    491         return xkb;
    492 
    493     /* we didn't get what we really needed. And that will likely leave
    494      * us with a keyboard that doesn't work. Use the defaults instead */
    495     LogMessage(X_ERROR, "XKB: Failed to load keymap. Loading default "
    496                         "keymap instead.\n");
    497 
    498     XkbGetRulesDflts(&dflts);
    499 
    500     xkb = XkbCompileKeymapForDevice(dev, &dflts, 0);
    501 
    502     XkbFreeRMLVOSet(&dflts, FALSE);
    503 
    504     return xkb;
    505 }
    506 
    507 
    508 XkbDescPtr
    509 XkbCompileKeymap(DeviceIntPtr dev, XkbRMLVOSet * rmlvo)
    510 {
    511     XkbDescPtr xkb;
    512     unsigned int need;
    513 
    514     if (!dev || !rmlvo) {
    515         LogMessage(X_ERROR, "XKB: No device or RMLVO specified\n");
    516         return NULL;
    517     }
    518 
    519     /* These are the components we really really need */
    520     need = XkmSymbolsMask | XkmCompatMapMask | XkmTypesMask |
    521         XkmKeyNamesMask | XkmVirtualModsMask;
    522 
    523     xkb = XkbCompileKeymapForDevice(dev, rmlvo, need);
    524 
    525     return KeymapOrDefaults(dev, xkb);
    526 }
    527 
    528 XkbDescPtr
    529 XkbCompileKeymapFromString(DeviceIntPtr dev,
    530                            const char *keymap, int keymap_length)
    531 {
    532     XkbDescPtr xkb;
    533     unsigned int need, provided;
    534 
    535     if (!dev || !keymap) {
    536         LogMessage(X_ERROR, "XKB: No device or keymap specified\n");
    537         return NULL;
    538     }
    539 
    540     /* These are the components we really really need */
    541     need = XkmSymbolsMask | XkmCompatMapMask | XkmTypesMask |
    542            XkmKeyNamesMask | XkmVirtualModsMask;
    543 
    544     provided =
    545         XkbDDXLoadKeymapFromString(dev, keymap, keymap_length,
    546                                    XkmAllIndicesMask, need, &xkb);
    547     if ((need & provided) != need) {
    548         if (xkb) {
    549             XkbFreeKeyboard(xkb, 0, TRUE);
    550             xkb = NULL;
    551         }
    552     }
    553 
    554     return KeymapOrDefaults(dev, xkb);
    555 }