home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
tk42r2s.zip
/
tk4.2
/
os2
/
tkOS2X.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-07-27
|
36KB
|
1,266 lines
/*
* tkOS2X.c --
*
* This file contains OS/2 PM emulation procedures for X routines.
*
* Copyright (c) 1996-1998 Illya Vaes
* Copyright (c) 1995 Sun Microsystems, Inc.
* Copyright (c) 1994 Software Research Associates, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tkInt.h"
#include "tkOS2Int.h"
/*
* The following declaration is a special purpose backdoor into the
* Tcl notifier. It is used to process events on the Tcl event queue,
* without reentering the system event queue.
*/
extern void TclOS2FlushEvents _ANSI_ARGS_((void));
/*
* Declarations of static variables used in this file.
*/
static Display *os2Display; /* Display that represents OS/2 PM screen. */
Tcl_HashTable windowTable;
/* Table of child windows indexed by handle. */
static char os2ScreenName[] = "PM:0";
/* Default name of OS2 display. */
static isInModal = 0; /* True if TK has entered a modal loop */
/*
* Forward declarations of procedures used in this file.
*/
static void DeleteWindow _ANSI_ARGS_((HWND hwnd));
static void TranslateEvent (HWND hwnd, ULONG message,
MPARAM param1, MPARAM param2);
/*
*----------------------------------------------------------------------
*
* TkGetServerInfo --
*
* Given a window, this procedure returns information about
* the window server for that window. This procedure provides
* the guts of the "winfo server" command.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
TkGetServerInfo(interp, tkwin)
Tcl_Interp *interp; /* The server information is returned in
* this interpreter's result. */
Tk_Window tkwin; /* Token for window; this selects a
* particular display and server. */
{
char buffer[50];
ULONG info[QSV_MAX]= {0}; /* System Information Data Buffer */
APIRET rc;
/* Request all available system information */
rc= DosQuerySysInfo (1L, QSV_MAX, (PVOID)info, sizeof(info));
/* Hack for OS/2-versions above 2.11 */
if (info[QSV_VERSION_MINOR - 1] > 11) {
int major = (int) (info[QSV_VERSION_MINOR - 1] / 10);
sprintf(buffer, "%s %d.%d", "OS/2", major,
(int) (info[QSV_VERSION_MINOR - 1] - major * 10));
} else {
sprintf(buffer, "%s %d.%d", "OS/2",
(int)(info[QSV_VERSION_MINOR - 1] / 10),
(int)info[QSV_VERSION_MINOR - 1]);
}
Tcl_AppendResult(interp, buffer, (char *) NULL);
}
/*
*----------------------------------------------------------------------
*
* TkOS2GetTkModule --
*
* This function returns the module handle for the Tk DLL.
*
* Results:
* Returns the library module handle.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
HMODULE
TkOS2GetTkModule()
{
return dllHandle;
}
/*
*----------------------------------------------------------------------
*
* TkOS2GetAppInstance --
*
* Retrieves the global application instance handle.
*
* Results:
* Returns the global application instance handle.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
HAB
TkOS2GetAppInstance()
{
return hab;
}
/*
*----------------------------------------------------------------------
*
* TkOS2XInit --
*
* Initialize Xlib emulation layer.
*
* Results:
* None.
*
* Side effects:
* Sets up various data structures.
*
*----------------------------------------------------------------------
*/
void
TkOS2XInit( hInstance )
HAB hInstance;
{
BOOL success;
static initialized = 0;
if (initialized != 0) {
return;
}
initialized = 1;
/*
* Register the Child window class.
*/
/*
* Don't use CS_SIZEREDRAW for the child, this will make vertical resizing
* work incorrectly (keeping the same distance from the bottom instead of
* from the top when using Tk's "pack ... -side top").
*/
success = WinRegisterClass(hab, TOC_CHILD, TkOS2ChildProc, 0,
sizeof(ULONG));
if (!success) {
panic("Unable to register TkChild class");
}
}
/*
*----------------------------------------------------------------------
*
* TkGetDefaultScreenName --
*
* Returns the name of the screen that Tk should use during
* initialization.
*
* Results:
* Returns a statically allocated string.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
char *
TkGetDefaultScreenName(interp, screenName)
Tcl_Interp *interp; /* Not used. */
char *screenName; /* If NULL, use default string. */
{
char *DISPLAY = NULL;
if ((screenName == NULL) || (screenName[0] == '\0')) {
DISPLAY = getenv("DISPLAY");
if (DISPLAY != NULL) {
screenName = DISPLAY;
} else {
screenName = os2ScreenName;
}
}
return screenName;
}
/*
*----------------------------------------------------------------------
*
* XOpenDisplay --
*
* Create the Display structure and fill it with device
* specific information.
*
* Results:
* Returns a Display structure on success or NULL on failure.
*
* Side effects:
* Allocates a new Display structure.
*
*----------------------------------------------------------------------
*/
Display *
XOpenDisplay(display_name)
_Xconst char *display_name;
{
Screen *screen;
TkOS2Drawable *todPtr;
TkOS2PointerInit();
Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS);
if (os2Display != NULL) {
if (strcmp(os2Display->display_name, display_name) == 0) {
return os2Display;
} else {
return NULL;
}
}
os2Display = (Display *) ckalloc(sizeof(Display));
if (!os2Display) {
return (Display *)None;
}
os2Display->display_name = (char *) ckalloc(strlen(display_name)+1);
if (!os2Display->display_name) {
ckfree((char *)os2Display);
return (Display *)None;
}
strcpy(os2Display->display_name, display_name);
os2Display->cursor_font = 1;
os2Display->nscreens = 1;
os2Display->request = 1;
os2Display->qlen = 0;
screen = (Screen *) ckalloc(sizeof(Screen));
if (!screen) {
ckfree((char *)os2Display->display_name);
ckfree((char *)os2Display);
return (Display *)None;
}
screen->display = os2Display;
screen->width = aDevCaps[CAPS_WIDTH];
screen->height = yScreen;
screen->mwidth = (screen->width * 1000) / aDevCaps[CAPS_HORIZONTAL_RESOLUTION];
screen->mheight = (screen->width * 1000) / aDevCaps[CAPS_VERTICAL_RESOLUTION];
/*
* Set up the root window.
*/
todPtr = (TkOS2Drawable*) ckalloc(sizeof(TkOS2Drawable));
if (!todPtr) {
ckfree((char *)os2Display->display_name);
ckfree((char *)os2Display);
ckfree((char *)screen);
return (Display *)None;
}
todPtr->type = TOD_WINDOW;
todPtr->window.winPtr = NULL;
todPtr->window.handle = HWND_DESKTOP;
screen->root = (Window)todPtr;
screen->root_depth = aDevCaps[CAPS_COLOR_BITCOUNT];
screen->root_visual = (Visual *) ckalloc(sizeof(Visual));
if (!screen->root_visual) {
ckfree((char *)os2Display->display_name);
ckfree((char *)os2Display);
ckfree((char *)screen);
ckfree((char *)todPtr);
return (Display *)None;
}
screen->root_visual->visualid = 0;
if ( aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER ) {
screen->root_visual->map_entries = aDevCaps[CAPS_COLOR_INDEX]+1;
screen->root_visual->class = PseudoColor;
screen->root_visual->red_mask = 0x0;
screen->root_visual->green_mask = 0x0;
screen->root_visual->blue_mask = 0x0;
} else {
if (screen->root_depth == 4) {
screen->root_visual->class = StaticColor;
screen->root_visual->map_entries = 16;
} else if (screen->root_depth == 8) {
screen->root_visual->class = StaticColor;
screen->root_visual->map_entries = 256;
} else if (screen->root_depth == 16) {
screen->root_visual->class = TrueColor;
/*
screen->root_visual->map_entries = 64;
screen->root_visual->red_mask = 0xf8;
screen->root_visual->green_mask = 0xfc00;
screen->root_visual->blue_mask = 0xf80000;
*/
screen->root_visual->map_entries = aDevCaps[CAPS_COLOR_INDEX]+1;
screen->root_visual->red_mask = 0xff;
screen->root_visual->green_mask = 0xff00;
screen->root_visual->blue_mask = 0xff0000;
} else if (screen->root_depth >= 24) {
screen->root_visual->class = TrueColor;
screen->root_visual->map_entries = 256;
screen->root_visual->red_mask = 0xff;
screen->root_visual->green_mask = 0xff00;
screen->root_visual->blue_mask = 0xff0000;
}
}
screen->root_visual->bits_per_rgb = screen->root_depth;
/*
* Note that these pixel values are not palette relative.
*/
screen->white_pixel = RGB(255, 255, 255);
screen->black_pixel = RGB(0, 0, 0);
os2Display->screens = screen;
os2Display->nscreens = 1;
os2Display->default_screen = 0;
screen->cmap = XCreateColormap(os2Display, None, screen->root_visual,
AllocNone);
return os2Display;
}
/*
*----------------------------------------------------------------------
*
* XBell --
*
* Generate a beep.
*
* Results:
* None.
*
* Side effects:
* Plays a sounds out the system speakers.
*
*----------------------------------------------------------------------
*/
void
XBell(display, percent)
Display* display;
int percent;
{
rc = DosBeep (770L, 300L);
}
MRESULT EXPENTRY
TkOS2FrameProc(hwnd, message, param1, param2)
HWND hwnd;
ULONG message;
MPARAM param1;
MPARAM param2;
{
static inMoveSize = 0;
if (inMoveSize) {
TclOS2FlushEvents();
}
switch (message) {
case WM_CREATE: {
TkOS2Drawable *todPtr = (TkOS2Drawable *) PVOIDFROMMP(param1);
Tcl_HashEntry *hPtr;
int new;
BOOL rc;
/*
* Add the window and handle to the window table.
*/
todPtr->window.handle = hwnd;
hPtr = Tcl_CreateHashEntry(&windowTable, (char *)hwnd, &new);
if (!new) {
panic("Duplicate window handle: %p", hwnd);
}
Tcl_SetHashValue(hPtr, todPtr);
/*
* Store the pointer to the drawable structure passed into
* WinCreateWindow in the user data slot of the window.
*/
rc= WinSetWindowULong(hwnd, QWL_USER, (ULONG)todPtr);
break;
}
case WM_DESTROY: {
DeleteWindow(hwnd);
return 0;
}
case WM_QUERYTRACKINFO: {
TRACKINFO *track = (TRACKINFO *)PVOIDFROMMP(param2);
SWP pos;
BOOL rc;
inMoveSize = 1;
/* Get present size as default max/min */
rc = WinQueryWindowPos(hwnd, &pos);
/* Fill in defaults */
track->cxBorder = track->cyBorder = 4; /* 4 pixels tracking */
track->cxGrid = track->cyGrid = 1; /* smooth tracking */
track->cxKeyboard= track->cyKeyboard= 8; /* fast keyboardtracking */
track->rclTrack.xLeft = pos.x;
track->rclTrack.yBottom = pos.y;
track->rclTrack.xRight = pos.x + pos.cx;
track->rclTrack.yTop = pos.y + pos.cy;
track->rclBoundary.xLeft = 0;
track->rclBoundary.yBottom = 0;
track->rclBoundary.xRight = xScreen;
track->rclBoundary.yTop = yScreen;
track->ptlMinTrackSize.x = 0;
track->ptlMaxTrackSize.x = xScreen;
track->ptlMinTrackSize.y = 0;
track->ptlMaxTrackSize.y = yScreen;
track->fs = SHORT1FROMMP(param1);
/* Determine what Tk will allow */
TkOS2WmSetLimits(hwnd, (TRACKINFO *) PVOIDFROMMP(param2));
inMoveSize = 0;
return (MRESULT)1; /* continue sizing or moving */
}
case WM_REALIZEPALETTE:
/* Notifies that the input focus window has realized its logical
* palette, so realize ours and update client area(s)
* Must return 0
*/
TkOS2WmInstallColormaps(hwnd, WM_REALIZEPALETTE, FALSE);
break;
case WM_SETFOCUS:
/*
* If usfocus is true we translate the event *AND* install the
* colormap, otherwise we only translate the event.
*/
if ( LONGFROMMP(param2) == TRUE ) {
HPS hps = WinGetPS(hwnd);
ULONG colorsChanged;
TkOS2Drawable *todPtr =
(TkOS2Drawable *) WinQueryWindowULong(hwnd, QWL_USER);
if (TkOS2GetWinPtr(todPtr) != NULL) {
GpiSelectPalette(hps,
TkOS2GetPalette(TkOS2GetWinPtr(todPtr)->atts.colormap));
WinRealizePalette(hwnd, hps, &colorsChanged);
/*
TkOS2WmInstallColormaps(hwnd, WM_SETFOCUS, FALSE);
*/
}
}
TranslateEvent(hwnd, message, param1, param2);
break;
case WM_WINDOWPOSCHANGED: {
SWP *pos = (SWP *) PVOIDFROMMP(param1);
TkOS2Drawable *todPtr = (TkOS2Drawable *)
WinQueryWindowULong(hwnd, QWL_USER);
TkOS2WmConfigure(TkOS2GetWinPtr(todPtr), pos);
break;
}
/*
* The frame sends the WM_CLOSE to the client (child) if it exists,
* so we have to handle it there.
* Also hand off mouse/button stoff to default procedure.
*/
case WM_CLOSE:
case WM_BUTTON1DOWN:
case WM_BUTTON2DOWN:
case WM_BUTTON3DOWN:
case WM_BUTTON1UP:
case WM_BUTTON2UP:
case WM_BUTTON3UP:
case WM_MOUSEMOVE:
break;
case WM_CHAR:
TranslateEvent(hwnd, message, param1, param2);
return 0;
case WM_DESTROYCLIPBOARD:
TranslateEvent(hwnd, message, param1, param2);
/*
* We need to pass these messages to the default window
* procedure in order to get the system menu to work.
*/
break;
default:
}
return oldFrameProc(hwnd, message, param1, param2);
}
/*
*----------------------------------------------------------------------
*
* TkOS2ChildProc --
*
* Callback from Presentation Manager whenever an event occurs on
* a child window.
*
* Results:
* Standard OS/2 PM return value.
*
* Side effects:
* Default window behavior.
*
*----------------------------------------------------------------------
*/
MRESULT EXPENTRY
TkOS2ChildProc(hwnd, message, param1, param2)
HWND hwnd;
ULONG message;
MPARAM param1;
MPARAM param2;
{
switch (message) {
case WM_CREATE: {
CREATESTRUCT *info = (CREATESTRUCT *) PVOIDFROMMP(param2);
Tcl_HashEntry *hPtr;
int new;
/*
* Add the window and handle to the window table.
*/
hPtr = Tcl_CreateHashEntry(&windowTable, (char *)hwnd, &new);
if (!new) {
panic("Duplicate window handle: %p", hwnd);
}
Tcl_SetHashValue(hPtr, info->pCtlData);
/*
* Store the pointer to the drawable structure passed into
* WinCreateWindow in the user data slot of the window. Then
* set the Z stacking order so the window appears on top.
*/
WinSetWindowULong(hwnd, QWL_USER, (ULONG)info->pCtlData);
WinSetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
return 0;
}
case WM_DESTROY:
DeleteWindow(hwnd);
return 0;
case WM_RENDERFMT: {
TkOS2Drawable *todPtr;
todPtr = (TkOS2Drawable *) WinQueryWindowULong(hwnd, QWL_USER);
TkOS2ClipboardRender(TkOS2GetWinPtr(todPtr),
(ULONG)(SHORT1FROMMP(param1)));
return 0;
}
case WM_BUTTON1DOWN:
case WM_BUTTON2DOWN:
case WM_BUTTON3DOWN:
case WM_BUTTON1UP:
case WM_BUTTON2UP:
case WM_BUTTON3UP:
TranslateEvent(hwnd, message, param1, param2);
/*
* Pass on BUTTON stuff to default procedure, eg. for having the
* focus set to the frame window for us.
*/
break;
/*
* For double-clicks, generate a ButtonPress and ButtonRelease.
* Pass on BUTTON stuff to default procedure, eg. for having the
* focus set to the frame window for us.
*/
case WM_BUTTON1DBLCLK:
TranslateEvent(hwnd, WM_BUTTON1DOWN, param1, param2);
TranslateEvent(hwnd, WM_BUTTON1UP, param1, param2);
break;
case WM_BUTTON2DBLCLK:
TranslateEvent(hwnd, WM_BUTTON2DOWN, param1, param2);
TranslateEvent(hwnd, WM_BUTTON2UP, param1, param2);
break;
case WM_BUTTON3DBLCLK:
TranslateEvent(hwnd, WM_BUTTON3DOWN, param1, param2);
TranslateEvent(hwnd, WM_BUTTON3UP, param1, param2);
break;
case WM_CLOSE:
/*
* The frame sends the WM_CLOSE to the client (child) if it exists,
* so we have to handle it here.
*/
case WM_PAINT:
case WM_DESTROYCLIPBOARD:
case WM_MOUSEMOVE:
case WM_CHAR:
case WM_SETFOCUS:
TranslateEvent(hwnd, message, param1, param2);
/* Do not pass on to PM */
return 0;
/* Added by/for Ilya Zakharevich: */
case WM_TRANSLATEACCEL: {
PQMSG pqmsg = PVOIDFROMMP(param1);
USHORT flags = (USHORT) SHORT1FROMMP(pqmsg->mp1);
USHORT charcode = (USHORT) SHORT1FROMMP(pqmsg->mp2);
USHORT vkeycode = (USHORT) SHORT2FROMMP(pqmsg->mp2);
if (flags & KC_VIRTUALKEY) {
switch (vkeycode) {
case VK_F1:
case VK_F10:
case VK_SPACE:
/* Do not consider as a shortcut */
return 0;
}
} else if ( charcode == ' ') { /* Alt-Space */
/* Do not consider as a shortcut */
return 0;
}
break;
}
}
return WinDefWindowProc(hwnd, message, param1, param2);
}
/*
*----------------------------------------------------------------------
*
* TranslateEvent --
*
* This function is called by the window procedures to handle
* the translation from OS/2 PM events to Tk events.
*
* Results:
* None.
*
* Side effects:
* Queues a new Tk event.
*
*----------------------------------------------------------------------
*/
static void
TranslateEvent(hwnd, message, param1, param2)
HWND hwnd;
ULONG message;
MPARAM param1;
MPARAM param2;
{
TkWindow *winPtr;
XEvent event;
TkOS2Drawable *todPtr;
HWND hwndTop;
/*
* Retrieve the window information, and reset the hwnd pointer in
* case the original window was a toplevel decorative frame.
*/
todPtr = (TkOS2Drawable *) WinQueryWindowULong(hwnd, QWL_USER);
if (todPtr == NULL) {
return;
}
winPtr = TkOS2GetWinPtr(todPtr);
/*
* TranslateEvent may get called even after Tk has deleted the window.
* So we must check for a dead window before proceeding.
*/
if (winPtr == NULL || winPtr->window == None) {
return;
}
hwndTop = hwnd;
hwnd = TkOS2GetHWND(winPtr->window);
event.xany.serial = winPtr->display->request++;
event.xany.send_event = False;
event.xany.display = winPtr->display;
event.xany.window = (Window) winPtr->window;
switch (message) {
case WM_PAINT: {
HPS hps;
RECTL rectl;
event.type = Expose;
hps= WinBeginPaint(hwnd, NULLHANDLE, &rectl);
WinEndPaint(hps);
event.xexpose.x = rectl.xLeft;
/* PM coordinates reversed (*/
event.xexpose.y = TkOS2WindowHeight(todPtr) - rectl.yTop;
event.xexpose.width = rectl.xRight - rectl.xLeft;
event.xexpose.height = rectl.yTop - rectl.yBottom;
event.xexpose.count = 0;
break;
}
case WM_CLOSE:
event.type = ClientMessage;
event.xclient.message_type =
Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS");
event.xclient.format = 32;
event.xclient.data.l[0] =
Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW");
break;
case WM_SETFOCUS:
if ( (LOUSHORT(param2)) == TRUE ) {
event.type = FocusIn;
} else {
event.type = FocusOut;
}
event.xfocus.mode = NotifyNormal;
event.xfocus.detail = NotifyAncestor;
break;
case WM_DESTROYCLIPBOARD:
event.type = SelectionClear;
event.xselectionclear.selection =
Tk_InternAtom((Tk_Window)winPtr, "CLIPBOARD");
event.xselectionclear.time = WinGetCurrentTime(hab);
break;
case WM_BUTTON1DOWN:
case WM_BUTTON2DOWN:
case WM_BUTTON3DOWN:
case WM_BUTTON1UP:
case WM_BUTTON2UP:
case WM_BUTTON3UP:
case WM_MOUSEMOVE:
case WM_CHAR:
{
/*
* WM_CHAR and the others have different params, while the latter
* give only the flags of which keys were pressed (or none).
*/
USHORT flags = (message == WM_CHAR) ? SHORT1FROMMP(param1)
: SHORT2FROMMP(param2);
unsigned int state = TkOS2GetModifierState(message, flags,
param1, param2);
/*
Time time = WinGetCurrentTime(hab);
*/
Time time = WinQueryMsgTime(hab);
POINTL clientPoint;
POINTL rootPoint;
BOOL rc;
/*
* Compute the screen and window coordinates of the event.
*/
rc = WinQueryMsgPos(hab, &rootPoint);
clientPoint.x = rootPoint.x;
clientPoint.y = rootPoint.y;
rc= WinMapWindowPoints (HWND_DESKTOP, hwnd, &clientPoint, 1);
/*
* Set up the common event fields.
*/
event.xbutton.root = RootWindow(winPtr->display,
winPtr->screenNum);
event.xbutton.subwindow = None;
event.xbutton.x = clientPoint.x;
/* PM coordinates reversed */
event.xbutton.y = TkOS2WindowHeight((TkOS2Drawable *)todPtr)
- clientPoint.y;
event.xbutton.x_root = rootPoint.x;
event.xbutton.y_root = yScreen - rootPoint.y;
event.xbutton.state = state;
event.xbutton.time = time;
event.xbutton.same_screen = True;
/*
* Now set up event specific fields.
*/
switch (message) {
case WM_BUTTON1DOWN:
event.type = ButtonPress;
event.xbutton.button = Button1;
break;
case WM_BUTTON2DOWN:
event.type = ButtonPress;
event.xbutton.button = Button2;
break;
case WM_BUTTON3DOWN:
event.type = ButtonPress;
event.xbutton.button = Button3;
break;
case WM_BUTTON1UP:
event.type = ButtonRelease;
event.xbutton.button = Button1;
break;
case WM_BUTTON2UP:
event.type = ButtonRelease;
event.xbutton.button = Button2;
break;
case WM_BUTTON3UP:
event.type = ButtonRelease;
event.xbutton.button = Button3;
break;
case WM_MOUSEMOVE:
event.type = MotionNotify;
event.xmotion.is_hint = NotifyNormal;
break;
/*
* We don't check for translated characters on keyup
* because Tk won't know what to do with them. Instead, we
* wait for the WM_CHAR messages which will follow.
*/
/*
event.type = KeyRelease;
event.xkey.keycode = param1;
event.xkey.nchars = 0;
break;
*/
case WM_CHAR: {
/*
* Careful: for each keypress, two of these messages are
* generated, one when pressed and one when released.
* When the keyboard-repeat is triggered, multiple key-
* down messages can be generated. If this goes faster
* than they are retrieved from the queue, they can be
* combined in one message.
*/
USHORT flags= CHARMSG(&message)->fs;
UCHAR krepeat= CHARMSG(&message)->cRepeat;
USHORT charcode= CHARMSG(&message)->chr;
USHORT vkeycode= CHARMSG(&message)->vkey;
int loop;
/*
* Check for translated characters in the event queue.
* and more than 1 char in the message
*/
if ( (flags & KC_ALT) && !(flags & KC_CTRL) &&
(vkeycode != VK_CTRL) && (vkeycode != VK_F10) ) {
/* Equivalent to Windows' WM_SYSKEY */
}
if ( flags & KC_KEYUP ) {
/* Key Up */
event.type = KeyRelease;
/* Added by/for Ilya Zakharevich */
/* KeyRelease for alphanums gets ORed with 0x*00 */
if ( !(flags & KC_VIRTUALKEY) ) {
charcode = charcode & 0xFF;
#ifdef KEYPATCHES
if (charcode && charcode <= 0x1F &&
(flags & KC_CTRL)) {
charcode += ((flags & KC_SHIFT) ? 'A'-1
: 'a'-1);
}
#endif /* KEYPATCHES */
}
} else {
/* Key Down */
event.type = KeyPress;
}
if ( flags & KC_VIRTUALKEY ) {
/* Next if() added by/for Ilya Zakharevich */
if ( (flags & KC_SHIFT) && vkeycode == VK_BACKTAB ) {
vkeycode = VK_TAB;
}
/* vkeycode is valid, should be given precedence */
event.xkey.keycode = vkeycode;
} else {
#ifdef KEYPATCHES
/* Move to VK_USER range, by/for Ilya Zakharevich */
event.xkey.keycode = (charcode & 0xFF) + 0x100;
#else /* KEYPATCHES */
event.xkey.keycode = 0;
#endif /* KEYPATCHES */
}
if ( flags & KC_CHAR ) {
/* charcode is valid */
event.xkey.nchars = krepeat;
for ( loop=0; loop < krepeat; loop++ ) {
event.xkey.trans_chars[loop] = charcode;
}
} else {
/*
* No KC_CHAR, but char can be valid with KC_ALT,
* KC_CTRL when it is not 0.
*/
/* KC_VIRTUALKEY criterion added by Ilya Zakharevich */
if ( (flags & KC_ALT || flags & KC_CTRL)
&& charcode != 0 && !(flags & KC_VIRTUALKEY)) {
event.xkey.keycode = charcode;
}
event.xkey.nchars = 0;
event.xkey.trans_chars[0] = 0;
}
/*
* Synthesize both a KeyPress and a KeyRelease.
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
event.type = KeyRelease;
*/
/*
* Setting xany.send_event to -1 indicates to the
* OS/2 implementation of XLookupString that this
* event was generated by OS/2 and that the OS/2
* extension xkey.trans_chars is filled.
* If it is not -1, xkey.keycode is the virtual
* key being sent programmatically by generic code.
*/
event.xany.send_event = -1;
break;
}
}
if ((event.type == MotionNotify)
|| (event.type == ButtonPress)
|| (event.type == ButtonRelease)) {
TkOS2PointerEvent(&event, winPtr);
goto done;
}
break;
}
default:
goto done;
}
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
done:
if (isInModal) {
TclOS2FlushEvents();
}
}
/*
*----------------------------------------------------------------------
*
* TkOS2GetModifierState --
*
* This function constructs a state mask for the mouse buttons
* and modifier keys.
*
* Results:
* Returns a composite value of all the modifier and button state
* flags that were set at the time the event occurred.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
unsigned int
TkOS2GetModifierState(message, flags, param1, param2)
ULONG message; /* OS/2 PM message type */
USHORT flags; /* Applicable flags (in different param for
* different messages
*/
MPARAM param1; /* param1 of message, used if key message */
MPARAM param2; /* param2 of message, used if key message */
{
unsigned int state = 0; /* accumulated state flags */
int isKeyEvent = 0; /* 1 if message is a key press or release */
int prevState = 0; /* 1 if key was previously down */
USHORT vkeycode= SHORT2FROMMP(param2); /* function key */
/*
* If the event is a key press or release, we check for autorepeat.
*/
if ( (flags & KC_CHAR) || (flags & KC_VIRTUALKEY) ) {
isKeyEvent = TRUE;
prevState = flags & KC_PREVDOWN;
}
/*
* If the key being pressed or released is a modifier key, then
* we use its previous state, otherwise we look at the current state.
*/
if (isKeyEvent && (vkeycode == VK_SHIFT)) {
state |= prevState ? ShiftMask : 0;
} else {
/*
state |= (WinGetKeyState(HWND_DESKTOP, VK_SHIFT) & 0x8000)
*/
state |= (flags & KC_SHIFT)
? ShiftMask : 0;
}
if (isKeyEvent && (vkeycode == VK_CTRL)) {
state |= prevState ? ControlMask : 0;
} else {
/*
state |= (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
*/
state |= (flags & KC_CTRL)
? ControlMask : 0;
}
/* Do NOT handle ALTGRAF specially, since that will ignore its char */
if (isKeyEvent && (vkeycode == VK_ALT)) {
state |= prevState ? Mod4Mask : 0;
} else {
/*
state |= (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000)
*/
state |= (flags & KC_ALT)
? Mod4Mask : 0;
}
if (isKeyEvent && (vkeycode == VK_MENU)) {
state |= prevState ? Mod2Mask : 0;
} else {
state |= (WinGetKeyState(HWND_DESKTOP, VK_MENU) & 0x8000)
? Mod2Mask : 0;
}
/*
* For toggle keys, we have to check both the previous key state
* and the current toggle state. The result is the state of the
* toggle before the event.
*/
if ((vkeycode == VK_CAPSLOCK) && !( flags & KC_KEYUP)) {
state = (prevState ^ (WinGetKeyState(HWND_DESKTOP,VK_CAPSLOCK)& 0x0001))
? 0 : LockMask;
} else {
state |= (WinGetKeyState(HWND_DESKTOP, VK_CAPSLOCK) & 0x0001)
? LockMask : 0;
}
if ((vkeycode == VK_NUMLOCK) && !( flags & KC_KEYUP)) {
state = (prevState ^ (WinGetKeyState(HWND_DESKTOP,VK_NUMLOCK) & 0x0001))
? 0 : Mod1Mask;
} else {
state |= (WinGetKeyState(HWND_DESKTOP, VK_NUMLOCK) & 0x0001)
? Mod1Mask : 0;
}
if ((vkeycode == VK_SCRLLOCK) && !( flags & KC_KEYUP)) {
state = (prevState ^ (WinGetKeyState(HWND_DESKTOP,VK_SCRLLOCK)& 0x0001))
? 0 : Mod3Mask;
} else {
state |= (WinGetKeyState(HWND_DESKTOP, VK_SCRLLOCK) & 0x0001)
? Mod3Mask : 0;
}
/*
* If a mouse button is being pressed or released, we use the previous
* state of the button.
*/
if (message == WM_BUTTON1UP || (message != WM_BUTTON1DOWN
&& WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000)) {
state |= Button1Mask;
}
if (message == WM_BUTTON2UP || (message != WM_BUTTON2DOWN
&& WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000)) {
state |= Button2Mask;
}
if (message == WM_BUTTON3UP || (message != WM_BUTTON3DOWN
&& WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000)) {
state |= Button3Mask;
}
return state;
}
/*
*----------------------------------------------------------------------
*
* TkOS2GetDrawableFromHandle --
*
* Find the drawable associated with the given window handle.
*
* Results:
* Returns a drawable pointer if the window is managed by Tk.
* Otherwise it returns NULL.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
TkOS2Drawable *
TkOS2GetDrawableFromHandle(hwnd)
HWND hwnd; /* OS/2 PM window handle */
{
Tcl_HashEntry *hPtr;
hPtr = Tcl_FindHashEntry(&windowTable, (char *)hwnd);
if (hPtr) {
return (TkOS2Drawable *)Tcl_GetHashValue(hPtr);
}
return NULL;
}
/*
*----------------------------------------------------------------------
*
* DeleteWindow --
*
* Remove a window from the window table, and free the resources
* associated with the drawable.
*
* Results:
* None.
*
* Side effects:
* Frees the resources associated with a window handle.
*
*----------------------------------------------------------------------
*/
static void
DeleteWindow(hwnd)
HWND hwnd;
{
TkOS2Drawable *todPtr;
Tcl_HashEntry *hPtr;
/*
* Remove the window from the window table.
*/
hPtr = Tcl_FindHashEntry(&windowTable, (char *)hwnd);
if (hPtr) {
Tcl_DeleteHashEntry(hPtr);
}
/*
* Free the drawable associated with this window, unless the drawable
* is still in use by a TkWindow. This only happens in the case of
* a top level window, since the window gets destroyed when the
* decorative frame is destroyed.
*/
todPtr = (TkOS2Drawable *) WinQueryWindowULong(hwnd, QWL_USER);
if (todPtr) {
if (todPtr->window.winPtr == NULL) {
ckfree((char *) todPtr);
todPtr= NULL;
} else if (!(todPtr->window.winPtr->flags & TK_TOP_LEVEL)) {
/*
* We can get here because PM does a depth-first WM_DESTROY tree traversal
* (children first, then the to-be-destroyed window, while Windows hands the
* message first to the to-be-destroyed window, then to the children.
* So don't panic
panic("Non-toplevel window destroyed before its drawable");
*/
} else {
todPtr->window.handle = NULLHANDLE;
}
}
}
/*
*----------------------------------------------------------------------
*
* Tk_FreeXId --
*
* This inteface is not needed under OS/2.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Tk_FreeXId(display, xid)
Display *display;
XID xid;
{
}
/*----------------------------------------------------------------------
* TkOS2EnterModalLoop --
*
* Notifies the OS/2 event handler that TK is about to enter a
* modal loop. OS/2 Events are handled immediately if TK has
* enter a modal loop.
*
* Results:
* None.
*
* Side effects:
* The isInModal counter is incremented.
*
*----------------------------------------------------------------------
*/
void TkOS2EnterModalLoop(interp)
Tcl_Interp * interp;
{
isInModal ++;
}
/*----------------------------------------------------------------------
* TkOS2LeaveModalLoop --
*
* Complement to the TkOS2EnterModalLoop function.
*
* Results:
* None.
*
* Side effects:
* The isInModal counter is decremented.
*
*----------------------------------------------------------------------
*/
void TkOS2LeaveModalLoop(interp)
Tcl_Interp * interp;
{
isInModal --;
}