1/************************************************************
2Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#ifdef DEBUG
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <stdio.h>
32#endif
33
34#include "Xlibint.h"
35#include "XKBlibint.h"
36#include "X11/extensions/XKBgeom.h"
37#include <X11/extensions/XKBproto.h>
38
39#ifndef MINSHORT
40#define	MINSHORT	-32768
41#endif
42#ifndef MAXSHORT
43#define	MAXSHORT	32767
44#endif
45
46/***====================================================================***/
47
48#define	_SizeCountedString(s)  ((s)?XkbPaddedSize(2+strlen(s)):4)
49
50static char *
51_WriteCountedString(char *wire, char *str)
52{
53    CARD16 len, *pLen;
54
55    len = (CARD16) (str ? strlen(str) : 0);
56    pLen = (CARD16 *) wire;
57    *pLen = len;
58    if (len && str)
59        memcpy(&wire[2], str, len);
60    wire += XkbPaddedSize(len + 2);
61    return wire;
62}
63
64static int
65_SizeGeomProperties(XkbGeometryPtr geom)
66{
67    register int i, size;
68    XkbPropertyPtr prop;
69
70    for (size = i = 0, prop = geom->properties; i < geom->num_properties;
71         i++, prop++) {
72        size = (int) ((unsigned) size + _SizeCountedString(prop->name));
73        size = (int) ((unsigned) size + _SizeCountedString(prop->value));
74    }
75    return size;
76}
77
78static int
79_SizeGeomColors(XkbGeometryPtr geom)
80{
81    register int i, size;
82    register XkbColorPtr color;
83
84    for (i = size = 0, color = geom->colors; i < geom->num_colors; i++, color++) {
85        size = (int) ((unsigned) size + _SizeCountedString(color->spec));
86    }
87    return size;
88}
89
90static int
91_SizeGeomShapes(XkbGeometryPtr geom)
92{
93    register int i, size;
94    register XkbShapePtr shape;
95
96    for (i = size = 0, shape = geom->shapes; i < geom->num_shapes; i++, shape++) {
97        register int n;
98        register XkbOutlinePtr ol;
99
100        size += SIZEOF(xkbShapeWireDesc);
101        for (n = 0, ol = shape->outlines; n < shape->num_outlines; n++, ol++) {
102            size += SIZEOF(xkbOutlineWireDesc);
103            size += ol->num_points * SIZEOF(xkbPointWireDesc);
104        }
105    }
106    return size;
107}
108
109static int
110_SizeGeomDoodads(int num_doodads, XkbDoodadPtr doodad)
111{
112    register int i, size;
113
114    for (i = size = 0; i < num_doodads; i++, doodad++) {
115        size += SIZEOF(xkbAnyDoodadWireDesc);
116        if (doodad->any.type == XkbTextDoodad) {
117            size = (int) ((unsigned) size + _SizeCountedString(doodad->text.text));
118            size = (int) ((unsigned) size + _SizeCountedString(doodad->text.font));
119        }
120        else if (doodad->any.type == XkbLogoDoodad) {
121            size = (int) ((unsigned) size + _SizeCountedString(doodad->logo.logo_name));
122        }
123    }
124    return size;
125}
126
127static int
128_SizeGeomSections(XkbGeometryPtr geom)
129{
130    register int i, size;
131    XkbSectionPtr section;
132
133    for (i = size = 0, section = geom->sections; i < geom->num_sections;
134         i++, section++) {
135        size += SIZEOF(xkbSectionWireDesc);
136        if (section->rows) {
137            int r;
138            XkbRowPtr row;
139
140            for (r = 0, row = section->rows; r < section->num_rows; row++, r++) {
141                size += SIZEOF(xkbRowWireDesc);
142                size += row->num_keys * SIZEOF(xkbKeyWireDesc);
143            }
144        }
145        if (section->doodads)
146            size += _SizeGeomDoodads(section->num_doodads, section->doodads);
147        if (section->overlays) {
148            int o;
149            XkbOverlayPtr ol;
150
151            for (o = 0, ol = section->overlays; o < section->num_overlays;
152                 o++, ol++) {
153                int r;
154                XkbOverlayRowPtr row;
155
156                size += SIZEOF(xkbOverlayWireDesc);
157                for (r = 0, row = ol->rows; r < ol->num_rows; r++, row++) {
158                    size += SIZEOF(xkbOverlayRowWireDesc);
159                    size += row->num_keys * SIZEOF(xkbOverlayKeyWireDesc);
160                }
161            }
162        }
163    }
164    return size;
165}
166
167static int
168_SizeGeomKeyAliases(XkbGeometryPtr geom)
169{
170    return geom->num_key_aliases * (2 * XkbKeyNameLength);
171}
172
173/***====================================================================***/
174
175static char *
176_WriteGeomProperties(char *wire, XkbGeometryPtr geom)
177{
178    register int i;
179    register XkbPropertyPtr prop;
180
181    for (i = 0, prop = geom->properties; i < geom->num_properties; i++, prop++) {
182        wire = _WriteCountedString(wire, prop->name);
183        wire = _WriteCountedString(wire, prop->value);
184    }
185    return wire;
186}
187
188static char *
189_WriteGeomColors(char *wire, XkbGeometryPtr geom)
190{
191    register int i;
192    register XkbColorPtr color;
193
194    for (i = 0, color = geom->colors; i < geom->num_colors; i++, color++) {
195        wire = _WriteCountedString(wire, color->spec);
196    }
197    return wire;
198}
199
200static char *
201_WriteGeomShapes(char *wire, XkbGeometryPtr geom)
202{
203    int i;
204    XkbShapePtr shape;
205    xkbShapeWireDesc *shapeWire;
206
207    for (i = 0, shape = geom->shapes; i < geom->num_shapes; i++, shape++) {
208        register int o;
209        XkbOutlinePtr ol;
210        xkbOutlineWireDesc *olWire;
211
212        shapeWire = (xkbShapeWireDesc *) wire;
213        shapeWire->name = shape->name;
214        shapeWire->nOutlines = shape->num_outlines;
215        if (shape->primary != NULL)
216            shapeWire->primaryNdx = XkbOutlineIndex(shape, shape->primary);
217        else
218            shapeWire->primaryNdx = XkbNoShape;
219        if (shape->approx != NULL)
220            shapeWire->approxNdx = XkbOutlineIndex(shape, shape->approx);
221        else
222            shapeWire->approxNdx = XkbNoShape;
223        wire = (char *) &shapeWire[1];
224        for (o = 0, ol = shape->outlines; o < shape->num_outlines; o++, ol++) {
225            register int p;
226            XkbPointPtr pt;
227            xkbPointWireDesc *ptWire;
228
229            olWire = (xkbOutlineWireDesc *) wire;
230            olWire->nPoints = ol->num_points;
231            olWire->cornerRadius = ol->corner_radius;
232            wire = (char *) &olWire[1];
233            ptWire = (xkbPointWireDesc *) wire;
234            for (p = 0, pt = ol->points; p < ol->num_points; p++, pt++) {
235                ptWire[p].x = pt->x;
236                ptWire[p].y = pt->y;
237            }
238            wire = (char *) &ptWire[ol->num_points];
239        }
240    }
241    return wire;
242}
243
244static char *
245_WriteGeomDoodads(char *wire, int num_doodads, XkbDoodadPtr doodad)
246{
247    register int i;
248
249    for (i = 0; i < num_doodads; i++, doodad++) {
250        xkbDoodadWireDesc *doodadWire = (xkbDoodadWireDesc *) wire;
251
252        wire = (char *) &doodadWire[1];
253        bzero(doodadWire, SIZEOF(xkbDoodadWireDesc));
254        doodadWire->any.name = doodad->any.name;
255        doodadWire->any.type = doodad->any.type;
256        doodadWire->any.priority = doodad->any.priority;
257        doodadWire->any.top = doodad->any.top;
258        doodadWire->any.left = doodad->any.left;
259        doodadWire->any.angle = doodad->any.angle;
260        switch (doodad->any.type) {
261        case XkbOutlineDoodad:
262        case XkbSolidDoodad:
263            doodadWire->shape.colorNdx = doodad->shape.color_ndx;
264            doodadWire->shape.shapeNdx = doodad->shape.shape_ndx;
265            break;
266        case XkbTextDoodad:
267            doodadWire->text.width = doodad->text.width;
268            doodadWire->text.height = doodad->text.height;
269            doodadWire->text.colorNdx = doodad->text.color_ndx;
270            wire = _WriteCountedString(wire, doodad->text.text);
271            wire = _WriteCountedString(wire, doodad->text.font);
272            break;
273        case XkbIndicatorDoodad:
274            doodadWire->indicator.shapeNdx = doodad->indicator.shape_ndx;
275            doodadWire->indicator.onColorNdx = doodad->indicator.on_color_ndx;
276            doodadWire->indicator.offColorNdx = doodad->indicator.off_color_ndx;
277            break;
278        case XkbLogoDoodad:
279            doodadWire->logo.colorNdx = doodad->logo.color_ndx;
280            doodadWire->logo.shapeNdx = doodad->logo.shape_ndx;
281            wire = _WriteCountedString(wire, doodad->logo.logo_name);
282            break;
283        default:
284            break;
285        }
286    }
287    return wire;
288}
289
290static char *
291_WriteGeomOverlay(char *wire, XkbOverlayPtr ol)
292{
293    register int r;
294    XkbOverlayRowPtr row;
295    xkbOverlayWireDesc *olWire = (xkbOverlayWireDesc *) wire;
296
297    olWire->name = ol->name;
298    olWire->nRows = ol->num_rows;
299    wire = (char *) &olWire[1];
300    for (r = 0, row = ol->rows; r < ol->num_rows; r++, row++) {
301        unsigned int k;
302        XkbOverlayKeyPtr key;
303        xkbOverlayRowWireDesc *rowWire = (xkbOverlayRowWireDesc *) wire;
304
305        rowWire->rowUnder = row->row_under;
306        rowWire->nKeys = row->num_keys;
307        wire = (char *) &rowWire[1];
308        for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
309            xkbOverlayKeyWireDesc *keyWire = (xkbOverlayKeyWireDesc *) wire;
310
311            memcpy(keyWire->over, key->over.name, XkbKeyNameLength);
312            memcpy(keyWire->under, key->under.name, XkbKeyNameLength);
313            wire = (char *) &keyWire[1];
314        }
315    }
316    return wire;
317}
318
319static char *
320_WriteGeomSections(char *wire, XkbGeometryPtr geom)
321{
322    register int i;
323    XkbSectionPtr section;
324
325    for (i = 0, section = geom->sections; i < geom->num_sections;
326         i++, section++) {
327        xkbSectionWireDesc *sectionWire = (xkbSectionWireDesc *) wire;
328
329        sectionWire->name = section->name;
330        sectionWire->top = section->top;
331        sectionWire->left = section->left;
332        sectionWire->width = section->width;
333        sectionWire->height = section->height;
334        sectionWire->angle = section->angle;
335        sectionWire->priority = section->priority;
336        sectionWire->nRows = section->num_rows;
337        sectionWire->nDoodads = section->num_doodads;
338        sectionWire->nOverlays = section->num_overlays;
339        sectionWire->pad = 0;
340        wire = (char *) &sectionWire[1];
341        if (section->rows) {
342            int r;
343            XkbRowPtr row;
344
345            for (r = 0, row = section->rows; r < section->num_rows; r++, row++) {
346                xkbRowWireDesc *rowWire = (xkbRowWireDesc *) wire;
347
348                rowWire->top = row->top;
349                rowWire->left = row->left;
350                rowWire->nKeys = row->num_keys;
351                rowWire->vertical = row->vertical;
352                rowWire->pad = 0;
353                wire = (char *) &rowWire[1];
354                if (row->keys) {
355                    int k;
356                    XkbKeyPtr key;
357                    xkbKeyWireDesc *keyWire = (xkbKeyWireDesc *) wire;
358
359                    for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
360                        memcpy(keyWire[k].name, key->name.name,
361                               XkbKeyNameLength);
362                        keyWire[k].gap = key->gap;
363                        keyWire[k].shapeNdx = key->shape_ndx;
364                        keyWire[k].colorNdx = key->color_ndx;
365                    }
366                    wire = (char *) &keyWire[row->num_keys];
367                }
368            }
369        }
370        if (section->doodads) {
371            wire = _WriteGeomDoodads(wire,
372                                     section->num_doodads, section->doodads);
373        }
374        if (section->overlays) {
375            register int o;
376
377            for (o = 0; o < section->num_overlays; o++) {
378                wire = _WriteGeomOverlay(wire, &section->overlays[o]);
379            }
380        }
381    }
382    return wire;
383}
384
385static char *
386_WriteGeomKeyAliases(char *wire, XkbGeometryPtr geom)
387{
388    register int sz;
389
390    sz = geom->num_key_aliases * (XkbKeyNameLength * 2);
391    if (sz > 0) {
392        memcpy(wire, (char *) geom->key_aliases, (size_t)sz);
393        wire += sz;
394    }
395    return wire;
396}
397
398/***====================================================================***/
399
400static Status
401_SendSetGeometry(Display *dpy, XkbGeometryPtr geom, xkbSetGeometryReq *req)
402{
403    int sz;
404    char *wire, *tbuf;
405
406    sz = 0;
407    sz = (int) ((unsigned) (sz + _SizeCountedString(geom->label_font)));
408    sz += _SizeGeomProperties(geom);
409    sz += _SizeGeomColors(geom);
410    sz += _SizeGeomShapes(geom);
411    sz += _SizeGeomSections(geom);
412    sz += _SizeGeomDoodads(geom->num_doodads, geom->doodads);
413    sz += _SizeGeomKeyAliases(geom);
414    req->length += (sz / 4);
415    if (sz < (dpy->bufmax - dpy->buffer)) {
416        BufAlloc(char *, wire, sz);
417        tbuf = NULL;
418    }
419    else {
420        tbuf = _XAllocTemp(dpy, sz);
421        if (!tbuf)
422            return BadAlloc;
423        wire = tbuf;
424    }
425    wire = _WriteCountedString(wire, geom->label_font);
426    if (geom->num_properties > 0)
427        wire = _WriteGeomProperties(wire, geom);
428    if (geom->num_colors > 0)
429        wire = _WriteGeomColors(wire, geom);
430    if (geom->num_shapes > 0)
431        wire = _WriteGeomShapes(wire, geom);
432    if (geom->num_sections > 0)
433        wire = _WriteGeomSections(wire, geom);
434    if (geom->num_doodads > 0)
435        wire = _WriteGeomDoodads(wire, geom->num_doodads, geom->doodads);
436    if (geom->num_key_aliases > 0)
437        wire = _WriteGeomKeyAliases(wire, geom);
438    if (tbuf != NULL) {
439        Data(dpy, tbuf, sz);
440        _XFreeTemp(dpy, tbuf, sz);
441    }
442    return Success;
443}
444
445/***====================================================================***/
446
447Status
448XkbSetGeometry(Display *dpy, unsigned deviceSpec, XkbGeometryPtr geom)
449{
450    xkbSetGeometryReq *req;
451    Status ret;
452
453    if ((!geom) || (dpy->flags & XlibDisplayNoXkb) ||
454        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
455        return BadAccess;
456
457    LockDisplay(dpy);
458    GetReq(kbSetGeometry, req);
459    req->reqType = dpy->xkb_info->codes->major_opcode;
460    req->xkbReqType = X_kbSetGeometry;
461    req->deviceSpec = deviceSpec;
462    req->nShapes = geom->num_shapes;
463    req->nSections = geom->num_sections;
464    req->name = geom->name;
465    req->widthMM = geom->width_mm;
466    req->heightMM = geom->height_mm;
467    req->nProperties = geom->num_properties;
468    req->nColors = geom->num_colors;
469    req->nDoodads = geom->num_doodads;
470    req->nKeyAliases = geom->num_key_aliases;
471    req->baseColorNdx = (geom->base_color - geom->colors);
472    req->labelColorNdx = (geom->label_color - geom->colors);
473
474    ret = _SendSetGeometry(dpy, geom, req);
475    UnlockDisplay(dpy);
476    SyncHandle();
477    return ret;
478}
479