1
/* $XConsortium: tclxkbui.c /main/2 1996/10/19 19:06:46 kaleb $ */
7
/* $XFree86: xc/programs/Xserver/hw/xfree86/XF86Setup/tclxkbui.c,v 3.2 1996/12/27 06:54:25 dawes Exp $ */
11
* This module implements "xkbview" widgets.
12
* A "xkbview" is a widget that uses the xkbui library to
13
* display a representation of the keyboard as described by
16
* Copyright 1996 Joseph Moss
18
* The file is derived from the sample widget code tkSquare.c, which is
19
* Copyright (c) 1991-1994 The Regents of the University of California.
20
* Copyright (c) 1994-1995 Sun Microsystems, Inc.
22
* See the file "license.terms" for information on usage and redistribution
23
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
29
#include <X11/XKBlib.h>
30
#include <X11/extensions/XKBgeom.h>
31
#include <X11/extensions/XKBui.h>
33
#define DEF_XKBUI_HEIGHT "100"
34
#define DEF_XKBUI_WIDTH "300"
36
extern char * TkInitXkbUIWin _ANSI_ARGS_((Tcl_Interp *interp,
37
Tk_Window tkwin, int toplevel, int argc,
40
extern XkbDescPtr GetXkbDescPtr _ANSI_ARGS_((Tcl_Interp *interp,
44
* A data structure of the following type is kept for each xkbview
45
* widget managed by this file:
49
Tk_Window tkwin; /* Window that embodies the xkbview. NULL
50
* means window has been deleted but
51
* widget record hasn't been cleaned up yet. */
52
Display *display; /* X's token for the window's display. */
53
Tcl_Interp *interp; /* Interpreter associated with widget. */
54
Tcl_Command widgetCmd; /* Token for xkbview's widget command. */
55
int width, height; /* Window height & width */
58
* Information used when displaying widget:
61
int borderWidth; /* Width of 3-D border around whole widget. */
62
Tk_3DBorder bgBorder; /* Used for drawing background. */
63
int relief; /* Indicates whether window as a whole is
64
* raised, sunken, or flat. */
65
GC gc; /* Graphics context for copying from
66
* off-screen pixmap onto screen. */
67
int doubleBuffer; /* Non-zero means double-buffer redisplay
68
* with pixmap; zero means draw straight
69
* onto the display. */
70
int updatePending; /* Non-zero means a call to XkbUIWinDisplay
71
* has already been scheduled. */
72
char *xkbHandle; /* Handle of XkbDescRec */
73
XkbUI_ViewPtr view; /* XkbUI view structure */
78
* Information used for argv parsing.
81
static Tk_ConfigSpec configSpecs[] = {
82
{TK_CONFIG_BORDER, "-background", "background", "Background",
83
"#cdb79e", Tk_Offset(XkbUIWin, bgBorder), TK_CONFIG_COLOR_ONLY},
84
{TK_CONFIG_BORDER, "-background", "background", "Background",
85
"white", Tk_Offset(XkbUIWin, bgBorder), TK_CONFIG_MONO_ONLY},
86
{TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
88
{TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
90
{TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
91
"2", Tk_Offset(XkbUIWin, borderWidth), 0},
92
{TK_CONFIG_INT, "-dbl", "doubleBuffer", "DoubleBuffer",
93
"1", Tk_Offset(XkbUIWin, doubleBuffer), 0},
94
{TK_CONFIG_PIXELS, "-height", "height", "Height",
95
DEF_XKBUI_HEIGHT, Tk_Offset(XkbUIWin, height), 0},
96
{TK_CONFIG_STRING, "-keyboard", "keyboard", (char *) NULL,
97
"xkb1", Tk_Offset(XkbUIWin, xkbHandle), 0},
98
{TK_CONFIG_SYNONYM, "-kbd", "keyboard", (char *) NULL,
100
{TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
101
"raised", Tk_Offset(XkbUIWin, relief), 0},
102
{TK_CONFIG_PIXELS, "-width", "width", "Width",
103
DEF_XKBUI_WIDTH, Tk_Offset(XkbUIWin, width), 0},
104
{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
109
* Forward declarations for procedures defined later in this file:
112
static void XkbUIWinCmdDeletedProc _ANSI_ARGS_((
113
ClientData clientData));
114
static int XkbUIWinConfigure _ANSI_ARGS_((Tcl_Interp *interp,
115
XkbUIWin *xkbui, int argc, char **argv,
117
static void XkbUIWinDestroy _ANSI_ARGS_((ClientData clientData));
118
static void XkbUIWinDisplay _ANSI_ARGS_((ClientData clientData));
119
static void XkbUIWinEventProc _ANSI_ARGS_((ClientData clientData,
121
static int XkbUIWinWidgetCmd _ANSI_ARGS_((ClientData clientData,
122
Tcl_Interp *, int argc, char **argv));
125
*--------------------------------------------------------------
129
* This procedure is invoked to process the "xkbview" Tcl
130
* command. It creates a new "xkbview" widget.
133
* A standard Tcl result.
136
* A new widget is created and configured.
138
*--------------------------------------------------------------
142
XkbUIWinCmd(clientData, interp, argc, argv)
143
ClientData clientData; /* Main window associated with
145
Tcl_Interp *interp; /* Current interpreter. */
146
int argc; /* Number of arguments. */
147
char **argv; /* Argument strings. */
149
Tk_Window main = (Tk_Window) clientData;
154
Tcl_AppendResult(interp, "wrong # args: should be \"",
155
argv[0], " pathName ?options?\"", (char *) NULL);
159
tkwin = Tk_CreateWindowFromPath(interp, main, argv[1], (char *) NULL);
163
Tk_SetClass(tkwin, "Xkbui");
166
* Allocate and initialize the widget record.
169
xkbuiPtr = (XkbUIWin *) ckalloc(sizeof(XkbUIWin));
170
xkbuiPtr->tkwin = tkwin;
171
xkbuiPtr->display = Tk_Display(tkwin);
172
xkbuiPtr->interp = interp;
173
xkbuiPtr->widgetCmd = Tcl_CreateCommand(interp,
174
Tk_PathName(xkbuiPtr->tkwin), XkbUIWinWidgetCmd,
175
(ClientData) xkbuiPtr, XkbUIWinCmdDeletedProc);
176
xkbuiPtr->height = -1;
177
xkbuiPtr->width = -1;
178
xkbuiPtr->borderWidth = 0;
179
xkbuiPtr->bgBorder = NULL;
180
xkbuiPtr->relief = TK_RELIEF_FLAT;
182
xkbuiPtr->doubleBuffer = 1;
183
xkbuiPtr->updatePending = 0;
184
xkbuiPtr->xkbHandle = NULL;
185
xkbuiPtr->view = NULL;
187
Tk_CreateEventHandler(xkbuiPtr->tkwin, ExposureMask|StructureNotifyMask,
188
XkbUIWinEventProc, (ClientData) xkbuiPtr);
189
if (XkbUIWinConfigure(interp, xkbuiPtr, argc-2, argv+2, 0) != TCL_OK) {
190
Tk_DestroyWindow(xkbuiPtr->tkwin);
194
interp->result = Tk_PathName(xkbuiPtr->tkwin);
199
*--------------------------------------------------------------
201
* XkbUIWinWidgetCmd --
203
* This procedure is invoked to process the Tcl command
204
* that corresponds to a widget managed by this module.
205
* See the user documentation for details on what it does.
208
* A standard Tcl result.
211
* See the user documentation.
213
*--------------------------------------------------------------
217
XkbUIWinWidgetCmd(clientData, interp, argc, argv)
218
ClientData clientData; /* Information about xkbview widget. */
219
Tcl_Interp *interp; /* Current interpreter. */
220
int argc; /* Number of arguments. */
221
char **argv; /* Argument strings. */
223
XkbUIWin *xkbuiPtr = (XkbUIWin *) clientData;
229
Tcl_AppendResult(interp, "wrong # args: should be \"",
230
argv[0], " option ?arg arg ...?\"", (char *) NULL);
233
Tk_Preserve((ClientData) xkbuiPtr);
235
length = strlen(argv[1]);
236
if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
239
Tcl_AppendResult(interp, "wrong # args: should be \"",
240
argv[0], " cget option\"",
244
result = Tk_ConfigureValue(interp, xkbuiPtr->tkwin, configSpecs,
245
(char *) xkbuiPtr, argv[2], 0);
246
} else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
249
result = Tk_ConfigureInfo(interp, xkbuiPtr->tkwin, configSpecs,
250
(char *) xkbuiPtr, (char *) NULL, 0);
251
} else if (argc == 3) {
252
result = Tk_ConfigureInfo(interp, xkbuiPtr->tkwin, configSpecs,
253
(char *) xkbuiPtr, argv[2], 0);
255
result = XkbUIWinConfigure(interp, xkbuiPtr, argc-2, argv+2,
256
TK_CONFIG_ARGV_ONLY);
258
} else if ((c == 'r') && (strncmp(argv[1], "refresh", length) == 0)
260
/* Nothing - The call to Tk_DoWhenIdle below takes care of this */
263
Tcl_AppendResult(interp, "bad option \"", argv[1],
264
"\": must be cget, configure, or refresh",
268
if (!xkbuiPtr->updatePending) {
269
Tk_DoWhenIdle(XkbUIWinDisplay, (ClientData) xkbuiPtr);
270
xkbuiPtr->updatePending = 1;
272
Tk_Release((ClientData) xkbuiPtr);
276
Tk_Release((ClientData) xkbuiPtr);
281
*----------------------------------------------------------------------
283
* XkbUIWinConfigure --
285
* This procedure is called to process an argv/argc list in
286
* conjunction with the Tk option database to configure (or
287
* reconfigure) a xkbview widget.
290
* The return value is a standard Tcl result. If TCL_ERROR is
291
* returned, then interp->result contains an error message.
294
* Configuration information, such as colors, border width,
295
* etc. get set for xkbuiPtr; old resources get freed,
298
*----------------------------------------------------------------------
302
XkbUIWinConfigure(interp, xkbuiPtr, argc, argv, flags)
303
Tcl_Interp *interp; /* Used for error reporting. */
304
XkbUIWin *xkbuiPtr; /* Information about widget. */
305
int argc; /* Number of valid entries in argv. */
306
char **argv; /* Arguments. */
307
int flags; /* Flags to pass to
308
* Tk_ConfigureWidget. */
310
if (Tk_ConfigureWidget(interp, xkbuiPtr->tkwin, configSpecs,
311
argc, argv, (char *) xkbuiPtr, flags) != TCL_OK) {
316
* Set the background for the window and create a graphics context
317
* for use during redisplay.
320
Tk_SetWindowBackground(xkbuiPtr->tkwin,
321
Tk_3DBorderColor(xkbuiPtr->bgBorder)->pixel);
322
if ((xkbuiPtr->gc == None) && (xkbuiPtr->doubleBuffer)) {
324
gcValues.function = GXcopy;
325
gcValues.graphics_exposures = False;
326
xkbuiPtr->gc = Tk_GetGC(xkbuiPtr->tkwin,
327
GCFunction|GCGraphicsExposures, &gcValues);
331
* Register the desired geometry for the window. Then arrange for
332
* the window to be redisplayed.
335
Tk_GeometryRequest(xkbuiPtr->tkwin, 200, 150);
336
Tk_SetInternalBorder(xkbuiPtr->tkwin, xkbuiPtr->borderWidth);
337
if (!xkbuiPtr->updatePending) {
338
Tk_DoWhenIdle(XkbUIWinDisplay, (ClientData) xkbuiPtr);
339
xkbuiPtr->updatePending = 1;
345
*--------------------------------------------------------------
347
* XkbUIWinEventProc --
349
* This procedure is invoked by the Tk dispatcher for various
350
* events on xkbviews.
356
* When the window gets deleted, internal structures get
357
* cleaned up. When it gets exposed, it is redisplayed.
359
*--------------------------------------------------------------
363
XkbUIWinEventProc(clientData, eventPtr)
364
ClientData clientData; /* Information about window. */
365
XEvent *eventPtr; /* Information about event. */
367
XkbUIWin *xkbuiPtr = (XkbUIWin *) clientData;
369
if (eventPtr->type == Expose) {
370
if (!xkbuiPtr->updatePending) {
371
Tk_DoWhenIdle(XkbUIWinDisplay, (ClientData) xkbuiPtr);
372
xkbuiPtr->updatePending = 1;
374
} else if (eventPtr->type == ConfigureNotify) {
375
if (!xkbuiPtr->updatePending) {
376
Tk_DoWhenIdle(XkbUIWinDisplay, (ClientData) xkbuiPtr);
377
xkbuiPtr->updatePending = 1;
379
} else if (eventPtr->type == DestroyNotify) {
380
if (xkbuiPtr->tkwin != NULL) {
381
xkbuiPtr->tkwin = NULL;
382
Tcl_DeleteCommand(xkbuiPtr->interp,
383
Tcl_GetCommandName(xkbuiPtr->interp,
384
xkbuiPtr->widgetCmd));
386
if (xkbuiPtr->updatePending) {
387
Tk_CancelIdleCall(XkbUIWinDisplay, (ClientData) xkbuiPtr);
389
Tk_EventuallyFree((ClientData) xkbuiPtr,
390
(Tcl_FreeProc *)XkbUIWinDestroy);
395
*----------------------------------------------------------------------
397
* XkbUIWinCmdDeletedProc --
399
* This procedure is invoked when a widget command is deleted. If
400
* the widget isn't already in the process of being destroyed,
401
* this command destroys it.
407
* The widget is destroyed.
409
*----------------------------------------------------------------------
413
XkbUIWinCmdDeletedProc(clientData)
414
ClientData clientData; /* Pointer to widget record for widget. */
416
XkbUIWin *xkbuiPtr = (XkbUIWin *) clientData;
417
Tk_Window tkwin = xkbuiPtr->tkwin;
420
* This procedure could be invoked either because the window was
421
* destroyed and the command was then deleted (in which case tkwin
422
* is NULL) or because the command was deleted, and then this procedure
423
* destroys the widget.
427
xkbuiPtr->tkwin = NULL;
428
Tk_DestroyWindow(tkwin);
433
*--------------------------------------------------------------
437
* This procedure redraws the contents of a xkbview window.
438
* It is invoked as a do-when-idle handler, so it only runs
439
* when there's nothing else for the application to do.
445
* Information appears on the screen.
447
*--------------------------------------------------------------
451
XkbUIWinDisplay(clientData)
452
ClientData clientData; /* Information about window. */
454
XkbUIWin *xkbuiPtr = (XkbUIWin *) clientData;
455
Tk_Window tkwin = xkbuiPtr->tkwin;
459
XkbUI_ViewOptsRec opts;
460
int width, height, bd;
462
xkbuiPtr->updatePending = 0;
463
if (!Tk_IsMapped(tkwin)) {
468
* Create a pixmap for double-buffering, if necessary.
471
if (xkbuiPtr->doubleBuffer) {
472
pm = XCreatePixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
473
(unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin),
474
(unsigned) DefaultDepthOfScreen(Tk_Screen(tkwin)));
477
d = Tk_WindowId(tkwin);
481
* Redraw the widget's background and border.
484
Tk_Fill3DRectangle(tkwin, d, xkbuiPtr->bgBorder, 0, 0, Tk_Width(tkwin),
485
Tk_Height(tkwin), xkbuiPtr->borderWidth, xkbuiPtr->relief);
488
* Display the keyboard.
491
bzero((char *)&opts, sizeof(opts));
493
if (xkbuiPtr->relief != TK_RELIEF_FLAT)
494
bd = xkbuiPtr->borderWidth;
495
opts.present = XkbUI_SizeMask|XkbUI_ColormapMask
496
|XkbUI_MarginMask|XkbUI_OffsetMask;
497
opts.margin_width = opts.margin_height = 0;
498
opts.viewport.x = opts.viewport.y = bd;
499
width = opts.viewport.width = Tk_Width(tkwin) - 2*bd;
500
height = opts.viewport.height = Tk_Height(tkwin) - 2*bd;
501
opts.cmap = Tk_Colormap(tkwin);
502
xkb = GetXkbDescPtr(xkbuiPtr->interp, xkbuiPtr->xkbHandle);
505
ckfree(xkbuiPtr->view);
506
xkbuiPtr->view= XkbUI_Init(xkbuiPtr->display, d,
507
width, height, xkb, &opts);
509
XkbUI_DrawRegion(xkbuiPtr->view,NULL);
513
* If double-buffered, copy to the screen and release the pixmap.
516
if (xkbuiPtr->doubleBuffer) {
517
XCopyArea(Tk_Display(tkwin), pm, Tk_WindowId(tkwin), xkbuiPtr->gc,
518
0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin),
520
XFreePixmap(Tk_Display(tkwin), pm);
525
*----------------------------------------------------------------------
529
* This procedure is invoked by Tk_EventuallyFree or Tk_Release
530
* to clean up the internal structure of a xkbview at a safe time
531
* (when no-one is using it anymore).
537
* Everything associated with the xkbview is freed up.
539
*----------------------------------------------------------------------
543
XkbUIWinDestroy(clientData)
544
ClientData clientData; /* Info about xkbview widget. */
546
XkbUIWin *xkbuiPtr = (XkbUIWin *) clientData;
548
Tk_FreeOptions(configSpecs, (char *) xkbuiPtr, xkbuiPtr->display, 0);
549
if (xkbuiPtr->gc != None) {
550
Tk_FreeGC(xkbuiPtr->display, xkbuiPtr->gc);
552
if (xkbuiPtr->view != NULL) {
553
ckfree(xkbuiPtr->view);
555
ckfree((char *) xkbuiPtr);