blob: ff8114f0ffcdcde3733176b8e32af525330460cf [file] [log] [blame]
/*
* BRLTTY - A background process providing access to the console screen (when in
* text mode) for a blind person using a refreshable braille display.
*
* Copyright (C) 1995-2023 by The BRLTTY Developers.
*
* BRLTTY comes with ABSOLUTELY NO WARRANTY.
*
* This is free software, placed under the terms of the
* GNU Lesser General Public License, as published by the Free Software
* Foundation; either version 2.1 of the License, or (at your option) any
* later version. Please see the file LICENSE-LGPL for details.
*
* Web Page: http://brltty.app/
*
* This software is maintained by Dave Mielke <dave@mielke.cc>.
*/
#include "prologue.h"
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <signal.h>
#include "log.h"
#include "parse.h"
#include "charset.h"
#include "unicode.h"
#if defined(WINDOWS)
#define USE_WINDOWS
#elif defined(HAVE_PKG_XAW)
#define USE_XAW
#define USE_XT
#include <X11/Intrinsic.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Repeater.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeLine.h>
#include <X11/Xaw/SmeBSB.h>
#elif defined(HAVE_PKG_XAW3D)
#define USE_XAW
#define USE_XT
#define XAW_INTERNATIONALIZATION
#include <X11/Intrinsic.h>
#include <X11/Xaw3d/Form.h>
#include <X11/Xaw3d/Paned.h>
#include <X11/Xaw3d/Label.h>
#include <X11/Xaw3d/Command.h>
#include <X11/Xaw3d/Repeater.h>
#include <X11/Xaw3d/SimpleMenu.h>
#include <X11/Xaw3d/SmeLine.h>
#include <X11/Xaw3d/SmeBSB.h>
#elif defined(HAVE_PKG_NEXTAW)
#define USE_XAW
#define USE_XT
#include <X11/Intrinsic.h>
#include <X11/neXtaw/Form.h>
#include <X11/neXtaw/Paned.h>
#include <X11/neXtaw/Label.h>
#include <X11/neXtaw/Command.h>
#include <X11/neXtaw/Repeater.h>
#include <X11/neXtaw/SimpleMenu.h>
#include <X11/neXtaw/SmeLine.h>
#include <X11/neXtaw/SmeBSB.h>
#elif defined(HAVE_PKG_XAWPLUS)
#define USE_XAW
#define USE_XT
#include <X11/Intrinsic.h>
#include <X11/XawPlus/Form.h>
#include <X11/XawPlus/Paned.h>
#include <X11/XawPlus/Label.h>
#include <X11/XawPlus/Command.h>
#include <X11/XawPlus/Repeater.h>
#include <X11/XawPlus/SimpleMenu.h>
#include <X11/XawPlus/SmeLine.h>
#include <X11/XawPlus/SmeBSB.h>
#elif defined(HAVE_PKG_XM)
#define USE_XM
#define USE_XT
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/PanedW.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/ToggleB.h>
#include <Xm/RowColumn.h>
#include <Xm/MenuShell.h>
#else /* HAVE_PKG_ */
#error GUI toolkit either unspecified or unsupported
#endif /* HAVE_PKG_ */
#ifdef USE_XT
#define XK_MISCELLANY
#include <X11/Xlib.h>
#include <X11/StringDefs.h>
#include <X11/keysymdef.h>
#include <X11/Shell.h>
#endif /* USE_XT */
#ifdef USE_WINDOWS
#include <commctrl.h>
#include <windowsx.h>
#define XtNumber(t) (sizeof(t)/sizeof(*t))
typedef void *XtPointer;
#endif /* USE_WINDOWS */
#if defined(USE_XAW)
#define formWidgetClass formWidgetClass
#define panedWidgetClass panedWidgetClass
#define labelWidgetClass labelWidgetClass
#define commandWidgetClass commandWidgetClass
#define repeaterWidgetClass repeaterWidgetClass
#define menuEntryWidgetClass smeBSBObjectClass
#define CreatePopupMenu(title, toplevel) \
XtCreatePopupShell(title, simpleMenuWidgetClass, toplevel, NULL, 0)
#define AddMenuSeparator(title, menu) \
XtVaCreateManagedWidget(title, smeLineObjectClass, menu, NULL)
#define AddMenuLabel(title, menu) \
XtVaCreateManagedWidget(title, smeBSBObjectClass, menu, NULL);
#define AddMenuRadio(title, menu, cb, checked) \
XtVaCreateManagedWidget(title, menuEntryWidgetClass, menu, \
NvalueChangedCallback, cb, NtoggleState, checked ? check : None, \
XtNleftMargin, 9, \
NULL);
#define Nlabel XtNlabel
#define Ncallback XtNcallback
#define NvalueChangedCallback XtNcallback
#define Ntop XtNtop
#define Nbottom XtNbottom
#define Nleft XtNleft
#define Nright XtNright
#define ChainTop XtChainTop
#define ChainBottom XtChainTop
#define ChainLeft XtChainLeft
#define ChainRight XtChainLeft
#define NvertDistance XtNvertDistance
#define NhorizDistance XtNhorizDistance
#define NtoggleState XtNleftBitmap
#define MenuWidget Widget
#elif defined(USE_XM)
#define formWidgetClass xmFormWidgetClass
#define panedWidgetClass xmPanedWindowWidgetClass
#define labelWidgetClass xmLabelWidgetClass
#define commandWidgetClass xmPushButtonWidgetClass
#define repeaterWidgetClass xmPushButtonWidgetClass
#define menuEntryWidgetClass xmToggleButtonWidgetClass
#define CreatePopupMenu(title, toplevel) \
XmCreatePopupMenu(toplevel, title, NULL, 0)
#define AddMenuSeparator(title, menu) while (0) { }
#define AddMenuLabel(title, menu) \
XtVaCreateManagedWidget(title, xmToggleButtonWidgetClass, menu, NULL);
#define AddMenuRadio(title, menu, cb, checked) \
XtVaCreateManagedWidget(title, menuEntryWidgetClass, menu, \
NvalueChangedCallback, cb, NtoggleState, checked ? XmSET : XmUNSET, \
NULL);
#define Nlabel XmNlabelString
#define Ncallback XmNactivateCallback
#define NvalueChangedCallback XmNvalueChangedCallback
#define Ntop XmNtopAttachment
#define Nbottom XmNbottomAttachment
#define Nleft XmNleftAttachment
#define Nright XmNrightAttachment
#define ChainTop XmATTACH_FORM
#define ChainBottom XmATTACH_NONE
#define ChainLeft XmATTACH_FORM
#define ChainRight XmATTACH_NONE
#define NvertDistance XmNtopOffset
#define NhorizDistance XmNleftOffset
#define NtoggleState XmNset
#define MenuWidget Widget
#elif defined(USE_WINDOWS)
#define Widget HWND
#define MenuWidget HMENU
#define CreatePopupMenu(title, toplevel) \
CreatePopupMenu()
#define AddMenuSeparator(title, menu) \
AppendMenu(menu, MF_SEPARATOR, 0, NULL)
#define AddMenuLabel(title, menu) \
AppendMenu(menu, MF_STRING | MF_DISABLED, 0, title)
#define AddMenuRadio(title, menu, cb, check) \
AppendMenu(menu, MF_STRING | (check?MF_CHECKED:0), cb, title)
#define CHRX 16
#define CHRY 20
#define RIGHTMARGIN 100
#else /* USE_ */
#error GUI toolkit paradigm either unspecified or unsupported
#endif /* USE_ */
typedef enum {
PARM_TKPARMS,
PARM_LINES,
PARM_COLUMNS,
PARM_MODEL,
PARM_INPUT,
PARM_FONT
} DriverParameter;
#define BRLPARMS "tkparms", "lines", "columns", "model", "input", "font"
#include "brl_driver.h"
#include "braille.h"
#define MAXLINES 3
#define MAXCOLS 88
#define WHOLESIZE (MAXLINES * MAXCOLS)
static int cols,lines;
static int input;
static const char *model = "simple";
static const char *fontname = "-*-clearlyu-*-*-*-*-*-*-*-*-*-*-iso10646-1,-*-fixed-*-*-*-*-*-*-*-*-*-*-iso10646-1,-*-unifont-*-*-*-*-*-*-*-*-*-*-iso10646-1,-*-fixed-*-*-*-*-*-*-*-*-*-*-iso8859-1";
static int xtArgc = 1;
static char *xtDefArgv[]= { "brltty", NULL };
static char **xtArgv = xtDefArgv;
static int regenerate;
static int generateToplevel(void);
static void destroyToplevel(void);
#if defined(USE_XAW) || defined(USE_WINDOWS)
static unsigned char displayedWindow[WHOLESIZE];
#endif /* USE_XAW || USE_WINDOWS */
static wchar_t displayedVisual[WHOLESIZE];
#define BUTWIDTH 48
#define BUTHEIGHT 32
static Widget toplevel,hbox,display[WHOLESIZE];
static MenuWidget menu;
#if defined(USE_XAW) || defined(USE_WINDOWS)
static Widget displayb[WHOLESIZE];
#endif /* USE_XAW || USE_WINDOWS */
#ifdef USE_XAW
static Pixmap check;
#endif /* USE_XAW */
static int lastcursor = BRL_NO_CURSOR;
#ifdef USE_XT
static Atom wm_delete_window;
static Widget vbox,keybox;
static Pixel displayForeground,displayBackground;
static XtAppContext app_con;
#ifdef USE_XM
static XmString display_cs;
#endif /* USE_XAW */
#endif /* USE_XT */
#ifdef USE_XAW
static XFontSet fontset;
#elif defined(USE_WINDOWS)
static HFONT font;
static int totlines;
#endif /* USE_WINDOWS */
#ifdef USE_WINDOWS
static int modelWidth,modelHeight;
#endif /* USE_WINDOWS */
#ifdef USE_XT
static void KeyPressCB(Widget w, XtPointer closure, XtPointer callData)
{
logMessage(LOG_DEBUG,"keypresscb(%p)", closure);
enqueueCommand((long) closure);
}
static void keypress(Widget w, XEvent *event, String *params, Cardinal *num_params) {
static Modifiers my_modifiers;
long keypressed;
Modifiers modifiers, modifier;
KeySym keysym;
if (event->type != KeyPress && event->type != KeyRelease) {
logMessage(LOG_ERR,"keypress is not a KeyPress");
return;
}
keysym = XtGetActionKeysym(event, &modifiers);
modifiers |= my_modifiers;
logMessage(LOG_DEBUG,"keypress(%#lx), modif(%#x)", keysym, modifiers);
/* latin1 */
if (keysym < 0x100) keysym |= 0x1000000;
if ((keysym & 0x1f000000) == 0x1000000) {
/* unicode */
if ((keysym & ~UNICODE_CELL_MASK) == UNICODE_BRAILLE_ROW)
keypressed = BRL_CMD_BLK(PASSDOTS) | (keysym & 0xff);
else {
int c = convertWcharToChar(keysym & 0xffffff);
if (c == EOF) {
logMessage(LOG_DEBUG, "non translatable unicode U+%lx", keysym & 0xffffff);
return;
}
keypressed = BRL_CMD_BLK(PASSCHAR) | c;
}
}
else switch(keysym) {
case XK_Shift_L:
case XK_Shift_R: modifier = ShiftMask; goto modif;
case XK_Control_L:
case XK_Control_R: modifier = ControlMask; goto modif;
case XK_Alt_L:
case XK_Alt_R:
case XK_Meta_L:
case XK_Meta_R: modifier = Mod1Mask; goto modif;
case XK_KP_Enter:
case XK_Return: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_ENTER; break;
case XK_KP_Tab:
case XK_Tab: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_TAB; break;
case XK_BackSpace: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_BACKSPACE; break;
case XK_Escape: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_ESCAPE; break;
case XK_KP_Left:
case XK_Left: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_CURSOR_LEFT; break;
case XK_KP_Right:
case XK_Right: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_CURSOR_RIGHT; break;
case XK_KP_Up:
case XK_Up: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_CURSOR_UP; break;
case XK_KP_Down:
case XK_Down: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_CURSOR_DOWN; break;
case XK_KP_Page_Up:
case XK_Page_Up: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_PAGE_UP; break;
case XK_KP_Page_Down:
case XK_Page_Down: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_PAGE_DOWN; break;
case XK_KP_Home:
case XK_Home: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_HOME; break;
case XK_KP_End:
case XK_End: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_END; break;
case XK_KP_Insert:
case XK_Insert: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_INSERT; break;
case XK_KP_Delete:
case XK_Delete: keypressed = BRL_CMD_BLK(PASSKEY) | BRL_KEY_DELETE; break;
case XK_KP_F1:
case XK_F1: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 0); break;
case XK_KP_F2:
case XK_F2: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 1); break;
case XK_KP_F3:
case XK_F3: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 2); break;
case XK_KP_F4:
case XK_F4: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 3); break;
case XK_F5: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 4); break;
case XK_F6: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 5); break;
case XK_F7: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 6); break;
case XK_F8: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 7); break;
case XK_F9: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 8); break;
case XK_F10: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 9); break;
case XK_F11: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 10); break;
case XK_F12: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 11); break;
case XK_F13: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 12); break;
case XK_F14: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 13); break;
case XK_F15: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 14); break;
case XK_F16: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 15); break;
case XK_F17: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 16); break;
case XK_F18: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 17); break;
case XK_F19: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 18); break;
case XK_F20: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 19); break;
case XK_F21: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 20); break;
case XK_F22: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 21); break;
case XK_F23: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 22); break;
case XK_F24: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 23); break;
case XK_F25: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 24); break;
case XK_F26: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 25); break;
case XK_F27: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 26); break;
case XK_F28: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 27); break;
case XK_F29: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 28); break;
case XK_F30: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 29); break;
case XK_F31: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 30); break;
case XK_F32: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 31); break;
case XK_F33: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 32); break;
case XK_F34: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 33); break;
case XK_F35: keypressed = BRL_CMD_BLK(PASSKEY) | (BRL_KEY_FUNCTION + 34); break;
case XK_KP_Space: keypressed = BRL_CMD_BLK(PASSCHAR) | ' '; break;
case XK_KP_Equal: keypressed = BRL_CMD_BLK(PASSCHAR) | '='; break;
case XK_KP_Multiply: keypressed = BRL_CMD_BLK(PASSCHAR) | '*'; break;
case XK_KP_Add: keypressed = BRL_CMD_BLK(PASSCHAR) | '+'; break;
case XK_KP_Separator: keypressed = BRL_CMD_BLK(PASSCHAR) | ','; break;
case XK_KP_Subtract: keypressed = BRL_CMD_BLK(PASSCHAR) | '-'; break;
case XK_KP_Decimal: keypressed = BRL_CMD_BLK(PASSCHAR) | '.'; break;
case XK_KP_Divide: keypressed = BRL_CMD_BLK(PASSCHAR) | '/'; break;
case XK_KP_0: keypressed = BRL_CMD_BLK(PASSCHAR) | '0'; break;
case XK_KP_1: keypressed = BRL_CMD_BLK(PASSCHAR) | '1'; break;
case XK_KP_2: keypressed = BRL_CMD_BLK(PASSCHAR) | '2'; break;
case XK_KP_3: keypressed = BRL_CMD_BLK(PASSCHAR) | '3'; break;
case XK_KP_4: keypressed = BRL_CMD_BLK(PASSCHAR) | '4'; break;
case XK_KP_5: keypressed = BRL_CMD_BLK(PASSCHAR) | '5'; break;
case XK_KP_6: keypressed = BRL_CMD_BLK(PASSCHAR) | '6'; break;
case XK_KP_7: keypressed = BRL_CMD_BLK(PASSCHAR) | '7'; break;
case XK_KP_8: keypressed = BRL_CMD_BLK(PASSCHAR) | '8'; break;
case XK_KP_9: keypressed = BRL_CMD_BLK(PASSCHAR) | '9'; break;
default: logMessage(LOG_DEBUG,"unsupported keysym %lx",keysym); return;
}
if (modifiers & ControlMask) keypressed |= BRL_FLG_INPUT_CONTROL;
if (modifiers & Mod1Mask) keypressed |= BRL_FLG_INPUT_META;
if (modifiers & ShiftMask) keypressed |= BRL_FLG_INPUT_SHIFT;
if (modifiers & LockMask) keypressed |= BRL_FLG_INPUT_UPPER;
if (event->type != KeyPress) keypressed = BRL_CMD_NOOP;
logMessage(LOG_DEBUG,"keypressed %#lx", keypressed);
enqueueCommand(keypressed);
return;
modif:
logMessage(LOG_DEBUG,"modifier %#x", modifier);
if (event->type == KeyPress)
my_modifiers |= modifier;
else
my_modifiers &= ~modifier;
}
static void route(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
int index = atoi(params[0]);
logMessage(LOG_DEBUG,"route(%u)", index);
if (event->xbutton.state & ControlMask) {
enqueueCommand(BRL_CMD_BLK(CLIP_NEW) | (index&BRL_MSK_ARG));
} else if (event->xbutton.state & Mod1Mask) {
enqueueCommand(BRL_CMD_BLK(COPY_LINE) | (index&BRL_MSK_ARG));
} else {
enqueueCommand(BRL_CMD_BLK(ROUTE) | (index&BRL_MSK_ARG));
}
}
static void quit(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
XtAppSetExitFlag(app_con);
}
#endif /* USE_XT */
static inline Widget crKeyBut(char *name, long keycode, int repeat,
int horizDistance, int vertDistance)
{
Widget button;
#if defined(USE_XT)
button = XtVaCreateManagedWidget(name,
repeat?repeaterWidgetClass:commandWidgetClass, keybox,
XtNwidth, BUTWIDTH, XtNheight, BUTHEIGHT,
#ifdef USE_XAW
XtNinitialDelay, 500, XtNminimumDelay, 100,
#endif /* USE_XAW */
NhorizDistance, horizDistance,
NvertDistance, vertDistance,
Ntop, ChainTop,
Nbottom, ChainBottom,
Nleft, ChainLeft,
Nright, ChainRight,
NULL);
XtAddCallback(button, Ncallback, KeyPressCB, (XtPointer) keycode);
#elif defined(USE_WINDOWS)
button = CreateWindow(WC_BUTTON, name, WS_CHILD | WS_VISIBLE, horizDistance, totlines*CHRY+1+vertDistance, BUTWIDTH, BUTHEIGHT, toplevel, NULL, NULL, NULL);
SetWindowLongPtr(button, GWLP_USERDATA, (LONG_PTR) keycode);
#else /* USE_ */
#error Toolkit button creation unspecified
#endif /* USE_ */
return button;
}
struct button {
char *label;
long keycode;
int repeat;
int x,y;
};
struct model {
const char *name;
struct button *buttons;
int width,height;
};
static const struct model *keyModel;
static struct button buttons_simple[] = {
{ "Dot1", BRL_CMD_BLK(PASSDOTS) | BRL_DOT1 , 0, 0, 0 },
{ "Dot2", BRL_CMD_BLK(PASSDOTS) | BRL_DOT2 , 0, 0, 1 },
{ "Dot3", BRL_CMD_BLK(PASSDOTS) | BRL_DOT3 , 0, 0, 2 },
{ "Dot4", BRL_CMD_BLK(PASSDOTS) | BRL_DOT4 , 0, 1, 0 },
{ "Dot5", BRL_CMD_BLK(PASSDOTS) | BRL_DOT5 , 0, 1, 1 },
{ "Dot6", BRL_CMD_BLK(PASSDOTS) | BRL_DOT6 , 0, 1, 2 },
{ "Dot7", BRL_CMD_BLK(PASSDOTS) | BRL_DOT7 , 0, 0, 3 },
{ "Dot8", BRL_CMD_BLK(PASSDOTS) | BRL_DOT8 , 0, 1, 3 },
{ "`", BRL_CMD_TOP_LEFT, 0, 3, 0 },
{ "^", BRL_CMD_LNUP, 1, 4, 0 },
{ "Paste", BRL_CMD_PASTE, 0, 5, 0 },
{ "<", BRL_CMD_FWINLT, 1, 3, 1 },
{ "Home", BRL_CMD_HOME, 0, 4, 1 },
{ ">", BRL_CMD_FWINRT, 1, 5, 1 },
{ "<=", BRL_CMD_FWINLTSKIP, 0, 3, 2 },
{ "v", BRL_CMD_LNDN, 1, 4, 2 },
{ "=>", BRL_CMD_FWINRTSKIP, 0, 5, 2 },
{ "alt-c", BRL_FLG_INPUT_META | BRL_CMD_BLK(PASSCHAR) | 'c', 0, 3, 3 },
{ "ctrl-c", BRL_FLG_INPUT_CONTROL | BRL_CMD_BLK(PASSCHAR) | 'c', 0, 4, 3 },
{ "a", BRL_CMD_BLK(PASSCHAR) | 'a', 0, 5, 3 },
{ "A", BRL_CMD_BLK(PASSCHAR) | 'A', 0, 6, 3 },
{ "Alt-F1", BRL_FLG_INPUT_META | BRL_KEY_FUNCTION | BRL_CMD_BLK(PASSKEY) , 0, 7, 3 },
{ "Frez", BRL_CMD_FREEZE, 0, 6, 0 },
{ "Bksp", BRL_CMD_KEY(BACKSPACE), 0, 6, 1 },
{ "Help", BRL_CMD_HELP, 0, 7, 0 },
{ "Pref", BRL_CMD_PREFMENU, 0, 7, 1 },
{ "PL", BRL_CMD_PREFLOAD, 0, 6, 2 },
{ "PS", BRL_CMD_PREFSAVE, 0, 7, 2 },
{ NULL, 0, 0, 0, 0},
};
static struct button buttons_vs[] = {
/*
{ "VT1", BRL_CMD_BLK(SWITCHVT)+0, 1, 0, 1 },
{ "VT2", BRL_CMD_BLK(SWITCHVT)+1, 1, 1, 1 },
{ "VT3", BRL_CMD_BLK(SWITCHVT)+2, 1, 2, 1 },
{ "VT4", BRL_CMD_BLK(SWITCHVT)+3, 1, 6, 1 },
{ "VT5", BRL_CMD_BLK(SWITCHVT)+4, 1, 7, 1 },
{ "VT6", BRL_CMD_BLK(SWITCHVT)+5, 1, 8, 1 },
*/
//{ "B5", EOF, /* cut */ 1, 5, 2 },
{ "TOP", BRL_CMD_TOP_LEFT, 1, 6, 2 },
{ "BOT", BRL_CMD_BOT_LEFT, 1, 6, 4 },
{ "<=", BRL_CMD_FWINLTSKIP, 1, 1, 0 },
{ "<=", BRL_CMD_FWINLTSKIP, 1, 8, 2 },
{ "=>", BRL_CMD_FWINRTSKIP, 1, 2, 0 },
{ "=>", BRL_CMD_FWINRTSKIP, 1, 8, 4 },
{ "-^-", BRL_CMD_LNUP, 1, 7, 2 },
{ "-v-", BRL_CMD_LNDN, 1, 7, 4 },
{ "->", BRL_CMD_FWINRT, 1, 8, 3 },
{ "<-", BRL_CMD_FWINLT, 1, 6, 3 },
{ "HOME", BRL_CMD_HOME, 1, 7, 3 },
{ "^", BRL_CMD_KEY(CURSOR_UP), 1, 1, 2 },
{ "v", BRL_CMD_KEY(CURSOR_DOWN), 1, 1, 4 },
{ ">", BRL_CMD_KEY(CURSOR_RIGHT), 1, 2, 3 },
{ "<", BRL_CMD_KEY(CURSOR_LEFT), 1, 0, 3 },
//{ "B3", BRL_CMD_CSRVIS, 1, 2, 2 },
{ "DEL", BRL_CMD_KEY(DELETE), 1, 0, 4 },
{ "INS", BRL_CMD_KEY(INSERT), 1, 2, 4 },
//{ "C5", BRL_CMD_PASTE, 1, 5, 3 },
//{ "D5", EOF, 1, 5, 4 },
//{ "B4", EOF, 1, 3, 2 },
//{ "B1", EOF, 1, 0, 2 },
//{ "C2", EOF, 1, 1, 3 },
//{ "C4", EOF, 1, 3, 3 },
//{ "D4", EOF, 1, 3, 4 },
{ NULL, 0, 0, 0, 0},
};
static const struct model models[] = {
{ "normal", buttons_simple, 4, 4 },
{ "vs", buttons_vs, 9, 5 },
};
static void setModel(Widget w, XtPointer closure, XtPointer data)
{
intptr_t newModel = (intptr_t) closure;
if (newModel == XtNumber(models))
keyModel = NULL;
else
keyModel = &models[newModel];
regenerate = 1;
}
static void createKeyButtons(struct button *buttons) {
struct button *b;
for (b=buttons; b->label; b++)
crKeyBut(b->label, b->keycode, b->repeat, b->x*(BUTWIDTH+1), b->y*(BUTHEIGHT+1));
}
struct radioInt {
const char *name;
int value;
};
static const struct radioInt colsRadio [] = {
{ "80", 80 },
{ "60", 60 },
{ "40", 40 },
{ "20", 20 },
{ "8", 8 },
};
static struct radioInt linesRadio [] = {
{ "3", 3 },
{ "2", 2 },
{ "1", 1 },
};
static void setWidth(Widget w, XtPointer closure, XtPointer data)
{
intptr_t newCols = (intptr_t) closure;
cols = newCols;
regenerate = 1;
}
static void setHeight(Widget w, XtPointer closure, XtPointer data)
{
intptr_t newLines = (intptr_t) closure;
lines = newLines;
regenerate = 1;
}
typedef void (*actionfun_t)(Widget, XtPointer, XtPointer);
enum actions {
SETMODEL,
SETWIDTH,
SETHEIGHT,
};
static actionfun_t actionfun[] = {
[SETMODEL] = setModel,
[SETWIDTH] = setWidth,
[SETHEIGHT] = setHeight,
};
#if defined(USE_XT)
#define SET_ACTION(cb, set) \
(cb)[0].callback = (XtCallbackProc) actionfun[set]
#define SET_VALUE(cb, value) \
(cb)[0].closure = (void*)(intptr_t) (value)
#elif defined(USE_WINDOWS)
#define SET_ACTION(cb, set) \
(cb) = (set) << 8
#define SET_VALUE(cb, value) \
(cb) = ((cb) & (~0xff)) | (value)
#define GET_ACTIONFUN(cbint) \
actionfun[(cbint) >> 8]
#define GET_VALUE(cbint) \
((cbint) & 0xff)
#else /* USE_ */
#error Toolkit callback recording unspecified
#endif /* USE_ */
#ifdef USE_WINDOWS
static LRESULT CALLBACK wndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (uMsg == WM_COMMAND) {
long keypressed;
hwnd = GET_WM_COMMAND_HWND(wParam, lParam);
keypressed = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (keypressed) {
enqueueCommand(keypressed);
} else {
/* menu entry */
GET_ACTIONFUN(wParam)(NULL, (XtPointer)(GET_VALUE(wParam)), NULL);
}
return 0;
}
if (uMsg == WM_CONTEXTMENU) {
TrackPopupMenu(menu, TPM_LEFTALIGN|TPM_RIGHTBUTTON, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0, toplevel, NULL);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
#define BRAILLE_USB 82
int CALLBACK fontEnumProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, DWORD FontType, LPARAM lParam) {
int shift = 8*sizeof(lpntme->ntmFontSig.fsUsb[0]);
if (!(lpntme->ntmFontSig.fsUsb[BRAILLE_USB / shift] &
(1 << (BRAILLE_USB % shift))))
return 1;
font = CreateFont(CHRY-6, CHRX-4, 0, 0, 0, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, (LPCTSTR) lpelfe->elfFullName);
if (!font) {
logWindowsSystemError("Couldn't load font");
logMessage(LOG_ERR,"font %s", lpelfe->elfFullName);
return 1;
}
logMessage(LOG_INFO, "Using braille font `%s\'",lpelfe->elfFullName);
return 0;
}
#endif /* USE_WINDOWS */
static int brl_readCommand(BrailleDisplay *brl, KeyTableCommandContext context)
{
#if defined(USE_XT)
while (XtAppPending(app_con)) {
XtAppProcessEvent(app_con,XtIMAll);
if (XtAppGetExitFlag(app_con))
raise(SIGTERM);
#elif defined(USE_WINDOWS)
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT
|| msg.message == WM_DESTROY
|| msg.message == WM_CLOSE)
raise(SIGTERM);
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
#else /* USE_ */
#error Toolkit loop unspecified
#endif /* USE_ */
if (regenerate) {
regenerate = 0;
destroyToplevel();
generateToplevel();
brl->textColumns = cols;
brl->textRows = lines;
brl->resizeRequired = 1;
}
}
return EOF;
}
#ifdef USE_XT
static char *fallback_resources[] = {
"*display.background: lightgreen",
#ifdef USE_XAW
"*displayb.background: black",
"*displayb.foreground: white",
#endif /* USE_XAW */
"*keybox.background: lightgrey",
"*menu.Label: Brltty",
"*menu.background: lightgrey",
NULL
};
#endif /* USE_XT */
#ifdef USE_XM
static void popup(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
Widget shell = XtParent(menu);
XmMenuPosition(menu, &event->xbutton);
XtManageChild(menu);
XtPopup(shell, XtGrabNone);
}
#endif /* USE_XM */
static int generateToplevel(void)
{
#ifdef USE_XT
int argc;
char **argv;
#ifdef USE_XAW
char *def_string_return;
char **missing_charset_list_return;
int missing_charset_count_return;
#endif /* USE_XAW */
XtActionsRec actions [] = {
{ "route", route },
{ "keypress", keypress },
#ifdef USE_XM
{ "popup", popup },
#endif /* USE_XM */
{ "Quit", quit },
};
char translations[] = "<Message>WM_PROTOCOLS: Quit()";
char inputActions[] = "\
:<Key>: keypress()\n\
:<KeyUp>: keypress()\n";
char popupAction[] =
"None<Btn3Down>: "
#if defined(USE_XAW)
"XawPositionSimpleMenu(menu) MenuPopup(menu)"
#elif defined(USE_XM)
"popup()"
#endif /* USE_ */
"\n";
Widget tmp_vbox;
char *disp;
#ifdef USE_XAW
char *dispb;
#endif /* USE_XAW */
XtCallbackRec cb[2] = { { NULL, NULL }, { NULL, NULL } };
#endif /* USE_XT */
#ifdef USE_WINDOWS
UINT cb = 0;
#endif /* USE_WINDOWS */
const struct radioInt *radioInt;
const struct model *radioModel;
int y,x;
#if defined(USE_XT)
argc = xtArgc;
if ((argv = malloc((xtArgc + 1) * sizeof(*xtArgv)))) {
memcpy(argv, xtArgv, (xtArgc + 1) * sizeof(*xtArgv));
/* toplevel */
toplevel = XtVaOpenApplication(&app_con, "Brltty",
NULL, 0,
&argc, argv, fallback_resources,
sessionShellWidgetClass,
XtNallowShellResize, True,
XtNinput, input ? True : False,
NULL);
XtAppAddActions(app_con,actions,XtNumber(actions));
XtOverrideTranslations(toplevel,XtParseTranslationTable(translations));
free(argv);
} else {
logMallocError();
toplevel = NULL;
}
#elif defined(USE_WINDOWS)
{
HWND root = GetDesktopWindow();
HDC hdc = GetDC(root);
EnumFontFamiliesEx(hdc, NULL, (void*) fontEnumProc, 0, 0);
ReleaseDC(root, hdc);
if (!font) {
logMessage(LOG_ERR,"Error while loading braille font");
totlines = lines;
} else {
totlines = 2*lines;
}
}
{
WNDCLASS wndclass = {
.style = 0,
.lpfnWndProc = wndProc,
.cbClsExtra = 0,
.cbWndExtra = 0,
.hInstance = NULL,
.hIcon = LoadIcon(NULL, IDI_APPLICATION), /* TODO: nice icon */
.hCursor = LoadCursor(NULL, IDC_ARROW),
.hbrBackground = NULL,
.lpszMenuName = NULL,
.lpszClassName = "BRLTTYWClass",
};
if (!(RegisterClass(&wndclass)) &&
GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
logWindowsSystemError("RegisterClass");
if (font) {
DeleteObject(font);
font = NULL;
}
return 0;
}
modelWidth = cols*CHRX;
if (keyModel) {
if (keyModel->width*(BUTWIDTH+1)+1 > modelWidth)
modelWidth = keyModel->width *(BUTWIDTH +1)-1;
modelHeight = keyModel->height*(BUTHEIGHT+1);
} else {
modelHeight = 0;
}
if (!(toplevel = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
"BRLTTYWClass", "BRLTTY",
WS_POPUP, GetSystemMetrics(SM_CXSCREEN)-modelWidth-RIGHTMARGIN, 0,
modelWidth, totlines*CHRY+modelHeight, NULL, NULL, NULL, NULL))) {
logWindowsSystemError("CreateWindow");
if (font) {
DeleteObject(font);
font = NULL;
}
return 0;
}
}
#else /* USE_ */
#error Toolkit toplevel creation unspecified
#endif /* USE_ */
/* vertical separation */
#ifdef USE_XT
vbox = XtVaCreateManagedWidget("vbox",panedWidgetClass,toplevel,
#ifdef USE_XM
XmNmarginHeight, 0,
XmNmarginWidth, 0,
XmNspacing, 1,
#endif /* USE_XM */
XtNresize, True,
XtNtranslations, XtParseTranslationTable(popupAction),
NULL);
if (input)
XtAugmentTranslations(vbox, XtParseTranslationTable(inputActions));
#endif /* USE_XT */
#ifdef USE_XAW
if (!(fontset = XCreateFontSet(XtDisplay(toplevel), fontname, &missing_charset_list_return, &missing_charset_count_return, &def_string_return)))
logMessage(LOG_ERR,"Error while loading unicode font");
if (missing_charset_count_return) {
int i;
for (i=0; i<missing_charset_count_return; i++)
logMessage(LOG_INFO,"Could not load a unicode font for charset %s",missing_charset_list_return[i]);
XFreeStringList(missing_charset_list_return);
}
#endif /* USE_XAW */
#ifdef USE_XT
/* horizontal separation */
hbox = XtVaCreateManagedWidget("hbox",panedWidgetClass,vbox,
XtNorientation, XtEhorizontal,
#ifdef USE_XM
XmNmarginHeight, 0,
XmNmarginWidth, 0,
XmNspacing, 0,
#endif /* USE_XM */
#ifdef USE_XAW
XtNshowGrip,False,
#else /* USE_XAW */
XmNpaneMaximum,20*lines,
XmNpaneMinimum,20*lines,
XmNskipAdjust, True,
#endif /* USE_XAW */
XtNresize, True,
NULL);
/* display Label */
disp=XtMalloc(2);
disp[0]=' ';
disp[1]=0;
#ifdef USE_XAW
dispb=XtMalloc(4);
dispb[0]=0xe0|((0x28>>4)&0x0f);
dispb[1]=0x80|((0x28<<2)&0x3f);
dispb[2]=0x80;
dispb[3]=0;
#endif /* USE_XAW */
#ifdef USE_XM
display_cs = XmStringCreateLocalized(disp);
#endif /* USE_XM */
#endif /* USE_XT */
#ifdef USE_WINDOWS
hbox = CreateWindow(WC_STATIC, "", WS_CHILD | WS_VISIBLE, 0, 0,
modelWidth, totlines*CHRY+modelHeight, toplevel, NULL, NULL, NULL);
#endif /* USE_WINDOWS */
for (x=0;x<cols;x++) {
#ifdef USE_XT
/* vertical separation */
tmp_vbox = XtVaCreateManagedWidget("tmp_vbox",panedWidgetClass,hbox,
#ifdef USE_XAW
XtNshowGrip,False,
#else /* USE_XAW */
XmNpaneMaximum,20,
XmNpaneMinimum,20,
XmNskipAdjust, True,
#endif /* USE_XAW */
#ifdef USE_XM
XmNmarginHeight, 0,
XmNmarginWidth, 0,
XmNspacing, 0,
#endif /* USE_XM */
XtNresize, True,
NULL);
#endif /* USE_XT */
for (y=0;y<lines;y++) {
#if defined(USE_XT)
char action[] = "<Btn1Up>: route(100)";
XtTranslations transl;
snprintf(action,sizeof(action),"<Btn1Up>: route(%u)",y*cols+x);
transl = XtParseTranslationTable(action);
display[y*cols+x] = XtVaCreateManagedWidget("display",labelWidgetClass,tmp_vbox,
XtNtranslations, transl,
#ifdef USE_XAW
XtNshowGrip,False,
XtNinternational, True,
#else /* USE_XAW */
XmNpaneMaximum,20,
XmNpaneMinimum,20,
XmNskipAdjust, True,
#endif /* USE_XAW */
#ifdef USE_XAW
XtNlabel, disp,
fontset ? XNFontSet : NULL, fontset, NULL
#else /* USE_XAW */
XmNlabelString, display_cs, NULL
#endif /* USE_XAW */
);
#ifdef USE_XAW
if (fontset) {
displayb[y*cols+x] = XtVaCreateManagedWidget("displayb",labelWidgetClass,tmp_vbox,
XtNtranslations, transl,
XtNinternational, True,
XNFontSet, fontset,
XtNshowGrip,False,
XtNlabel, dispb,
NULL);
}
#endif /* USE_XAW */
#elif defined(USE_WINDOWS)
display[y*cols+x] = CreateWindow(WC_BUTTON, " ", WS_CHILD | WS_VISIBLE | BS_CHECKBOX | BS_PUSHLIKE, x*CHRX, y*CHRY, CHRX, CHRY, toplevel, NULL, NULL, NULL);
SetWindowLongPtr(display[y*cols+x], GWLP_USERDATA, (LONG_PTR) (BRL_CMD_BLK(ROUTE) | ((y*cols+x)&BRL_MSK_ARG)));
if (font) {
displayb[y*cols+x] = CreateWindowW(WC_BUTTONW, WS_C(" "), WS_CHILD | WS_VISIBLE | BS_CHECKBOX | BS_PUSHLIKE, x*CHRX, (lines+y)*CHRY, CHRX, CHRY, toplevel, NULL, NULL, NULL);
SetWindowLongPtr(displayb[y*cols+x], GWLP_USERDATA, (LONG_PTR) (BRL_CMD_BLK(ROUTE) | ((y*cols+x)&BRL_MSK_ARG)));
SendMessage(displayb[y*cols+x], WM_SETFONT, (WPARAM) font, TRUE);
}
#else /* USE_ */
#error Toolkit display unspecified
#endif /* USE_ */
}
}
#ifdef USE_XT
#ifdef USE_XM
XmStringFree(display_cs);
#endif /* USE_XM */
XtFree(disp);
#ifdef USE_XAW
XtFree(dispb);
#endif /* USE_XAW */
#endif /* USE_XT */
#ifdef USE_XT
XtVaGetValues(display[0],
XtNforeground, &displayForeground,
XtNbackground, &displayBackground,
NULL);
#endif /* USE_XT */
if (keyModel) {
/* key box */
#ifdef USE_XT
keybox = XtVaCreateManagedWidget("keybox",formWidgetClass,vbox,
#ifdef USE_XAW
XtNdefaultDistance,0,
#endif /* USE_XAW */
NULL);
#endif /* USE_XT */
createKeyButtons(keyModel->buttons);
}
menu = CreatePopupMenu("menu", toplevel);
#ifdef USE_XAW
if (!check) {
static unsigned char checkimg [] = {
0x00, 0x00, 0xc0, 0x60, 0x33, 0x1e, 0x0c, 0x00
};
check = XCreateBitmapFromData(XtDisplay(toplevel),
RootWindowOfScreen(XtScreen(toplevel)), (char *) checkimg, 8, 8);
}
#endif /* USE_XAW */
#ifdef USE_XAW
AddMenuSeparator("WidthLine", menu);
#endif /* USE_XAW */
AddMenuLabel("Width", menu);
SET_ACTION(cb, SETWIDTH);
for (radioInt = colsRadio; radioInt < &colsRadio[XtNumber(colsRadio)]; radioInt++) {
SET_VALUE(cb, radioInt->value);
AddMenuRadio(radioInt->name, menu, cb, radioInt->value == cols);
}
AddMenuSeparator("HeightLine", menu);
AddMenuLabel("Height", menu);
SET_ACTION(cb, SETHEIGHT);
for (radioInt = linesRadio; radioInt < &linesRadio[XtNumber(linesRadio)]; radioInt++) {
SET_VALUE(cb, radioInt->value);
AddMenuRadio(radioInt->name, menu, cb, radioInt->value == lines);
}
AddMenuSeparator("ModelLine", menu);
AddMenuLabel("Model", menu);
SET_ACTION(cb, SETMODEL);
for (radioModel = models; radioModel < &models[XtNumber(models)]; radioModel++) {
SET_VALUE(cb, radioModel-models);
AddMenuRadio(radioModel->name, menu, cb, radioModel == keyModel);
}
SET_VALUE(cb, XtNumber(models));
AddMenuRadio("bare", menu, cb, !keyModel);
/* go go go */
#if defined(USE_XT)
XtRealizeWidget(toplevel);
if (!wm_delete_window)
wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", False);
XSetWMProtocols(XtDisplay(toplevel),XtWindow(toplevel),&wm_delete_window,1);
#elif defined(USE_WINDOWS)
ShowWindow(toplevel, SW_SHOWDEFAULT);
UpdateWindow(toplevel);
#else /* USE_ */
#error Toolkit toplevel realization unspecified
#endif /* USE_ */
#if defined(USE_XAW) || defined(USE_WINDOWS)
memset(displayedWindow,0,sizeof(displayedWindow));
#endif /* USE_XAW || USE_WINDOWS */
memset(displayedVisual,0,sizeof(displayedVisual));
lastcursor = BRL_NO_CURSOR;
return 1;
}
static int brl_construct(BrailleDisplay *brl, char **parameters, const char *device)
{
lines=1;
if (*parameters[PARM_LINES]) {
static const int minimum = 1;
static const int maximum = MAXLINES;
int value;
if (validateInteger(&value, parameters[PARM_LINES], &minimum, &maximum)) {
lines=value;
} else {
logMessage(LOG_WARNING, "%s: %s", "invalid line count", parameters[PARM_LINES]);
}
}
cols=40;
if (*parameters[PARM_COLUMNS]) {
static const int minimum = 1;
static const int maximum = MAXCOLS;
int value;
if (validateInteger(&value, parameters[PARM_COLUMNS], &minimum, &maximum)) {
cols=value;
} else {
logMessage(LOG_WARNING, "%s: %s", "invalid column count", parameters[PARM_COLUMNS]);
}
}
if (*parameters[PARM_INPUT]) {
unsigned int value;
if (validateOnOff(&value, parameters[PARM_INPUT])) {
input = value;
} else {
logMessage(LOG_WARNING, "%s: %s", "invalid input setting", parameters[PARM_INPUT]);
}
}
if (*parameters[PARM_TKPARMS]) {
int reallocated = 0;
{
int count;
char **args1 = splitString(parameters[PARM_TKPARMS], ' ', &count);
if (args1) {
char **args2 = realloc(args1, (count+2) * sizeof(char *));
if (args2) {
char *name = strdup(xtDefArgv[0]);
args1 = NULL;
if (name) {
memmove(args2+1, args2, (count+1) * sizeof(char *));
args2[0] = name;
count += 1;
if (xtArgv != xtDefArgv) deallocateStrings(xtArgv);
xtArgv = args2;
xtArgc = count;
args2 = NULL;
reallocated = 1;
} else {
logMallocError();
}
if (args2) deallocateStrings(args2);
} else {
logMallocError();
}
if (args1) deallocateStrings(args1);
}
}
if (!reallocated) return 0;
}
if (*parameters[PARM_MODEL]) {
model = parameters[PARM_MODEL];
for (keyModel = models; keyModel < &models[XtNumber(models)] && strcmp(keyModel->name,model); keyModel++);
if (keyModel == &models[XtNumber(models)]) keyModel = NULL;
}
if (*parameters[PARM_FONT]) {
fontname = parameters[PARM_FONT];
}
#if defined(USE_XT)
XtToolkitThreadInitialize();
XtSetLanguageProc(NULL, NULL, NULL);
#endif /* USE_XT */
brl->textColumns=cols;
brl->textRows=lines;
return generateToplevel();
}
static void destroyToplevel(void)
{
#if defined(USE_XT)
#ifdef USE_XAW
if (fontset) {
XFreeFontSet(XtDisplay(toplevel),fontset);
fontset = NULL;
}
check = None;
#endif /* USE_XAW */
XtDestroyApplicationContext(app_con);
app_con = NULL;
#elif defined(USE_WINDOWS)
DestroyMenu(menu);
if (!DestroyWindow(toplevel))
logWindowsSystemError("DestroyWindow");
if (font) {
DeleteObject(font);
font = NULL;
}
#else /* USE_ */
#error Toolkit toplevel destruction unspecified
#endif /* USE_ */
}
static void brl_destruct(BrailleDisplay *brl)
{
destroyToplevel();
}
static int brl_writeWindow(BrailleDisplay *brl, const wchar_t *text)
{
unsigned int from, to;
wchar_t wc;
int i;
#ifdef USE_XM
char data[2];
#elif defined(USE_XAW)
Utf8Buffer utf8;
#elif defined(USE_WINDOWS)
wchar_t data[3];
#endif
if (lastcursor != brl->cursor) {
if (lastcursor != BRL_NO_CURSOR) {
#if defined(USE_XT)
XtVaSetValues(display[lastcursor],
XtNforeground, displayForeground,
XtNbackground, displayBackground,
NULL);
#elif defined(USE_WINDOWS)
SendMessage(display[lastcursor],BM_SETSTATE,FALSE,0);
#else /* USE_ */
#error Toolkit cursor not specified
#endif /* USE_ */
}
lastcursor = brl->cursor;
if (lastcursor != BRL_NO_CURSOR) {
#if defined(USE_XT)
XtVaSetValues(display[lastcursor],
XtNforeground, displayBackground,
XtNbackground, displayForeground,
NULL);
#elif defined(USE_WINDOWS)
SendMessage(display[lastcursor],BM_SETSTATE,TRUE,0);
#else /* USE_ */
#error Toolkit cursor not specified
#endif /* USE_ */
}
}
if (text && wmemcmp(text,displayedVisual,brl->textRows*brl->textColumns)) {
for (i=0;i<brl->textRows*brl->textColumns;i++) {
if (displayedVisual[i] != text[i]) {
wc = text[i];
if (wc == 0) wc = WC_C(' ');
#ifdef USE_XM
if (wc < 0x100)
data[0] = wc;
else
data[0] = '?';
data[1] = 0;
#elif defined(USE_XAW)
convertWcharToUtf8(wc, utf8);
#elif defined(USE_WINDOWS)
data[0] = wc;
if (data[0]==WC_C('&')) {
data[1] = WC_C('&');
data[2] = 0;
} else
data[1]=0;
#else /* USE_ */
#error Toolkit cursor not specified
#endif /* USE_ */
#if defined(USE_XT)
#ifdef USE_XM
display_cs = XmStringCreateLocalized(data);
#endif /* USE_XM */
XtVaSetValues(display[i],
#ifdef USE_XAW
XtNlabel, utf8,
#else /* USE_XAW */
XmNlabelString, display_cs,
#endif /* USE_XAW */
NULL);
#ifdef USE_XM
XmStringFree(display_cs);
#endif /* USE_XM */
#elif defined(USE_WINDOWS)
SetWindowTextW(display[i],data);
#else /* USE_ */
#error Toolkit display refresh unspecified
#endif /* USE_ */
displayedVisual[i] = text[i];
}
}
}
#if defined(USE_XAW) || defined(USE_WINDOWS)
if (!cellsHaveChanged(displayedWindow,brl->buffer,brl->textRows*brl->textColumns,&from,&to,NULL) || !displayb[0]) return 1;
for (i=from;i<to;i++) {
unsigned char c = brl->buffer[i];
c =
(!!(c&BRL_DOT1))<<0
|(!!(c&BRL_DOT2))<<1
|(!!(c&BRL_DOT3))<<2
|(!!(c&BRL_DOT4))<<3
|(!!(c&BRL_DOT5))<<4
|(!!(c&BRL_DOT6))<<5
|(!!(c&BRL_DOT7))<<6
|(!!(c&BRL_DOT8))<<7;
#ifdef USE_XAW
convertWcharToUtf8(UNICODE_BRAILLE_ROW | c, utf8);
XtVaSetValues(displayb[i], XtNlabel, utf8, NULL);
#elif defined(USE_WINDOWS)
data[0] = UNICODE_BRAILLE_ROW | c;
data[1] = 0;
SetWindowTextW(displayb[i],data);
#endif /* USE_WINDOWS */
}
#endif /* USE_XAW || USE_WINDOWS */
return 1;
}