"
COPYRIGHT (c) 1989 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
"{ Package: 'stx:libview' }"
DeviceWorkstation subclass:#XWorkstation
instanceVariableNames:'hasShapeExtension hasShmExtension hasDPSExtension
hasMbufExtension hasXVideoExtension hasSaveUnder hasPEXExtension
hasImageExtension hasInputExtension ignoreBackingStore blackpixel
whitepixel atoms protocolsAtom deleteWindowAtom saveYourselfAtom
quitAppAtom primaryAtom cutBuffer0Atom stringAtom lengthAtom
wmStateAtom listOfXFonts buttonsPressed eventRootX eventRootY
displayName eventTrace dispatchingExpose rgbVisual virtualRootId
rootId eventBuffer altModifierMask metaModifierMask
multiClickTime deviceIOTimeoutErrorSignal activateOnClick
rawKeySymTranslation'
classVariableNames:'RawKeySymTranslation ConservativeSync MaxStringLength'
poolDictionaries:''
category:'Interface-Graphics'
!
!XWorkstation primitiveDefinitions!
%{
#ifdef LINUX
# define SHM
#endif
#define COUNT_RESOURCES
#ifdef COUNT_RESOURCES
static int __cnt_color = 0;
static int __cnt_bitmap = 0;
static int __cnt_view = 0;
static int __cnt_gc = 0;
static int __cnt_cursor = 0;
static int __cnt_font = 0;
#endif
/*
* x does a typedef Time - I need Object Time ...
*/
#undef Time
#define Time XTime
/*
* x does a #define True / False
* we are lucky - the ST/X True/False are not needed
*/
#undef True
#undef False
#ifdef memset
# undef memset
#endif
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#define XK_MISCELLANY
#include <X11/keysymdef.h>
#include <X11/cursorfont.h>
#ifdef LINUX
# include <sys/socket.h>
#endif
/*
* this define suppresses XAllocColor/XFreeColor on
* TrueColor systems - I am not certain, if this is
* always legal to do (it works with XFree servers).
*/
#define QUICK_TRUE_COLORS
/*
* shape support works; enabled by -DSHAPE in makefile
* see RoundClock and RoundGlobe examples
*/
#ifdef SHAPE
# include <X11/extensions/shape.h>
#endif
/*
* shared memory extension access is currently not supported
* (only query is implemented)
*/
#ifdef SHM
# include <X11/extensions/XShm.h>
#endif
/*
* multiBuffer extension access is currently not supported
* (only query is implemented)
*/
#ifdef MBUF
# include <X11/extensions/multibuf.h>
#endif
/*
* XVideo extension access is currently not supported
* (only query is implemented)
*/
#ifdef XVIDEO
# include <X11/extensions/Xv.h>
#endif
/*
* PEX extension - if available
*/
#ifdef PEX5
# include <PEX5/PEX.h>
#endif
/*
* XImage extension - if available
*/
#ifdef XIE
# include <X11/extensions/XIE.h>
#endif
/*
* when I have more time to check it out, I will support display-PS
*/
#ifdef DPS
# ifdef sgi
# include <X11/extensions/XDPS.h>
# include <X11/extensions/XDPSlib.h>
# include <X11/extensions/dpsXclient.h>
# else
# include <DPS/XDPS.h>
# include <DPS/XDPSlib.h>
# include <DPS/dpsXclient.h>
# endif
#endif
#if defined(someMachine)
/*
* if nformats cannot be found in the Display structure ...
*/
# define NO_PRIVATE_DISPLAY_ACCESS
#endif
#if defined(IRIX5) || defined(__VMS) || (XlibSpecificationRelease == 6)
/*
* accessing private data in Display ... sorry
*/
# define DISPLAYACCESS(d) ((_XPrivDisplay)d)
#else
# define DISPLAYACCESS(d) d
#endif
/*
* some defines - tired of typing ...
*/
#define __DisplayVal(o) (Display *)(__externalAddressVal(o))
#define __DrawableVal(o) (Drawable)(__externalAddressVal(o))
#define __WindowVal(o) (Window)(__externalAddressVal(o))
#define __PixmapVal(o) (Pixmap)(__externalAddressVal(o))
#define __GCVal(o) (GC)(__externalAddressVal(o))
#define __CursorVal(o) (Cursor)(__externalAddressVal(o))
#define __FontVal(o) (XFontStruct *)(__externalAddressVal(o))
#define __DPSContextVal(o) (DPSContext)(__externalAddressVal(o))
#define __MKATOMOBJ(a) __MKSMALLINT(a)
#define __AtomVal(o) __intVal(o)
#define __isAtomID(o) __isSmallInteger(o)
#define myDpy __DisplayVal(__INST(displayId))
#define ISCONNECTED (__INST(displayId) != nil)
#ifdef __VMS__
# include "vms_Xnames.h"
#endif
void __XTimeoutErrorHandler();
int __XErrorHandler__();
int __XIOErrorHandler__();
#define DEFAULT_XLIB_TIMEOUT 600 /* in 50ms ticks (30 seconds) */
static __xlibTimeout__ = DEFAULT_XLIB_TIMEOUT;
#define ENTER_XLIB() \
{ \
__blockingPrimitiveTimoutHandler__ = (VOIDFUNC)__XTimeoutErrorHandler; \
__blockingPrimitiveTimeoutArg__ = (INT)self; \
__blockingPrimitiveTimeout__ = __xlibTimeout__; \
} {
#define LEAVE_XLIB() \
{ \
__blockingPrimitiveTimeout__ = 0; \
} }
%}
! !
!XWorkstation primitiveVariables!
%{
/*
* remembered info from private error handler
*/
static char lastErrorMsg[128] = "";
static unsigned INT lastRequestCode = 0;
static unsigned INT lastMinorCode = 0;
static unsigned INT lastResource = 0;
static int __debug__ = 0;
#define DPRINTF(x) if (__debug__) { printf x; }
%}
! !
!XWorkstation primitiveFunctions!
%{
/*
* some systems need a dummy reference to force the linker
* to include that stuff. Should be #ifdef'd ...
*/
#ifndef ELF
# ifdef __GNUC__
VOLATILE
# endif
static
dummyToForceLoading() {
XCreateSimpleWindow(0, 0, 0, 0, 0, 0, 0, 0, 0);
XCloseDisplay(0);
XCreateImage(0, 0, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0);
XSetWindowColormap(0, 0, 0);
XQueryColors(0,0,0,0);
# ifdef SHM
XShmAttach(0, 0);
XShmCreateImage(0, 0, 0, 0, 0, 0, 0 ,0);
XShmDetach(0, 0);
XShmPutImage(0, 0, 0, 0 , 0,0,0,0,0,0,0);
shmctl(0,0,0);
fgetc(0);
# endif
}
#endif
/*
* catch X-errors and forward as errorInterrupt:#DisplayError,
* (which itself invokes my handler and optionally raises an exceptionSignal)
* the implementation below is somewhat wrong: it will
* report all errors for Display, even though there could be
* more than one display connection. (being fixed, new errorInterrupt mechanism
* allows passing an additional argument, which is the displayID ...)
*/
int
__XErrorHandler__(dpy, event)
Display *dpy;
XErrorEvent *event;
{
XGetErrorText(dpy, event->error_code, lastErrorMsg, 127);
lastErrorMsg[127] = '\0';
if (lastErrorMsg[0] == '\0') {
sprintf(lastErrorMsg, "code: %d", event->error_code);
}
lastRequestCode = event->request_code;
lastMinorCode = event->minor_code;
lastResource = event->resourceid;
if ((event->error_code == BadWindow) && (lastRequestCode == 4) && (lastMinorCode == 0)) {
/*
* this is a BadWindow error for X_DestroyWindow.
* ignore it here, since it results from the GC freeing windows
* in non bottom-up window order.
*/
return 0;
}
if (@global(ErrorPrinting) == true) {
fprintf(stderr, "XWorkstation [error]: x-error caught maj=%d (0x%x) min=%d (0x%x) resource=%x\n",
event->request_code, event->request_code,
event->minor_code, event->minor_code, event->resourceid);
fprintf(stderr, "XWorkstation [error]: x-error message is [%d] '%s'\n",
event->error_code, lastErrorMsg);
}
__errorInterruptWithIDAndParameter__(@symbol(DisplayError), __MKEXTERNALADDRESS(dpy));
return 0;
}
/*
* much like the above, but for IO Errors;
* forwarded as errorInterrupt:#DisplayIOError,
* In single display apps, handling those here does not
* really make sense (except, for a controlled cleanup).
* However, in multiDisplay apps, a single broken
* connection should not affect the other users.
*/
int
__XIOErrorHandler__(dpy)
Display *dpy;
{
if (@global(ErrorPrinting) == true) {
fprintf(stderr, "XWorkstation [error]: I/O error\n");
}
__immediateErrorInterruptWithIDAndParameter__(@symbol(DisplayIOError),
__MKEXTERNALADDRESS(dpy));
#if 0
/*
* don't do this.
* This error is called asynchronously, and the wrong process may be terminated
*/
/*
* if we return from the error interrupt ...
*/
__internalError("unhandled display I/O error");
__terminateProcess(0); /* soft terminate */
__terminateProcess(1); /* hard terminate */
/* never reached */
#endif
return 0;
}
/*
* timeout error in case of Xlib request timeout.
* forwarded as errorInterrupt:#DisplayIOTimeoutError,
* This is generated synthetically by the VM if the
* timeoutHandler has been set.
*/
void
__XTimeoutErrorHandler(displayDeviceInst)
OBJ displayDeviceInst;
{
if (@global(ErrorPrinting) == true) {
fprintf(stderr, "XWorkstation [error]: I/O request timeout dpy=%x\n", displayDeviceInst);
}
if (displayDeviceInst == @global(MainDisplay)) {
fprintf(stderr, "XWorkstation [error]: keep display connection for master display (no shutdown)\n");
return;
}
#if 0
This is litter:
1. How should I ever close the display without a displayId?
2. This may loop for ever, if there is some data in the socket, but #eventPending returns
false because displayId is nil.
3. The problem is not the EventListener, which is reading (and waiting in #eventPending),
but maybe other processes writing to the Display and blocking the system again (for 30 Seconds).
/*
* must immediately flush that displays deviceID - otherwise,
* the scheduler may try to ask for pending events without a watchdog
* timer ...
*/
__OINST(displayDeviceInst, displayId) = nil;
#endif
__immediateErrorInterruptWithIDAndParameter__(@symbol(DisplayIOTimeoutError), displayDeviceInst);
/*
* if we return from the error interrupt ...
*/
if (__OINST(displayDeviceInst, displayId) != nil) {
__internalError("unhandled display Timeout error");
__terminateProcess(0); /* soft terminate */
__terminateProcess(1); /* hard terminate */
}
}
#ifdef VIRTUAL_ROOT
/*
* added since RootWindow-macro is not sufficient
* when virtual root-windows are involved (i.e. tvtwm)
*/
static Window
getRootWindow(dpy, screen)
Display *dpy;
{
Window root;
Atom vRootAtom = None;
int i;
Window rootReturn, parentReturn;
Window* children = (Window *)0;
unsigned int numChildren;
root = RootWindow(dpy, screen);
/*
* on IRIS, this creates a badwindow error - why ?
* children contains a funny window (000034)
*/
# if !defined(IRIS) || defined(IRIX5)
if (root) {
if (XQueryTree(dpy, root, &rootReturn, &parentReturn, &children, &numChildren)) {
vRootAtom = XInternAtom(dpy, "__SWM_VROOT", True );
if (vRootAtom != None) {
for (i=0; i < numChildren; i++) {
Atom actual_type;
int actual_format;
unsigned long nitems, bytesafter;
Window* newRoot = (Window*) 0;
if (children[i]) {
if (XGetWindowProperty(dpy, children[i], vRootAtom,
0L, 1L, False, XA_WINDOW,
&actual_type, &actual_format, &nitems, &bytesafter,
(unsigned char**) &newRoot) == Success && newRoot) {
root = *newRoot;
XFree(newRoot); /* XXX */
break;
}
}
}
}
if (children) XFree( children );
}
}
# endif
return root;
}
#endif
%}
! !
!XWorkstation class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1989 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
documentation
"
this class provides the interface to X11. It redefines all required methods
from DeviceWorkstation. Notice, that in Smalltalk/X you are not technically
limited to one display - in theory, you can create Views on many displays
simultanously. However, the default setup is for one display only.
To support multiple displays, you will have to start another event dispatcher
process for the other display(s) and create the other views with a slightly
different protocol. However, 'normal' applications do not have to care for
all of this ...
See more documentation in my superclass, DeviceWorkstation.
[author:]
Claus Gittinger
"
! !
!XWorkstation class methodsFor:'initialization'!
initialize
|d|
super initialize.
ConservativeSync := OperatingSystem platformName == #win32.
"/ some XServers crash, when given too long strings in XDrawString/XDrawInageString.
"/ the following is an adjustable soft-limit.
MaxStringLength := 4096.
RawKeySymTranslation isNil ifTrue:[
"/ the following table maps X-keyevents to ST/X
"/ device independed events.
"/ It is NOT meant as a keyboardMap replacement.
RawKeySymTranslation := d := Dictionary new.
d at:'Delete_line' put:#DeleteLine.
d at:'Delete_word' put:#DeleteWord.
d at:'Down' put:#CursorDown.
d at:'Up' put:#CursorUp.
d at:'Left' put:#CursorLeft.
d at:'Right' put:#CursorRight.
]
"Modified: / 27.4.1999 / 17:21:30 / cg"
! !
!XWorkstation class methodsFor:'error handling'!
debug:aBoolean
%{ /* NOCONTEXT */
__debug__ = (aBoolean == true) ? 1 : 0;
%}
!
debugResources
%{
#ifdef COUNT_RESOURCES
printf("colors:%d bitmaps:%d views:%d gc:%d cursors:%d fonts:%d\n",
__cnt_color, __cnt_bitmap,
__cnt_view, __cnt_gc, __cnt_cursor, __cnt_font);
#endif
%}
"
XWorkstation debugResources
"
!
errorStringOfLastError
%{
RETURN ( __MKSTRING(lastErrorMsg) );
%}
!
getConnectionTimeOut
%{
RETURN (__MKSMALLINT(__xlibTimeout__ / 50));
%}
!
lastErrorString
"return the last X-error string -
when buffering is on, this may be
an error for a long-ago operation"
|string requestCode s match line|
string := self errorStringOfLastError.
requestCode := self requestCodeOfLastError.
"
X specific: search the requestCode in '/usr/lib/X11/XErrorDB',
and append the name of the corresponding X-request
"
s := '/usr/lib/X11/XErrorDB' asFilename readStream.
s notNil ifTrue:[
match := 'XRequest.' , requestCode printString.
line := s peekForLineStartingWith:match.
line notNil ifTrue:[
string := string , ' in ' , (line copyFrom:(line indexOf:$:)+1)
].
s close.
].
^ string
!
minorCodeOfLastError
%{ /* NOCONTEXT */
RETURN ( __MKSMALLINT(lastMinorCode) );
%}
!
requestCodeOfLastError
%{ /* NOCONTEXT */
RETURN ( __MKSMALLINT(lastRequestCode) );
%}
!
resourceIdOfLastError
%{ /* NOCONTEXT */
RETURN ( __MKEXTERNALADDRESS(lastResource) );
%}
!
setConnectionTimeOut:seconds
%{
__xlibTimeout__ = __intVal(seconds) * 50;
%}
! !
!XWorkstation class methodsFor:'queries'!
platformName
"ST-80 compatibility.
Return a string describing the display systems platform.
WinWorkstation always returns 'X11'."
^ 'X11' "I don't know what ST-80 returns for X ..."
"Modified: 26.5.1996 / 15:32:46 / cg"
! !
!XWorkstation methodsFor:'Signal constants'!
deviceIOTimeoutErrorSignal
"return the per-device signal, which is raised when a timeout
IO error (i.e. broken connection) occurs."
^ deviceIOTimeoutErrorSignal
! !
!XWorkstation methodsFor:'accessing & queries'!
activateOnClick:aBoolean
"set/clear the activateOnClick behavior.
If on, a click into a window raises and activates
the (top) window.
Windows users typically enable this;
in contrast, those used to the X-Window system typically prefer
it disabled.
Returns the previous setting."
|prev|
prev := activateOnClick ? false.
aBoolean notNil ifTrue:[
activateOnClick := aBoolean.
].
^ prev
"
Display class activateOnClick:true
Display class activateOnClick:false
"
!
anyButtonMotionMask
"return the state-mask for any button in motion events' state-field.
This is the devices mask."
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT(Button1MotionMask | Button2MotionMask | Button3MotionMask));
%}.
^ nil
!
blackpixel
"return the colornumber of black"
^ blackpixel
!
button1MotionMask
"return the state-mask for button1 in motion events' state-field.
For backward compatibility."
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT(Button1MotionMask));
%}
"
Display button1MotionMask
"
!
button2MotionMask
"return the state-mask for button2 in motion events' state-field
For backward compatibility."
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT(Button2MotionMask));
%}
!
button3MotionMask
"return the state-mask for button3 in motion events' state-field
For backward compatibility."
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT(Button3MotionMask));
%}
!
buttonMotionMask:aButton
"return the state-mask for button1 in motion events state-field.
This is the devices mask."
%{ /* NOCONTEXT */
if (aButton == __MKSMALLINT(1)) {
RETURN (__MKSMALLINT(Button1MotionMask));
}
if (aButton == __MKSMALLINT(2)) {
RETURN (__MKSMALLINT(Button2MotionMask));
}
if (aButton == __MKSMALLINT(3)) {
RETURN (__MKSMALLINT(Button3MotionMask));
}
%}.
^ nil
!
controlMask
"return the state-mask for the CTRL modified in motion events' state-field."
"/ obsolete
^ self ctrlModifierMask
!
displayFileDescriptor
"return the displays fileNumber - for select"
%{ /* NOCONTEXT */
#ifndef WIN32
if (ISCONNECTED) {
RETURN ( __MKSMALLINT(ConnectionNumber(myDpy)) );
}
#endif
RETURN (nil);
%}
!
displayName
"return the X-connections display name.
This is (currently) nil for the default display,
something like foo:0 for any other remote display.
Future versions may return non-nil strings for the default display as well."
^ displayName
!
protocolVersion
"return the X-servers protocol version - should normally not be of
any interest"
%{ /* NOCONTEXT */
if (ISCONNECTED) {
RETURN ( __MKSMALLINT(XProtocolVersion(myDpy)) );
}
RETURN (nil);
%}
"
Display protocolVersion
"
!
serverVendor
"return the X-server vendor string - this should normally not be of
any interest, but can be for special cases
(to avoid bugs in certain implementations)"
%{
if (ISCONNECTED) {
RETURN ( __MKSTRING(XServerVendor(myDpy)) );
}
RETURN (nil);
%}
"
Display serverVendor
"
!
shiftMask
"return the state-mask for the SHIFT modified in motion events' state-field."
"/ obsolete
^ self shiftModifierMask
!
translatePoint:aPoint from:windowId1 to:windowId2
"given a point in window1, return the coordinate in window2.
This expects a device coordinate (relative to the first views origin)
in aPoint and returns a device coordinate relative to the 2nd views origin.
- use to xlate points from a window to rootwindow"
<context: #return>
|x1 y1 x2 y2|
x1 := x2 := aPoint x truncated.
y1 := y2 := aPoint y truncated.
%{
int xpos, ypos;
Window w1, w2, child_ret;
int screen = __intVal(__INST(screen));
if (ISCONNECTED
&& __isExternalAddress(windowId1)
&& __isExternalAddress(windowId2)
&& __bothSmallInteger(x1, y1)) {
Display *dpy = myDpy;
Window rootWin;
w1 = __WindowVal(windowId1);
w2 = __WindowVal(windowId2);
#ifdef VIRTUAL_ROOT
rootWin = RootWindow(dpy, screen);
if ((w1 == rootWin) || (w2 == rootWin)) {
if (w1 == rootWin) {
w1 = getRootWindow(dpy, screen);
}
if (w2 == rootWin) {
w2 = getRootWindow(dpy, screen);
}
}
#endif
ENTER_XLIB();
XTranslateCoordinates(dpy, w1, w2,
__intVal(x1), __intVal(y1),
&xpos, &ypos, &child_ret);
LEAVE_XLIB();
x2 = __MKSMALLINT(xpos);
y2 = __MKSMALLINT(ypos);
}
%}.
^ (x2 @ y2)
!
vendorRelease
"return the X-servers vendor release - should normally not be of
any interest, but can be for special cases.
(to avoid bugs in certain implementations)"
%{ /* NOCONTEXT */
if (ISCONNECTED) {
RETURN ( __MKSMALLINT(XVendorRelease(myDpy)) );
}
RETURN (nil);
%}
"
Display vendorRelease
"
!
viewIdFromPoint:aPoint in:windowId
"given a point in rootWindow, return the viewId of the subview of windowId
hit by this coordinate. Return nil if no view was hit.
The returned id may be the id of a non ST view.
- used to find the window to drop objects after a cross-view drag."
<context: #return>
%{
int screen = __intVal(__INST(screen));
OBJ xp, yp;
int xpos, ypos;
Window child_ret;
if (ISCONNECTED
&& __isExternalAddress(windowId)
&& __isPoint(aPoint)) {
Display *dpy = myDpy;
xp = _point_X(aPoint);
yp = _point_Y(aPoint);
if (__bothSmallInteger(xp, yp)) {
ENTER_XLIB();
XTranslateCoordinates(dpy,
RootWindow(dpy, screen),
__WindowVal(windowId),
__intVal(xp), __intVal(yp),
&xpos, &ypos, &child_ret);
LEAVE_XLIB();
if (child_ret) {
RETURN ( __MKEXTERNALADDRESS(child_ret) );
}
RETURN ( nil );
}
}
%}.
windowId notNil ifTrue:[
aPoint isPoint ifTrue:[
^ self viewIdFromPoint:aPoint asPoint truncated in:windowId
]
].
^ nil
"
Display viewIdFromPoint:100@100 in:Display realRootWindowId
"
!
virtualExtent
"return the virtual extent of the display (in pixels).
On most systems, this is the same as the physical width;
except, if a window manager with a virtual desktop like olvwm
(simulating a bigger screen) is running."
%{
if (ISCONNECTED
&& (__INST(rootId) != __INST(virtualRootId))
&& __isExternalAddress(__INST(virtualRootId))) {
Window vRootWin;
Window root;
int x, y;
unsigned int width, height;
unsigned int dummy;
int ret;
vRootWin = __WindowVal(__INST(virtualRootId));
ENTER_XLIB();
ret = XGetGeometry(myDpy, vRootWin, &root, &x, &y, &width, &height,
&dummy, &dummy);
LEAVE_XLIB();
if (ret) {
RETURN ( __MKPOINT_INT(width, height) );
}
}
%}.
^ width @ height
!
whitepixel
"return the colornumber of white"
^ whitepixel
! !
!XWorkstation methodsFor:'accessing-display capabilities'!
hasDPS
"return true, if this workstation supports display postscript.
Both the server must support it, and the feature must have been
enabled in the smalltalk system, for true to be returned."
^ hasDPSExtension
"
Display hasDPS
"
!
hasExtension:extensionString
"query for an X extension. The argument, extensionString
should be the name of the extension (i.e. 'SHAPE', 'XInputExtension' etc).
Return true, if that extension is available in the server.
(which does not imply, that there is support in smalltalk for it."
<context: #return>
%{
int dummy;
OBJ rslt = false;
if (ISCONNECTED
&& __isNonNilObject(extensionString)
&& (__qIsString(extensionString) || __qIsSymbol(extensionString))) {
ENTER_XLIB();
if (XQueryExtension(myDpy, __stringVal(extensionString), &dummy, &dummy, &dummy)) {
rslt = true;
}
LEAVE_XLIB();
}
RETURN (rslt);
%}
"
Display hasExtension:'XVideo'
Display hasExtension:'Input'
Display hasExtension:'GLX'
Display hasExtension:'X3D-PEX'
Display hasExtension:'XInputExtension'
Display hasExtension:'SHAPE'
Display hasExtension:'MIT-SHM'
Display hasExtension:'SGIFullScreenStereo'
"
!
hasImageExtension
"return true, if this workstation supports the X image extension.
Both the server must support it, and the feature must have been
enabled in the smalltalk system, for true to be returned."
^ hasImageExtension
"
Display hasImageExtension
"
!
hasInputExtension
"return true, if this workstation supports the X input extension.
Both the server must support it, and the feature must have been
enabled in the smalltalk system, for true to be returned."
^ hasInputExtension
"
Display hasInputExtension
"
!
hasMultibuffer
"return true, if this workstation supports the multibuffer extension.
Both the server must support it, and the feature must have been
enabled in the smalltalk system, for true to be returned."
^ hasMbufExtension
"
Display hasMultibuffer
"
!
hasPEX
"return true, if this workstation supports PEX 3D graphics.
Both the server must support it, and the feature must have been
enabled in the smalltalk system, for true to be returned."
^ hasPEXExtension
"
Display hasPEX
"
!
hasShm
"return true, if this workstation supports the shared pixmap extension.
Both the server must support it, and the feature must have been
enabled in the smalltalk system, for true to be returned."
^ hasShmExtension
"
Display hasShm
"
!
hasXVideo
"return true, if this workstation supports the XVideo extension.
Both the server must support it, and the feature must have been
enabled in the smalltalk system, for true to be returned."
^ hasXVideoExtension
"
Display hasXVideo
"
!
iconSizes
"Get the preferred/supported icon sizes. These are set by the window manager.
We return nil (if not set) or an OrderedCollection of iconSize specs."
<context: #return>
|xIconSizes count ret|
%{
int screen = __intVal(__INST(screen));
XIconSize *sizeList;
int cnt;
if (ISCONNECTED) {
Display *dpy = myDpy;
int status;
ENTER_XLIB();
status = XGetIconSizes(dpy, RootWindow(dpy, screen), &sizeList, &cnt);
LEAVE_XLIB();
if (status > 0) {
xIconSizes = __MKEXTERNALBYTES(sizeList);
count = __MKSMALLINT(cnt);
}
}
%}.
xIconSizes isNil ifTrue:[^ nil].
ret := OrderedCollection new:count.
1 to:count do:[ :i |
|minWidth minHeight maxWidth maxHeight widthStep heightStep d|
%{
XIconSize *slp;
slp = &((XIconSize *)__externalAddressVal(xIconSizes))[__intVal(i)-1];
minWidth = __MKSMALLINT(slp->min_width);
minHeight = __MKSMALLINT(slp->min_height);
maxWidth = __MKSMALLINT(slp->max_width);
maxHeight = __MKSMALLINT(slp->max_height);
widthStep = __MKSMALLINT(slp->width_inc);
heightStep = __MKSMALLINT(slp->height_inc);
%}.
d := IdentityDictionary new.
d at:#minWidth put:minWidth.
d at:#maxWidth put:maxWidth.
d at:#widthStep put:widthStep.
d at:#minHeight put:minHeight.
d at:#maxHeight put:maxHeight.
d at:#heightStep put:heightStep.
ret add:d
].
xIconSizes free.
^ ret
"
Display iconSizes
"
!
ignoreBackingStore:aBoolean
"if the argument is true, the views backingStore setting will be ignored, and
no backing store used - this can be used on servers where backing store is
very slow or is broken (can be put into display-rc-file)"
ignoreBackingStore := aBoolean
!
preferredIconSize
"return the displays preferred size for icons.
Redefined to return a special value on SGI servers."
self serverVendor = 'Silicon Graphics' ifTrue:[
^ 86@68
].
^ super preferredIconSize
"Created: 10.6.1996 / 21:06:48 / cg"
!
queryBlackPixel
%{ /* NOCONTEXT */
if (ISCONNECTED) {
Display *dpy;
int scr;
dpy = myDpy;
scr = DefaultScreen(dpy);
RETURN ( __MKSMALLINT(BlackPixel(dpy, scr)));
}
%}.
^ nil
"
Display queryBlackPixel
"
!
queryCells
%{ /* NOCONTEXT */
if (ISCONNECTED) {
Display *dpy;
int scr;
dpy = myDpy;
scr = DefaultScreen(dpy);
RETURN ( __MKSMALLINT(DisplayCells(dpy, scr)));
}
%}.
^ nil
"
Display queryCells
"
!
queryDPSExtension
%{ /* NOCONTEXT */
#ifdef DPS
if (ISCONNECTED) {
Display *dpy;
int dummy;
dpy = myDpy;
if (XQueryExtension(dpy, "DPSExtension", &dummy, &dummy, &dummy)) {
RETURN ( true );
}
}
#endif
%}.
^ false
"
Display queryDPSExtension
"
!
queryDefaultScreen
%{ /* NOCONTEXT */
if (ISCONNECTED) {
Display *dpy;
dpy = myDpy;
RETURN ( __MKSMALLINT(DefaultScreen(dpy)));
}
%}.
^ nil
"
Display queryDefaultScreen
"
!
queryDefaultVisualType
%{ /* NOCONTEXT */
if (ISCONNECTED) {
Display *dpy;
Visual *visual;
dpy = myDpy;
visual = DefaultVisualOfScreen(DefaultScreenOfDisplay(dpy));
switch (visual->class) {
case StaticGray:
RETURN ( @symbol(StaticGray) );
case GrayScale:
RETURN ( @symbol(GrayScale) );
case StaticColor:
RETURN ( @symbol(StaticColor) );
case PseudoColor:
RETURN ( @symbol(PseudoColor) );
case TrueColor:
RETURN ( @symbol(TrueColor) );
case DirectColor:
RETURN ( @symbol(DirectColor) );
}
}
%}.
^ nil
"
Display queryDefaultVisualType
"
!
queryDepth
%{ /* NOCONTEXT */
if (ISCONNECTED) {
Display *dpy;
int scr;
dpy = myDpy;
scr = DefaultScreen(dpy);
RETURN ( __MKSMALLINT(DisplayPlanes(dpy, scr)));
}
%}.
^ nil
"
Display queryDepth
"
!
queryHeight
%{ /* NOCONTEXT */
if (ISCONNECTED) {
Display *dpy;
int scr;
dpy = myDpy;
scr = DefaultScreen(dpy);
RETURN ( __MKSMALLINT(DisplayHeight(dpy, scr)));
}
%}.
^ nil
"
Display queryHeight
"
!
queryHeightMM
%{ /* NOCONTEXT */
if (ISCONNECTED) {
Display *dpy;
int scr;
dpy = myDpy;
scr = DefaultScreen(dpy);
RETURN ( __MKSMALLINT(DisplayHeightMM(dpy, scr)));
}
%}.
^ nil
"
Display queryHeightMM
"
!
queryMBUFExtension
%{ /* NOCONTEXT */
#ifdef MBUF
if (ISCONNECTED) {
Display *dpy;
int dummy;
dpy = myDpy;
if (XQueryExtension(dpy, "Multi-Buffering", &dummy, &dummy, &dummy)) {
RETURN ( true );
}
}
#endif
%}.
^ false
"
Display queryMBUFExtension
"
!
queryPEXExtension
%{ /* NOCONTEXT */
#ifdef PEX5
if (ISCONNECTED) {
Display *dpy;
int dummy;
dpy = myDpy;
if (XQueryExtension(dpy, PEX_NAME_STRING, &dummy, &dummy, &dummy)) {
RETURN ( true );
}
}
#endif
%}.
^ false
"
Display queryPEXExtension
"
!
queryRGBMasks
%{ /* NOCONTEXT */
if (ISCONNECTED) {
Display *dpy;
Visual *visual;
OBJ redMask, greenMask, blueMask, bprgb;
dpy = myDpy;
visual = DefaultVisualOfScreen(DefaultScreenOfDisplay(dpy));
redMask = __MKSMALLINT(visual->red_mask);
greenMask = __MKSMALLINT(visual->green_mask);
blueMask = __MKSMALLINT(visual->blue_mask);
bprgb = __MKSMALLINT(visual->bits_per_rgb);
RETURN ( __ARRAY_WITH4(redMask, greenMask, blueMask, bprgb) );
}
%}.
^ nil
"
Display queryRGBMasks
"
!
querySHMExtension
%{ /* NOCONTEXT */
#ifdef xxSHM
if (ISCONNECTED) {
Display *dpy;
int dummy;
dpy = myDpy;
if (XQueryExtension(dpy, "MIT_SHM", &dummy, &dummy, &dummy)) {
RETURN ( true );
}
}
#endif
%}.
^ false
"
Display querySHMExtension
"
!
queryShapeExtension
%{ /* NOCONTEXT */
#ifdef SHAPE
if (ISCONNECTED) {
Display *dpy;
int dummy;
dpy = myDpy;
if (XShapeQueryExtension(dpy, &dummy, &dummy)) {
RETURN ( true );
}
}
#endif
%}.
^ false
"
Display queryShapeExtension
"
!
queryWhitePixel
%{ /* NOCONTEXT */
if (ISCONNECTED) {
Display *dpy;
int scr;
dpy = myDpy;
scr = DefaultScreen(dpy);
RETURN ( __MKSMALLINT(WhitePixel(dpy, scr)));
}
%}.
^ nil
"
Display queryWhitePixel
"
!
queryWidth
%{ /* NOCONTEXT */
if (ISCONNECTED) {
Display *dpy;
int scr;
dpy = myDpy;
scr = DefaultScreen(dpy);
RETURN ( __MKSMALLINT(DisplayWidth(dpy, scr)));
}
%}.
^ nil
"
Display queryWidth
"
!
queryWidthMM
%{ /* NOCONTEXT */
if (ISCONNECTED) {
Display *dpy;
int scr;
dpy = myDpy;
scr = DefaultScreen(dpy);
RETURN ( __MKSMALLINT(DisplayWidthMM(dpy, scr)));
}
%}.
^ nil
"
Display queryWidthMM
"
!
queryXIEExtension
%{ /* NOCONTEXT */
#ifdef XIE
if (ISCONNECTED) {
Display *dpy;
int dummy;
dpy = myDpy;
if (XQueryExtension(dpy, xieExtName, &dummy, &dummy, &dummy)) {
RETURN ( true );
}
}
#endif
%}.
^ false
"
Display queryXIEExtension
"
!
queryXIExtension
%{ /* NOCONTEXT */
#ifdef XI
if (ISCONNECTED) {
Display *dpy;
int dummy;
dpy = myDpy;
if (XQueryExtension(dpy, "XInputExtension", &dummy, &dummy, &dummy)) {
RETURN ( true );
}
}
#endif
%}.
^ false
"
Display queryXIExtension
"
!
queryXVideoExtension
%{ /* NOCONTEXT */
#ifdef XVIDEO
if (ISCONNECTED) {
Display *dpy;
int dummy;
dpy = myDpy;
if (XQueryExtension(dpy, "XVideo", &dummy, &dummy, &dummy)) {
RETURN ( true );
}
}
#endif
%}.
^ false
"
Display queryXVideoExtension
"
!
scrollsAsynchronous
"return true, if this display asynchronously sends expose events after a
scroll operation. False otherwise. Asynchronous expose events are an X
speciality, which affects a few methods outside of the display class (sorry)"
^ true
!
supportedImageFormats
"return an array with supported image formats;
each array entry is an attribute dictionary, consisting of
depth, bitsPerPixel and padding values."
|nFormats "{ Class: SmallInteger }"
formatArray|
%{
Display *dpy;
if (! ISCONNECTED) {
RETURN (nil);
}
dpy = myDpy;
#ifdef NO_PRIVATE_DISPLAY_ACCESS
nFormats = __MKSMALLINT(1);
#else
nFormats = __MKSMALLINT(DISPLAYACCESS(dpy)->nformats);
#endif
%}.
formatArray := Array new:nFormats.
1 to:nFormats do:[:index |
|info bitsPerPixelInfo depthInfo paddingInfo i|
i := index.
%{
ScreenFormat *format;
Display *dpy = myDpy;
#ifdef NO_PRIVATE_DISPLAY_ACCESS
depthInfo = __MKSMALLINT(1);
bitsPerPixelInfo = __MKSMALLINT(1);
paddingInfo = __MKSMALLINT(8);
#else
format = DISPLAYACCESS(dpy)->pixmap_format;
format += (__intVal(i)-1);
bitsPerPixelInfo = __MKSMALLINT(format->bits_per_pixel);
depthInfo = __MKSMALLINT(format->depth);
paddingInfo = __MKSMALLINT(format->scanline_pad);
#endif
%}.
info := IdentityDictionary new.
info at:#depth put:depthInfo.
info at:#bitsPerPixel put:bitsPerPixelInfo.
info at:#padding put:paddingInfo.
formatArray at:index put:info.
].
^ formatArray
"
Display supportedImageFormats
"
!
supportsAnyViewBackgroundPixmaps
"return true, if the device allows pixmaps as
viewBackground."
^ true
"Created: / 4.5.1999 / 18:41:07 / cg"
!
supportsArbitraryShapedViews
"return true, if this workstation supports arbitrary shaped windows.
Both the server must support it (the shape-extension),
and the feature must have been enabled in the smalltalk system,
for true to be returned."
^ hasShapeExtension
"
Display supportsArbitraryShapedViews
"
!
supportsIconViews
"return true, if this device supports views as icons.
Only Xservers (currently) support this."
^ true
"
Display supportsIconViews
"
"Modified: 10.6.1996 / 20:11:48 / cg"
"Created: 10.6.1996 / 21:08:18 / cg"
!
supportsMaskedDrawingWith:aForm
"return true, if the device allows the given form pixmap
to be used as paint color.
True returned here - X has no trouble with any mask."
^ true
"Created: / 4.5.1999 / 12:16:43 / cg"
!
supportsViewBackgroundPixmap:aForm
"return true, if the device allows the given pixmap as
viewBackground.
True returned here - X support any size."
^ true
"Created: / 4.5.1999 / 18:40:42 / cg"
"Modified: / 4.5.1999 / 18:44:25 / cg"
!
supportsViewGravity
"return true, if this device supports gravity attributes.
We do not depend on it being implemented, but some resizing operations
are faster, it is is."
^ true
! !
!XWorkstation methodsFor:'bitmap/window creation'!
createBitmapFromArray:anArray width:w height:h
"create a monochrome, depth1 bitmap from a given (byte-)array.
The rows are aligned to a multiple of 8"
|bitmapId|
bitmapId := self primCreateBitmapFromArray:anArray width:w height:h.
bitmapId isNil ifTrue:[
self primitiveFailedOrClosedConnection
].
^ bitmapId
!
createBitmapFromFile:aString for:aForm
<context: #return>
|id w h|
%{
int screen = __intVal(__INST(screen));
if (ISCONNECTED
&& __isNonNilObject(aString)
&& (__qIsString(aString) || __qIsSymbol(aString))) {
Display *dpy = myDpy;
char *filename;
int status;
Pixmap newBitmap;
unsigned b_width, b_height;
int b_x_hot, b_y_hot;
filename = (char *) __stringVal(aString);
ENTER_XLIB();
status = XReadBitmapFile(dpy, RootWindow(dpy, screen),
filename, &b_width, &b_height, &newBitmap,
&b_x_hot, &b_y_hot);
LEAVE_XLIB();
if ((status == BitmapSuccess) && newBitmap) {
#ifdef COUNT_RESOURCES
__cnt_bitmap++;
#endif
w = __MKSMALLINT(b_width);
h = __MKSMALLINT(b_height);
id = __MKEXTERNALADDRESS(newBitmap);
}
}
%}.
id notNil ifTrue:[
aForm setWidth:w height:h
].
^ id
!
createBitmapWidth:w height:h
"allocate a bitmap on the Xserver, the contents is undefined
(i.e. random). Return a bitmap id or nil"
<context: #return>
%{
int screen = __intVal(__INST(screen));
Pixmap newBitmap;
if (__bothSmallInteger(w, h) && ISCONNECTED) {
Display *dpy = myDpy;
ENTER_XLIB();
newBitmap = XCreatePixmap(dpy, RootWindow(dpy, screen),
__intVal(w), __intVal(h), 1);
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
if (newBitmap)
__cnt_bitmap++;
#endif
RETURN ( (newBitmap != (Pixmap)0) ? __MKEXTERNALADDRESS(newBitmap) : nil );
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
!
createPixmapWidth:w height:h depth:d
"allocate a pixmap on the Xserver, the contents is undefined
(i.e. random). Return a bitmap id or nil"
<context: #return>
%{
int screen = __intVal(__INST(screen));
Pixmap newBitmap;
if (__bothSmallInteger(w, h) && ISCONNECTED) {
Display *dpy = myDpy;
ENTER_XLIB();
newBitmap = XCreatePixmap(dpy, RootWindow(dpy, screen),
__intVal(w), __intVal(h), __intVal(d));
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
if (newBitmap)
__cnt_bitmap++;
#endif
RETURN ( (newBitmap != (Pixmap)0) ? __MKEXTERNALADDRESS(newBitmap) : nil );
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
!
createWindowFor:aView type:typeSymbol
origin:origin
extent:extent
minExtent:minExt
maxExtent:maxExt
borderWidth:bWidth
subViewOf:wsuperView
style:wStyle
inputOnly:winputOnly
label:wlabel
owner:wowner
icon:wicon iconMask:wiconMask
iconView:wiconView
<context: #return>
|xpos ypos wwidth wheight minWidth minHeight maxWidth maxHeight
bColorId wsuperViewId wiconId wiconMaskId windowId
weventMask wiconViewId bitGravity viewGravity vBgColor
vBgForm deepForm preferredVisual preferredDepth|
displayId isNil ifTrue:[
self primitiveFailedOrClosedConnection.
^ nil
].
origin notNil ifTrue:[
xpos := origin x.
ypos := origin y.
] ifFalse:[
xpos := ypos := 0.
].
extent notNil ifTrue:[
wwidth := extent x.
wheight := extent y.
] ifFalse:[
wwidth := wheight := 100.
].
minExt notNil ifTrue:[
minWidth := minExt x.
minHeight := minExt y
].
maxExt notNil ifTrue:[
maxWidth := maxExt x.
maxHeight := maxExt y
].
wsuperView notNil ifTrue:[
wsuperViewId := wsuperView id
].
wicon notNil ifTrue:[
wiconId := wicon id.
wiconMask notNil ifTrue:[
wiconMaskId := wiconMask id
]
].
wiconView notNil ifTrue:[
wiconViewId := wiconView id
].
weventMask := aView eventMask.
preferredVisual := aView preferredVisual.
preferredDepth := aView preferredDepth.
%{ /* STACK:64000 */ /* used to be 16000 - but VMS seems to need a lot */
Display *dpy = myDpy;
int screen = __intVal(__INST(screen));
Visual visual;
XGCValues xgcv;
XSetWindowAttributes xswa;
XSizeHints sizehints;
XWMHints wmhints;
int bw, bd, bg;
Window newWindow, parentWindow;
char *windowName;
XFontStruct *f;
Pixmap backPixmap = (Pixmap)0,
iconBitmap = (Pixmap)0,
iconMask = (Pixmap)0;
int flags = 0, depth, ioClass;
Window iconWindow;
Atom WmDeleteWindowAtom, WmSaveYourselfAtom, WmProtocolsAtom;
Atom WmQuitAppAtom;
Atom atoms[3];
int atomCount = 0, isTopWindow = 0;
sizehints.flags = 0;
sizehints.width = 100;
sizehints.height = 100;
sizehints.x = 0;
sizehints.y = 0;
if (__bothSmallInteger(wwidth, wheight)) {
sizehints.flags |= PSize;
sizehints.width = __intVal(wwidth);
sizehints.height = __intVal(wheight);
}
if (__bothSmallInteger(xpos, ypos)) {
sizehints.flags |= PPosition;
sizehints.x = __intVal(xpos);
sizehints.y = __intVal(ypos);
}
if (__bothSmallInteger(minWidth, minHeight)) {
sizehints.flags |= PMinSize;
sizehints.min_width = __intVal(minWidth);
sizehints.min_height = __intVal(minHeight);
}
if (__bothSmallInteger(maxWidth, maxHeight)) {
sizehints.flags |= PMaxSize;
sizehints.max_width = __intVal(maxWidth);
sizehints.max_height = __intVal(maxHeight);
}
bg = WhitePixel(dpy, screen);
if (__isSmallInteger(bWidth)) {
bw = __intVal(bWidth);
} else {
bw = 0;
}
bd = BlackPixel(dpy, screen);
if (__isExternalAddress(wsuperViewId)) {
parentWindow = __WindowVal(wsuperViewId);
} else {
parentWindow = RootWindow(dpy, screen);
isTopWindow = 1;
}
if (wStyle == @symbol(popUp))
xswa.override_redirect = 1;
else
xswa.override_redirect = 0;
if (winputOnly == true)
ioClass = InputOnly;
else
ioClass = InputOutput;
if (__isSmallInteger(weventMask)) {
xswa.event_mask = __intVal(weventMask);
} else {
xswa.event_mask = 0;
}
if (ioClass == InputOnly) {
bw = 0;
depth = 0;
flags |= CWEventMask;
} else {
depth = DefaultDepth(dpy,screen);
flags |= CWEventMask | CWBorderPixel | CWOverrideRedirect;
if (backPixmap != (Pixmap)0) {
xswa.background_pixmap = backPixmap;
flags |= CWBackPixmap;
} else {
xswa.background_pixel = bg;
flags |= CWBackPixel;
}
xswa.border_pixel = bd;
}
visual.visualid = CopyFromParent;
if (__isSmallInteger(preferredDepth)) {
depth = __intVal(preferredDepth);
}
if (preferredVisual != nil) {
XVisualInfo vi;
int cls;
if (preferredVisual == @symbol(StaticGray))
cls = StaticGray;
else if (preferredVisual == @symbol(GrayScale))
cls = GrayScale;
else if (preferredVisual == @symbol(StaticColor))
cls = StaticColor;
else if (preferredVisual == @symbol(PseudoColor))
cls = PseudoColor;
else if (preferredVisual == @symbol(TrueColor))
cls = TrueColor;
else if (preferredVisual == @symbol(DirectColor))
cls = DirectColor;
else
cls = PseudoColor;
ENTER_XLIB();
if (XMatchVisualInfo(dpy, screen, depth, cls, &vi)) {
visual.visualid = vi.visualid;
/*
printf("visualId=%x\n", vi.visualid);
*/
}
LEAVE_XLIB();
}
ENTER_XLIB();
newWindow = XCreateWindow(dpy, parentWindow,
sizehints.x, sizehints.y,
sizehints.width, sizehints.height,
bw, depth, ioClass, &visual,
flags, &xswa);
LEAVE_XLIB();
if (! newWindow) {
RETURN ( nil );
}
#ifdef COUNT_RESOURCES
__cnt_view++;
#endif
/*
* define its icon and name
* (only makes sense for topWindows)
*/
if (isTopWindow) {
if (__isExternalAddress(wiconId))
iconBitmap = __PixmapVal(wiconId);
else
iconBitmap = (Pixmap)0;
if (__isExternalAddress(wiconMaskId))
iconMask = __PixmapVal(wiconMaskId);
else
iconMask = (Pixmap)0;
if (__isExternalAddress(wiconViewId))
iconWindow = __WindowVal(wiconViewId);
else
iconWindow = (Window)0;
if (__isString(wlabel) || __isSymbol(wlabel))
windowName = (char *) __stringVal(wlabel);
else
windowName = "";
if (iconBitmap || windowName) {
ENTER_XLIB();
XSetStandardProperties(dpy, newWindow,
windowName, windowName,
iconBitmap,
0, 0, &sizehints);
LEAVE_XLIB();
}
wmhints.flags = 0;
if (iconBitmap) {
wmhints.flags |= IconPixmapHint;
wmhints.icon_pixmap = iconBitmap;
}
if (iconMask) {
wmhints.flags |= IconMaskHint;
wmhints.icon_mask = iconMask;
}
if (iconWindow) {
wmhints.flags |= IconWindowHint;
wmhints.icon_window = iconWindow;
}
/*
wmhints.flags |= InputHint;
wmhints.input = True;
*/
ENTER_XLIB();
XSetWMHints(dpy, newWindow, &wmhints);
LEAVE_XLIB();
/*
* tell window manager to not kill us but send an event instead
*/
/*
* get atoms first (if not already known)
*/
if (__INST(protocolsAtom) == nil) {
ENTER_XLIB();
WmProtocolsAtom = XInternAtom(dpy, "WM_PROTOCOLS", False);
__INST(protocolsAtom) = __MKATOMOBJ(WmProtocolsAtom);
#ifdef USE_SAVEYOURSELF_ATOM
WmSaveYourselfAtom = XInternAtom(dpy, "WM_SAVE_YOURSELF", False);
__INST(saveYourselfAtom) = __MKATOMOBJ(WmSaveYourselfAtom);
#endif
#ifdef USE_QUIT_APP_ATOM
WmQuitAppAtom = XInternAtom(dpy, "_WM_QUIT_APP", False);
__INST(quitAppAtom) = __MKATOMOBJ(WmQuitAppAtom);
#endif
WmDeleteWindowAtom = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
__INST(deleteWindowAtom) = __MKATOMOBJ(WmDeleteWindowAtom);
LEAVE_XLIB();
} else {
#ifdef USE_QUIT_APP_ATOM
WmQuitAppAtom = __AtomVal(__INST(quitAppAtom));
#else
WmQuitAppAtom = 0;
#endif
WmProtocolsAtom = __AtomVal(__INST(protocolsAtom));
WmDeleteWindowAtom = __AtomVal(__INST(deleteWindowAtom));
#ifdef USE_SAVEYOURSELF_ATOM
WmSaveYourselfAtom = __AtomVal(__INST(saveYourselfAtom));
#else
WmSaveYourselfAtom = 0;
#endif
}
atoms[0] = WmDeleteWindowAtom; atomCount++;
#ifdef USE_SAVEYOURSELF_ATOM
atoms[atomCount] = WmSaveYourselfAtom; atomCount++;
#endif
#ifdef USE_QUIT_APP_ATOM
atoms[atomCount] = WmQuitAppAtom; atomCount++;
#endif
ENTER_XLIB();
XChangeProperty(dpy, newWindow, WmProtocolsAtom, XA_ATOM,
32, PropModeReplace, (unsigned char *)atoms, atomCount);
LEAVE_XLIB();
}
windowId = __MKEXTERNALADDRESS(newWindow);
%}.
self addKnownView:aView withId:windowId.
^ windowId
!
destroyGC:aGCId
<context: #return>
%{
if (! ISCONNECTED) {
RETURN ( self );
}
if (__isExternalAddress(aGCId)) {
GC gc = __GCVal(aGCId);
if (gc) {
ENTER_XLIB();
XFreeGC(myDpy, gc);
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
__cnt_gc--;
#endif
}
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
destroyPixmap:aDrawableId
<context: #return>
%{
if (! ISCONNECTED) {
RETURN ( self );
}
if (__isExternalAddress(aDrawableId)) {
Pixmap pix = __PixmapVal(aDrawableId);
if (pix) {
ENTER_XLIB();
XFreePixmap(myDpy, pix);
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
__cnt_bitmap--;
#endif
}
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
destroyView:aView withId:aWindowId
self primDestroyView:aView withId:aWindowId.
self removeKnownView:aView withId:aWindowId.
!
dpsContextFor:aDrawableId and:aGCId
%{ /* NOCONTEXT */
#ifdef XXDPS
int screen = __intVal(__INST(screen));
DPSContext dps;
int height;
if (__isExternalAddress(aDrawableId)
&& __isExternalAddress(aGCId)
&& ISCONNECTED) {
ENTER_XLIB();
dps = XDPSCreateContext(myDpy, __DrawableVal(aDrawableId),
__GCVal(aGCId),
0, height, 0, colormap, NULL, 0,
XDPSDefaultTextBackstop,
XDPSDefaultErrorProc,
NULL);
LEAVE_XLIB();
RETURN ( dps ? __MKEXTERNALADDRESS(dps) : nil );
}
#endif
%}.
self primitiveFailedOrClosedConnection.
^ nil
!
gcFor:aDrawableId
<context: #return>
%{
int screen = __intVal(__INST(screen));
GC gc;
if (__isExternalAddress(aDrawableId) && ISCONNECTED) {
ENTER_XLIB();
gc = XCreateGC(myDpy, __DrawableVal(aDrawableId), 0L, (XGCValues *)0);
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
if (gc)
__cnt_gc++;
#endif
RETURN ( gc ? __MKEXTERNALADDRESS(gc) : nil );
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
!
gcForBitmap:aDrawableId
"with X, this is the same as a normal gc"
^ self gcFor:aDrawableId
!
primCreateBitmapFromArray:anArray width:w height:h
<context: #return>
%{ /* UNLIMITEDSTACK */
Display *dpy;
int screen = __intVal(__INST(screen));
Pixmap newBitmap;
unsigned int b_width, b_height;
REGISTER unsigned char *cp;
REGISTER unsigned char *pBits;
unsigned char *b_bits, *allocatedBits;
int index, row;
REGISTER int col;
unsigned bits;
static char reverseBitTable[256];
static firstCall = 1;
int nBytes;
unsigned char fastBits[10000];
OBJ num, *op;
int bytesPerRow;
if (! ISCONNECTED) {
RETURN (nil);
}
dpy = myDpy;
if (firstCall) {
for (index=0; index < 256; index++) {
reverseBitTable[index] = 0;
if (index & 128) reverseBitTable[index] |= 1;
if (index & 64) reverseBitTable[index] |= 2;
if (index & 32) reverseBitTable[index] |= 4;
if (index & 16) reverseBitTable[index] |= 8;
if (index & 8) reverseBitTable[index] |= 16;
if (index & 4) reverseBitTable[index] |= 32;
if (index & 2) reverseBitTable[index] |= 64;
if (index & 1) reverseBitTable[index] |= 128;
}
firstCall = 0;
}
if (__bothSmallInteger(w, h) && _isNonNilObject(anArray)) {
newBitmap = (Pixmap)0;
b_width = __intVal(w);
b_height = __intVal(h);
bytesPerRow = (b_width + 7) / 8;
nBytes = b_height * bytesPerRow;
if (nBytes < sizeof(fastBits)) {
cp = b_bits = fastBits;
allocatedBits = 0;
} else {
cp = b_bits = allocatedBits = (unsigned char *) malloc(nBytes);
if (! cp) goto fail;
}
if (__qClass(anArray) == @global(Array)) {
index = 1;
op = &(__ArrayInstPtr(anArray)->a_element[index - 1]);
for (row = b_height; row; row--) {
for (col = bytesPerRow; col; col--) {
num = *op++;
if (__isSmallInteger(num)) {
bits = __intVal(num);
} else {
bits = __longIntVal(num);
if (bits == 0) {
goto fail;
}
}
*cp++ = reverseBitTable[bits & 0xFF];
}
}
} else {
if (__qClass(anArray) == @global(ByteArray)) {
pBits = __ByteArrayInstPtr(anArray)->ba_element;
for (col = b_height*bytesPerRow; col; col--) {
*cp++ = reverseBitTable[*pBits++];
}
} else {
goto fail;
}
}
ENTER_XLIB();
newBitmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
(char *)b_bits,
b_width, b_height);
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
if (newBitmap)
__cnt_bitmap++;
#endif
fail: ;
if (allocatedBits)
free(allocatedBits);
RETURN ( newBitmap ? __MKEXTERNALADDRESS(newBitmap) : nil );
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
!
primCreateWindowType:t origin:o extent:e minExtent:minE maxExtent:maxE borderWidth:bw superViewId:sv style:st inputOnly:i label:l ownerId:oId iconId:ic iconMaskId:im iconViewId:iv
"for rel5 only"
^ self primitiveFailedOrClosedConnection
!
primDestroyView:aView withId:aWindowId
<context: #return>
%{
if (! ISCONNECTED) {
RETURN ( self );
}
if (__isExternalAddress(aWindowId)) {
Window win = __WindowVal(aWindowId);
if (win) {
ENTER_XLIB();
XDestroyWindow(myDpy, win);
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
__cnt_view--;
#endif
}
}
%}
!
realRootWindowId
"return the id of the real root window.
This may not be the window you see as background,
since some window managers install a virtual root window on top
of it. Except for very special cases, use #rootWindowId, which takes
care of any virtual root."
%{
int screen = __intVal(__INST(screen));
Window root;
OBJ id;
if (__INST(rootId) != nil) {
RETURN (__INST(rootId));
}
if (ISCONNECTED) {
root = RootWindow(myDpy, screen);
if (! root) {
id = nil;
} else {
__INST(rootId) = id = __MKEXTERNALADDRESS(root); __STORE(self, id);
}
RETURN (id);
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
!
rootWindowId
"return the id of the root window.
This is the window you see as background,
however, it may or may not be the real physical root window,
since some window managers install a virtual root window on top
of the real one. If this is the case, that views id is returned here."
%{
int screen = __intVal(__INST(screen));
Window rootWin, vRootWin = 0;
OBJ id;
if (__INST(virtualRootId) != nil) {
RETURN (__INST(virtualRootId));
}
if (ISCONNECTED) {
Display *dpy = myDpy;
rootWin = RootWindow(dpy, screen);
#ifndef IRIS
/*
* on IRIS, this creates a badwindow error - why ?
* children contains a funny window (000034)
*/
/*
* care for virtual root windows (tvtwm & friends)
*/
{
Atom vRootAtom, kwinAtom;
int i;
Window rootReturn, parentReturn;
Window* children = (Window *)0;
unsigned int numChildren;
int ignoreVRoot = 0;
/*
* Take care of KDE 2.1.
* they define _SWM_ROOT but this is not the parent of
* the application windows.
* Instead it is used for background painting
*/
kwinAtom = XInternAtom(dpy, "KWIN_RUNNING", True);
if (kwinAtom != None) {
Atom actual_type;
int actual_format;
unsigned long nitems, bytesafter;
unsigned char *retVal = 0;
ignoreVRoot = XGetWindowProperty(dpy, rootWin, kwinAtom,
0L, 1L, False, kwinAtom,
&actual_type, &actual_format,
&nitems, &bytesafter, &retVal) == Success
&& actual_type != 0;
if (retVal)
XFree(retVal);
}
if (!ignoreVRoot) {
vRootAtom = XInternAtom(dpy, "__SWM_VROOT", True);
if (vRootAtom != None) {
if (XQueryTree(dpy, rootWin,
&rootReturn, &parentReturn,
&children, &numChildren)) {
for (i=0; i < numChildren; i++) {
Atom actual_type;
int actual_format;
unsigned long nitems, bytesafter;
Window* newRoot = (Window*) 0;
if (children[i]) {
if (XGetWindowProperty(dpy, children[i], vRootAtom,
0L, 1L, False, XA_WINDOW,
&actual_type, &actual_format,
&nitems, &bytesafter,
(unsigned char**) &newRoot
) == Success && newRoot) {
vRootWin = *newRoot;
XFree(newRoot); /* XXX */
break;
}
}
}
if (children) XFree(children);
}
}
}
}
#endif
}
if (! vRootWin) {
vRootWin = rootWin;
if (! vRootWin) {
RETURN ( nil );
}
}
__INST(rootId) = id = __MKEXTERNALADDRESS(rootWin); __STORE(self, id);
__INST(virtualRootId) = id = __MKEXTERNALADDRESS(vRootWin); __STORE(self, id);
RETURN ( id );
%}
"
Display rootWindowId
"
! !
!XWorkstation methodsFor:'color stuff'!
colorCell
"allocate a color cell - return the color index (i.e. colorID).
This method will return nil for StaticGrey, StaticGrey and TrueColor displays."
<context: #return>
%{
int screen = __intVal(__INST(screen));
XColor color;
unsigned long dummy;
Status ok;
if (ISCONNECTED) {
Display *dpy = myDpy;
ENTER_XLIB();
ok = XAllocColorCells(dpy, DefaultColormap(dpy, screen), (Bool)0,
&dummy, 0, &color.pixel, 1);
LEAVE_XLIB();
if (ok) {
#ifdef COUNT_RESOURCES
__cnt_color++;
#endif
RETURN ( __MKSMALLINT(color.pixel) );
}
}
%}.
^ nil
!
colorNamed:aString
"allocate a color with color name - return the color index (i.e. colorID).
Dont use this method, colornames are mostly X specific"
<context: #return>
%{
char *colorname;
XColor scolor, ecolor;
int screen = __intVal(__INST(screen));
int id;
Status ok;
if (ISCONNECTED
&& __isNonNilObject(aString)
&& (__qIsString(aString) || __qIsSymbol(aString))) {
Display *dpy = myDpy;
colorname = (char *) __stringVal(aString);
ENTER_XLIB();
ok = XParseColor(dpy, DefaultColormap(dpy, screen), colorname, &ecolor);
LEAVE_XLIB();
if (ok) {
#ifdef QUICK_TRUE_COLORS
if (__INST(visualType) == @symbol(TrueColor)) {
id = ((ecolor.red >> (16 - __intVal(__INST(bitsRed)))) << __intVal(__INST(redShift))) & __intVal(__INST(redMask));
id += ((ecolor.green >> (16 - __intVal(__INST(bitsGreen)))) << __intVal(__INST(greenShift))) & __intVal(__INST(greenMask));
id += ((ecolor.blue >> (16 - __intVal(__INST(bitsBlue)))) << __intVal(__INST(blueShift))) & __intVal(__INST(blueMask));
RETURN ( __MKSMALLINT(id) );
}
#endif
ENTER_XLIB();
ok = XAllocColor(dpy, DefaultColormap(dpy, screen), &ecolor);
LEAVE_XLIB();
}
if (! ok) {
RETURN ( nil );
}
#ifdef COUNT_RESOURCES
__cnt_color++;
#endif
RETURN ( __MKSMALLINT(ecolor.pixel) );
}
%}.
^ super colorNamed:aString
!
colorScaledRed:r scaledGreen:g scaledBlue:b
"allocate a color with rgb values (0..16rFFFF) - return the color index (i.e. colorID)"
<context: #return>
%{
Display *dpy;
XColor ecolor;
int screen = __intVal(__INST(screen));
Status ok;
int id;
if (__bothSmallInteger(r, g)
&& __isSmallInteger(b)
&& ISCONNECTED) {
ecolor.red = __intVal(r);
ecolor.green= __intVal(g);
ecolor.blue = __intVal(b);
#ifdef QUICK_TRUE_COLORS
if (__INST(visualType) == @symbol(TrueColor)) {
id = ((ecolor.red >> (16 - __intVal(__INST(bitsRed)))) << __intVal(__INST(redShift))) & __intVal(__INST(redMask));
id += ((ecolor.green >> (16 - __intVal(__INST(bitsGreen)))) << __intVal(__INST(greenShift))) & __intVal(__INST(greenMask));
id += ((ecolor.blue >> (16 - __intVal(__INST(bitsBlue)))) << __intVal(__INST(blueShift))) & __intVal(__INST(blueMask));
RETURN ( __MKSMALLINT(id) );
}
#endif
dpy = myDpy;
ENTER_XLIB();
ok = XAllocColor(dpy, DefaultColormap(dpy, screen), &ecolor);
LEAVE_XLIB();
if (! ok) {
RETURN ( nil );
}
#ifdef COUNT_RESOURCES
__cnt_color++;
#endif
RETURN ( __MKSMALLINT(ecolor.pixel) );
}
%}.
^ super colorScaledRed:r scaledGreen:g scaledBlue:b
!
deviceColorValueToPercent:aDeviceValue
"given a color-component value in percent (0..65k), return the corresponding
x-component value (0..100)"
^ (100.0 * aDeviceValue / 16rFFFF)
"
Display deviceColorValueToPercent:0
Display deviceColorValueToPercent:16r8000
Display deviceColorValueToPercent:16rFFFF
"
!
freeColor:colorIndex
"free a display color when its no longer needed"
<context: #return>
%{
Display *dpy;
unsigned long color;
int screen = __intVal(__INST(screen));
#ifdef QUICK_TRUE_COLORS
if (__INST(visualType) == @symbol(TrueColor)) {
/* no need to do anything on TrueColor displays ... */
RETURN (self);
}
#endif
if (! ISCONNECTED) {
RETURN (self);
}
if (__isSmallInteger(colorIndex)) {
dpy = myDpy;
color = (long) __intVal(colorIndex);
ENTER_XLIB();
XFreeColors(dpy, DefaultColormap(dpy, screen), &color, 1, 0L);
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
__cnt_color--;
#endif
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
getScaledRGBFrom:index
"get rgb components (0 .. 16rFFFF) of color in map at:index,
and return a 3-element array containing them"
<context: #return>
%{
int screen = __intVal(__INST(screen));
XColor color;
int sr, sg, sb;
int bits, scale, shift;
if (ISCONNECTED
&& __isSmallInteger(index)) {
Display *dpy = myDpy;
color.pixel = __intVal(index);
ENTER_XLIB();
XQueryColor(dpy, DefaultColormap(dpy, screen), &color);
LEAVE_XLIB();
/*
* have to compensate for an error in X ?, which does not scale
* colors correctly if lesser than 16bits are valid in a color,
* (for example, color white on a 4bitsPerRGB server will Return
* (16rF000 16rF000 16rF000) instead of (16rFFFF 16rFFFF 16rFFFF)
*/
bits = __intVal(__INST(bitsPerRGB));
scale = (1<<bits) - 1;
shift = 16 - bits;
sr = ((double)(color.red>>shift) / scale) * 0xFFFF;
sg = ((double)(color.green>>shift) / scale) * 0xFFFF;
sb = ((double)(color.blue>>shift) / scale) * 0xFFFF;
RETURN ( __ARRAY_WITH3(__MKSMALLINT(sr), __MKSMALLINT(sg), __MKSMALLINT(sb)));
}
%}.
^ super getScaledRGBFrom:index
!
getScaledRGBFromName:colorName
"get rgb components (0..16rFFFF) of color named colorName,
and return a 3-element array containing them"
%{
int screen = __intVal(__INST(screen));
XColor color;
int sr, sg, sb;
double floor();
int bits, scale, shift;
if (ISCONNECTED
&& __isNonNilObject(colorName)
&& (__qIsString(colorName) || __qIsSymbol(colorName))) {
Display *dpy = myDpy;
if (XParseColor(dpy, DefaultColormap(dpy, screen),
(char *) __stringVal(colorName), &color)) {
/*
* have to compensate for an error in X ?, which does not scale
* colors correctly if lesser than 16bits are valid in a color,
* (for example, color white on a 4bitsPerRGB server will Return
* (16rF000 16rF000 16rF000) instead of (16rFFFF 16rFFFF 16rFFFF)
*/
bits = __intVal(__INST(bitsPerRGB));
scale = (1<<bits) - 1;
shift = 16 - bits;
sr = ((double)(color.red>>shift) / scale) * 0xFFFF;
sg = ((double)(color.green>>shift) / scale) * 0xFFFF;
sb = ((double)(color.blue>>shift) / scale) * 0xFFFF;
RETURN ( __ARRAY_WITH3(__MKSMALLINT(sr), __MKSMALLINT(sg), __MKSMALLINT(sb)));
}
}
%}.
^ super getScaledRGBFromName:colorName
!
listOfAvailableColors
"return a list of all available colornames.
This should not be used, since colornames are very
display-specific (here X-specific)."
|aStream list line index colorName|
aStream := FileStream readonlyFileNamed:'/usr/lib/X11/rgb.txt'.
aStream isNil ifTrue:[^ nil].
list := OrderedCollection new.
[aStream atEnd] whileFalse:[
line := aStream nextLine.
line notNil ifTrue:[
"skip the r/g/b numbers"
index := 1.
[(line at:index) isSeparator] whileTrue:[index := index + 1].
[(line at:index) isDigit] whileTrue:[index := index + 1].
[(line at:index) isSeparator] whileTrue:[index := index + 1].
[(line at:index) isDigit] whileTrue:[index := index + 1].
[(line at:index) isSeparator] whileTrue:[index := index + 1].
[(line at:index) isDigit] whileTrue:[index := index + 1].
[(line at:index) isSeparator] whileTrue:[index := index + 1].
colorName := line copyFrom:index.
((colorName occurrencesOf:(Character space)) == 0) ifTrue:[
list add:colorName
]
]
].
aStream close.
^ list sort
"
Screen current listOfAvailableColors
"
"Modified: 11.9.1996 / 15:26:28 / stefan"
!
percentToDeviceColorValue:aPercentage
"given a color-component value in percent (0..100), return the corresponding
x-component value (0..65k) as an integer"
%{ /* NOCONTEXT */
if (__isSmallInteger(aPercentage)) {
RETURN ( __MKSMALLINT(0xFFFF * __intVal(aPercentage) / 100) );
}
if (__isFloat(aPercentage)) {
RETURN ( __MKSMALLINT(0xFFFF * (int)(__floatVal(aPercentage)) / 100) );
}
%}.
^ (16rFFFF * aPercentage / 100) rounded
!
setColor:index scaledRed:sred scaledGreen:sgreen scaledBlue:sblue
"change color in map at:index to rgb (0..16rFFFF).
This method is a noop for StaticGrey, StaticGrey and TrueColor displays."
<context: #return>
%{
char *colorname;
XColor color;
int screen = __intVal(__INST(screen));
int r, g, b;
int ok = 1;
if (__isSmallInteger(sred))
r = __intVal(sred);
else ok = 0;
if (__isSmallInteger(sgreen))
g = __intVal(sgreen);
else ok = 0;
if (__isSmallInteger(sblue))
b = __intVal(sblue);
else ok = 0;
if (ISCONNECTED
&& __isSmallInteger(index) && ok) {
Display *dpy = myDpy;
color.pixel = __intVal(index);
color.red = r;
color.green = g;
color.blue = b;
color.flags = DoRed | DoGreen | DoBlue;
ENTER_XLIB();
XStoreColor(dpy, DefaultColormap(dpy, screen), &color);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
! !
!XWorkstation methodsFor:'cursor stuff'!
builtInCursorShapes
"return a collection of standard cursor names.
Those are built into the XServer and need not be created as
user cursors.
(actually, there are more than those below ...)"
"/ if you add something here, also add to #shapeNumberFromCursor ...
^ #(
#upLeftArrow "/ XC_top_left_arrow
#upRightHand "/ XC_hand1
#upDownArrow "/ XC_sb_v_double_arrow
#leftRightArrow "/ XC_sb_h_double_arrow
#upLimitArrow "/ XC_top_side
#downLimitArrow "/ XC_bottom_side
#leftLimitArrow "/ XC_left_side
#rightLimitArrow "/ XC_right_side
#text "/ XC_xterm
#upRightArrow "/ XC_draft_large
#leftHand "/ XC_hand2
#questionMark "/ XC_question_arrow
#cross "/ XC_X_cursor
#wait "/ XC_watch
#crossHair "/ XC_tcross
#origin "/ XC_ul_angle
#topLeft "/ XC_ul_angle
#corner "/ XC_lr_angle
#bottomRight "/ XC_lr_angle
#topRight "/ XC_ur_angle
#bottomLeft "/ XC_ll_angle
#square "/ XC_dotbox
#fourWay "/ XC_fleur
#crossCursor "/ XC_X_cursor
)
"Created: 8.4.1997 / 10:12:30 / cg"
"Modified: 8.4.1997 / 10:31:46 / cg"
!
colorCursor:aCursorId foreground:fgColor background:bgColor
"change a cursors colors"
<context: #return>
|fgR fgG fgB bgR bgG bgB|
fgR := fgColor scaledRed.
fgG := fgColor scaledGreen.
fgB := fgColor scaledBlue.
bgR := bgColor scaledRed.
bgG := bgColor scaledGreen.
bgB := bgColor scaledBlue.
%{
XColor fgcolor, bgcolor;
if (ISCONNECTED
&& __isExternalAddress(aCursorId)
&& __bothSmallInteger(fgG, fgB)
&& __bothSmallInteger(bgR, bgG)
&& __bothSmallInteger(bgB, fgR)) {
fgcolor.red = __intVal(fgR);
fgcolor.green= __intVal(fgG);
fgcolor.blue = __intVal(fgB);
bgcolor.red = __intVal(bgR);
bgcolor.green= __intVal(bgG);
bgcolor.blue = __intVal(bgB);
ENTER_XLIB();
XRecolorCursor(myDpy, __CursorVal(aCursorId), &fgcolor, &bgcolor);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
createCursorShape:aShape
"create a cursor given a shape-symbol. This only works
for a few standard cursors, and returns nil if no such cursor exists.
Senders must always care for a fallBack, in case of a nil return."
|shapeNumber|
shapeNumber := self shapeNumberFromSymbol:aShape.
shapeNumber isNil ifTrue:[^ nil].
^ self primCreateCursorShapeNumber:shapeNumber
!
createCursorSourceForm:sourceForm maskForm:maskForm hotX:hx hotY:hy width:w height:h
"create a cursor given 2 bitmaps (source, mask) and a hotspot"
^ self
primCreateCursorSourceFormId:sourceForm id
maskFormId:maskForm id
hotX:hx hotY:hy
width:w height:h
!
destroyCursor:aCursorId
"release a cursor - frees any device resources"
<context: #return>
%{
if (! ISCONNECTED) {
RETURN ( self );
}
if (__isExternalAddress(aCursorId)) {
Cursor curs = __CursorVal(aCursorId);
if (curs) {
ENTER_XLIB();
XFreeCursor(myDpy, curs);
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
__cnt_cursor--;
#endif
}
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
needDeviceFormsForCursor
^ true
!
primCreateCursorShapeNumber:aShapeNumber
"create a cursor given a shape-number."
<context: #return>
%{
Cursor newCursor;
if (ISCONNECTED
&& __isSmallInteger(aShapeNumber)) {
ENTER_XLIB();
newCursor = XCreateFontCursor(myDpy, __intVal(aShapeNumber));
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
if (newCursor)
__cnt_cursor++;
#endif
if (newCursor != (Cursor)0) {
RETURN (__MKEXTERNALADDRESS(newCursor));
}
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
!
primCreateCursorSourceFormId:sourceId maskFormId:maskId hotX:hx hotY:hy width:w height:h
"create a cursor given 2 bitmaps (source, mask) and a hotspot"
<context: #return>
%{
Cursor newCursor;
XColor fgColor, bgColor;
if (ISCONNECTED
&& __isExternalAddress(sourceId)
&& __isExternalAddress(maskId)
&& __bothSmallInteger(hx, hy)) {
fgColor.red = 0; /* fg is black */
fgColor.green = 0;
fgColor.blue = 0;
bgColor.red = 0xFFFF; /* bg is white */
bgColor.green = 0xFFFF;
bgColor.blue = 0xFFFF;
ENTER_XLIB();
newCursor = XCreatePixmapCursor(myDpy,
__PixmapVal(sourceId),
__PixmapVal(maskId),
&fgColor, &bgColor, __intVal(hx), __intVal(hy));
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
if (newCursor)
__cnt_cursor++;
#endif
if (newCursor != (Cursor)0) {
RETURN (__MKEXTERNALADDRESS(newCursor));
}
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
!
shapeNumberFromSymbol:shape
"given a shape-symbol, return the corresponding cursor-number,
or nil if no such standard cursor exists."
"/this is pure X-knowlegde - but you may easily add more
"/ if you add something here, also add to #builtInCursorShapes ...
(shape == #upLeftArrow) ifTrue:[ ^ %{ __MKSMALLINT(XC_top_left_arrow) %} "132" ].
(shape == #upRightHand) ifTrue:[ ^ %{ __MKSMALLINT(XC_hand1) %} "58" ].
(shape == #upDownArrow) ifTrue:[ ^ %{ __MKSMALLINT(XC_sb_v_double_arrow) %} "116" ].
(shape == #leftRightArrow) ifTrue:[ ^ %{ __MKSMALLINT(XC_sb_h_double_arrow) %} "108" ].
(shape == #upLimitArrow) ifTrue:[ ^ %{ __MKSMALLINT(XC_top_side) %} "138" ].
(shape == #downLimitArrow) ifTrue:[ ^ %{ __MKSMALLINT(XC_bottom_side) %} "16" ].
(shape == #leftLimitArrow) ifTrue:[ ^ %{ __MKSMALLINT(XC_left_side) %} "70" ].
(shape == #rightLimitArrow) ifTrue:[ ^ %{ __MKSMALLINT(XC_right_side) %} "96" ].
(shape == #text) ifTrue:[ ^ %{ __MKSMALLINT(XC_xterm) %} "152" ].
(shape == #upRightArrow) ifTrue:[ ^ %{ __MKSMALLINT(XC_draft_large) %} "44" ].
(shape == #leftHand) ifTrue:[ ^ %{ __MKSMALLINT(XC_hand2) %} "60" ].
(shape == #questionMark) ifTrue:[ ^ %{ __MKSMALLINT(XC_question_arrow) %} "92" ].
(shape == #cross) ifTrue:[ ^ %{ __MKSMALLINT(XC_X_cursor) %} "0" ].
(shape == #wait) ifTrue:[ ^ %{ __MKSMALLINT(XC_watch) %} "150" ].
(shape == #crossHair) ifTrue:[ ^ %{ __MKSMALLINT(XC_tcross) %} "130" ].
((shape == #origin)
or:[shape == #topLeft]) ifTrue:[ ^ %{ __MKSMALLINT(XC_ul_angle) %} "144" ].
((shape == #corner)
or:[shape == #bottomRight]) ifTrue:[ ^ %{ __MKSMALLINT(XC_lr_angle) %} "78" ].
(shape == #topRight) ifTrue:[ ^ %{ __MKSMALLINT(XC_ur_angle) %} "148" ].
(shape == #bottomLeft) ifTrue:[ ^ %{ __MKSMALLINT(XC_ll_angle) %} "76" ].
(shape == #square) ifTrue:[ ^ %{ __MKSMALLINT(XC_dotbox) %} "40" ].
(shape == #fourWay) ifTrue:[ ^ %{ __MKSMALLINT(XC_fleur) %} "52" ].
(shape == #crossCursor) ifTrue:[ ^ %{ __MKSMALLINT(XC_X_cursor) %} "0" ].
"/ ('XWorkstation [info]: invalid cursorShape:' , shape printString) infoPrintNL.
^ nil
! !
!XWorkstation methodsFor:'drag & drop'!
dndDrop:dropObjects inWindowID:destinationId position:destinationPoint rootPosition:rootPoint
"drop something in some alien view, using the DND protocol.
Returns false, if the drop could not be performed."
|msgType dropColl dropCollSize anyFile anyDir anyText anyOther
dropType dropTypeCode strings sz idx val|
(msgType := self atomIDOf:#DndProtocol) notNil ifTrue:[
"/ DND can drop files, file, dir, links, dirLink and text
"/ check for this.
dropObjects isCollection ifFalse:[
dropColl := Array with:dropObjects
] ifTrue:[
dropColl := dropObjects
].
anyFile := anyDir := anyText := anyOther := false.
dropColl do:[:aDropObject |
aDropObject isFileObject ifTrue:[
aDropObject theObject isDirectory ifTrue:[
anyDir := true
] ifFalse:[
anyFile := true
]
] ifFalse:[
aDropObject isTextObject ifTrue:[
anyText := true
] ifFalse:[
anyOther := true
]
]
].
anyOther ifTrue:[
"/ DND does not support this ...
'XWorkstation [info]: DND can only drop files or text' infoPrintCR.
^ false
].
anyText ifTrue:[
(anyFile or:[anyDir]) ifTrue:[
"/ DND does not support mixed types
'XWorkstation [info]: DND cannot drop both files and text' infoPrintCR.
^ false
]
].
dropCollSize := dropColl size.
anyFile ifTrue:[
dropType := #DndFiles.
dropCollSize == 1 ifTrue:[
dropType := #DndFile
]
] ifFalse:[
anyDir ifTrue:[
dropType := #DndFiles.
dropCollSize == 1 ifTrue:[
dropType := #DndDir
]
] ifFalse:[
anyText ifTrue:[
dropCollSize == 1 ifTrue:[
dropType := #DndText
] ifFalse:[
"/ can only drop a single text object
'XWorkstation [info]: DND can only drop a single text' infoPrintCR.
^ false
]
] ifFalse:[
"/ mhmh ...
'XWorkstation [info]: DND cannot drop this' infoPrintCR.
^ false
]
]
].
dropTypeCode := self dndDropTypes indexOf:dropType.
dropTypeCode == 0 ifTrue:[
'XWorkstation [info]: DND cannot drop this' infoPrintCR.
^ false
].
dropTypeCode := dropTypeCode - 1.
"/ place the selection inTo the DndSelection property
"/ of the rootView ...
"/ ... need a single string, with 0-terminated parts.
strings := OrderedCollection new.
sz := 0.
dropColl do:[:anObject |
|s o|
o := anObject theObject.
anObject isFileObject ifTrue:[
o := o pathName
].
s := o asString.
strings add:s.
sz := sz + (s size) + 1.
].
val := String new:sz.
idx := 1.
strings do:[:aString |
|sz|
sz := aString size.
val replaceFrom:idx to:(idx + sz - 1) with:aString startingAt:1.
idx := idx + sz.
val at:idx put:(Character value:0).
idx := idx + 1
].
self
setProperty:(self atomIDOf:#DndSelection)
type:(self atomIDOf:#STRING)
value:val
for:rootId.
^ self
sendClientEvent:msgType
format:32
to:destinationId
data1:dropTypeCode
data2:0
data3:destinationId
data4:nil
data5:nil.
].
^ false
"Created: 6.4.1997 / 13:39:37 / cg"
"Modified: 6.4.1997 / 14:30:43 / cg"
!
dndDropTypes
"return the dropTypes as supported by DND"
^ #(
DndUnknown "/ 0
DndRawData "/ 1
DndFile "/ 2
DndFiles "/ 3
DndText "/ 4
DndDir "/ 5
DndLink "/ 6
DndExe "/ 7
)
"Created: 6.4.1997 / 12:57:56 / cg"
"Modified: 6.4.1997 / 13:38:52 / cg"
!
drop:aCollectionOfDropObjects inWindowID:destinationId position:destinationPoint rootPosition:rootPoint
"drop something in some alien view.
Returns false, if the drop could not be performed."
"/
"/ see, if the display supports the DND protocol ...
"/
(self atomIDOf:#DndProtocol) notNil ifTrue:[
^ self
dndDrop:aCollectionOfDropObjects
inWindowID:destinationId
position:destinationPoint
rootPosition:rootPoint
].
"/ add more drag&drop protocols here.
^ false
"Modified: 11.4.1997 / 12:44:50 / cg"
! !
!XWorkstation methodsFor:'drawing'!
copyFromId:sourceId x:srcX y:srcY gc:srcGCId to:destId x:dstX y:dstY gc:dstGCId width:w height:h
"do a bit-blt; copy bits from the rectangle defined by
srcX/srcY and w/h from the sourceId drawable to the rectangle
below dstX/dstY in the destId drawable. Trigger an error if any
argument is not integer."
<context: #return>
%{
GC gc;
Drawable source, dest;
if (ISCONNECTED
&& __isExternalAddress(dstGCId)
&& __isExternalAddress(sourceId)
&& __isExternalAddress(destId)
&& __bothSmallInteger(w, h)
&& __bothSmallInteger(srcX, srcY)
&& __bothSmallInteger(dstX, dstY)) {
int _sX, _sY, _w, _h, _dX, _dY;
_sX = __intVal(srcX);
_sY = __intVal(srcY);
_w = __intVal(w);
_h = __intVal(h);
_dX = __intVal(dstX);
_dY = __intVal(dstY);
gc = __GCVal(dstGCId);
source = __DrawableVal(sourceId);
dest = __DrawableVal(destId);
ENTER_XLIB();
XCopyArea(myDpy, source, dest, gc, _sX, _sY, _w, _h, _dX, _dY);
LEAVE_XLIB();
RETURN ( self );
}
%}.
"badGC, bad sourceDrawableId or destDrawableID
or any non integer coordinate"
self primitiveFailedOrClosedConnection
!
copyFromPixmapId:sourceId x:srcX y:srcY gc:srcGCId to:destId x:dstX y:dstY gc:dstGCId width:w height:h
"do a bit-blt from a pix- or bitmap; copy bits from the rectangle defined by
srcX/srcY and w/h from the sourceId drawable to the rectangle
below dstX/dstY in the destId drawable. Trigger an error if any
argument is not integer.
This is basically the same as copyFromId:..., but does not generate expose events."
<context: #return>
%{
GC gc;
Drawable source, dest;
if (ISCONNECTED
&& __isExternalAddress(dstGCId)
&& __isExternalAddress(sourceId)
&& __isExternalAddress(destId)
&& __bothSmallInteger(w, h)
&& __bothSmallInteger(srcX, srcY)
&& __bothSmallInteger(dstX, dstY)) {
Display *dpy = myDpy;
gc = __GCVal(dstGCId);
source = __DrawableVal(sourceId);
dest = __DrawableVal(destId);
ENTER_XLIB();
XSetGraphicsExposures(dpy, gc, 0);
XCopyArea(dpy, source, dest, gc,
__intVal(srcX), __intVal(srcY),
__intVal(w), __intVal(h),
__intVal(dstX), __intVal(dstY));
XSetGraphicsExposures(dpy, gc, 1);
LEAVE_XLIB();
RETURN ( self );
}
%}.
"badGC, bad sourceDrawableId or destDrawableID
or any non integer coordinate"
self primitiveFailedOrClosedConnection
!
copyPlaneFromId:sourceId x:srcX y:srcY gc:srcGCId to:destId x:dstX y:dstY gc:dstGCId width:w height:h
"do a bit-blt, but only copy the low-bit plane;
copy bits from the rectangle defined by
srcX/srcY and w/h from the sourceId drawable to the rectangle
below dstX/dstY in the destId drawable. Trigger an error if any
argument is not integer."
<context: #return>
%{
GC gc;
Drawable source, dest;
if (ISCONNECTED
&& __isExternalAddress(dstGCId)
&& __isExternalAddress(sourceId)
&& __isExternalAddress(destId)
&& __bothSmallInteger(w, h)
&& __bothSmallInteger(srcX, srcY)
&& __bothSmallInteger(dstX, dstY)) {
gc = __GCVal(dstGCId);
source = __DrawableVal(sourceId);
dest = __DrawableVal(destId);
ENTER_XLIB();
XCopyPlane(myDpy, source, dest, gc,
__intVal(srcX), __intVal(srcY),
__intVal(w), __intVal(h),
__intVal(dstX), __intVal(dstY), 1);
LEAVE_XLIB();
RETURN ( self );
}
%}.
"badGC, bad sourceDrawableId or destDrawableID
or any non integer coordinate"
self primitiveFailedOrClosedConnection
!
copyPlaneFromPixmapId:sourceId x:srcX y:srcY gc:srcGCId to:destId x:dstX y:dstY gc:dstGCId width:w height:h
"do a bit-blt from a pix- or bitmap, but only copy the low-bit plane;
copy bits from the rectangle defined by
srcX/srcY and w/h from the sourceId drawable to the rectangle
below dstX/dstY in the destId drawable. Trigger an error if any
argument is not integer.
This is the same as copyPlaneFromId:..., but does not generate graphics exposes"
<context: #return>
%{
GC gc;
Drawable source, dest;
if (ISCONNECTED
&& __isExternalAddress(dstGCId)
&& __isExternalAddress(sourceId)
&& __isExternalAddress(destId)
&& __bothSmallInteger(w, h)
&& __bothSmallInteger(srcX, srcY)
&& __bothSmallInteger(dstX, dstY)) {
Display *dpy = myDpy;
gc = __GCVal(dstGCId);
source = __DrawableVal(sourceId);
dest = __DrawableVal(destId);
ENTER_XLIB();
XSetGraphicsExposures(dpy, gc, 0);
XCopyPlane(dpy, source, dest, gc,
__intVal(srcX), __intVal(srcY),
__intVal(w), __intVal(h),
__intVal(dstX), __intVal(dstY), 1);
XSetGraphicsExposures(dpy, gc, 1);
LEAVE_XLIB();
RETURN ( self );
}
%}.
"badGC, bad sourceDrawableId or destDrawableID
or any non integer coordinate"
self primitiveFailedOrClosedConnection
!
displayArcX:x y:y width:width height:height from:startAngle angle:angle in:aDrawableId with:aGCId
"draw an arc. If any of x,y, w or h is not an integer, an error is triggered.
The angles may be floats or integer - they are given in degrees."
<context: #return>
%{
GC gc;
Window win;
int w, h, angle1, angle2;
double f;
if (__isSmallInteger(startAngle))
angle1 = __intVal(startAngle) * 64;
else if (__isFloat(startAngle)) {
f = __floatVal(startAngle);
angle1 = f * 64;
} else if (__isShortFloat(startAngle)) {
f = __shortFloatVal(startAngle);
angle1 = f * 64;
} else goto bad;
if (__isSmallInteger(angle))
angle2 = __intVal(angle) * 64;
else if (__isFloat(angle)) {
f = __floatVal(angle);
angle2 = f * 64;
} else if (__isShortFloat(angle)) {
f = __shortFloatVal(angle);
angle2 = f * 64;
} else goto bad;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId)
&& __bothSmallInteger(x, y)
&& __bothSmallInteger(width, height)) {
win = __WindowVal(aDrawableId);
gc = __GCVal(aGCId);
w = __intVal(width);
h = __intVal(height);
/*
* need this check here: some servers simply dump core with bad args
*/
if ((w >= 0) && (h >= 0) && (angle1 >= 0) && (angle2 >= 0)) {
ENTER_XLIB();
XDrawArc(myDpy, win, gc, __intVal(x), __intVal(y),
w, h, angle1, angle2);
LEAVE_XLIB();
}
RETURN ( self );
}
bad: ;
%}.
"badGC, badDrawable or coordinates not integer
or angle(s) not integer or float."
self primitiveFailedOrClosedConnection
!
displayLineFromX:x0 y:y0 toX:x1 y:y1 in:aDrawableId with:aGCId
"draw a line. If the coordinates are not integers, an error is triggered."
<context: #return>
%{
GC gc;
Window win;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId)
&& __bothSmallInteger(x0, y0)
&& __bothSmallInteger(x1, y1)) {
Display *dpy = myDpy;
gc = __GCVal(aGCId);
win = __WindowVal(aDrawableId);
ENTER_XLIB();
if ((x0 == x1) && (y0 == y1)) {
XDrawPoint(dpy, win, gc, __intVal(x0), __intVal(y0));
} else {
XDrawLine(dpy, win, gc, __intVal(x0), __intVal(y0),
__intVal(x1), __intVal(y1));
}
LEAVE_XLIB();
RETURN ( self );
}
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailedOrClosedConnection
!
displayLinesFromX:startX step:stepX yValues:yValues scaleY:scaleY transY:transY in:aDrawableId with:aGCId
"draw a polygon starting at x; the y values derives from the collection yValues.
The associated x is a multiple of step. Each y value will be scaled and translated
"
<context: #return>
|noY|
(noY := yValues size) < 2 ifTrue:[
^ self
].
%{
OBJ yA, t;
int i, num;
float y, x, sY, tY, step;
GC gc;
XPoint * points;
XPoint qPoints[200];
int mustFree = 0;
Window win;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId) ) {
gc = __GCVal(aGCId);
win = __WindowVal(aDrawableId);
if( __isSmallInteger(scaleY) )
sY = (float) __intVal( scaleY );
else if (__isFloat(scaleY))
sY = __floatVal( scaleY );
else if (__isShortFloat(scaleY))
sY = __shortFloatVal( scaleY );
else {
t = __SSEND0(scaleY, @symbol(asFloat), 0);
if (! __isFloat(t)) goto fail;
sY = __floatVal( t );
}
if( __isSmallInteger(transY) )
tY = (float) __intVal( transY );
else if (__isFloat(transY))
tY = __floatVal( transY );
else if (__isShortFloat(transY))
tY = __shortFloatVal( transY );
else {
t = __SSEND0(transY, @symbol(asFloat), 0);
if (! __isFloat(t)) goto fail;
tY = __floatVal( t );
}
if( __isSmallInteger(startX) )
x = (float) __intVal( startX );
else if (__isFloat(startX))
x = __floatVal( startX );
else if (__isShortFloat(startX))
x = __shortFloatVal( startX );
else {
t = __SSEND0(startX, @symbol(asFloat), 0);
if (! __isFloat(t)) goto fail;
x = __floatVal( t );
}
if( __isSmallInteger(stepX) )
step = (float) __intVal( stepX );
else if (__isFloat(stepX))
step = __floatVal( stepX );
else if (__isShortFloat(stepX))
step = __shortFloatVal( stepX );
else {
t = __SSEND0(stepX, @symbol(asFloat), 0);
if (! __isFloat(t)) goto fail;
step = __floatVal( t );
}
num = __intVal( noY );
if( num > 200 ) {
if( ! (points = (XPoint *) malloc ( sizeof(XPoint) * num )) )
goto fail;
mustFree = 1;
} else {
points = qPoints;
}
for( i = 0; i < num; ++i ) {
yA = __AT_(yValues, __MKSMALLINT(i+1) );
if( __isFloat(yA) )
y = __floatVal( yA );
else if( __isSmallInteger(yA) )
y = (float) __intVal( yA );
else if( __isShortFloat( yA) )
y = __shortFloatVal( yA );
else {
t = __SSEND0(yA, @symbol(asFloat), 0);
if (! __isFloat(t)) goto fail;
y = __floatVal( t );
}
points[i].x = (int) (x + 0.5);
points[i].y = (int) ((y * sY) + tY + 0.5);
x = x + step;
}
ENTER_XLIB();
XDrawLines(myDpy, win, gc, points, num, CoordModeOrigin);
LEAVE_XLIB();
if( mustFree ) {
free( points );
}
RETURN ( self );
}
fail:
if( mustFree )
free( points );
%}.
^ super displayLinesFromX:startX step:stepX yValues:yValues scaleY:scaleY transY:transY in:aDrawableId with:aGCId
"Modified: / 13.6.1998 / 13:51:39 / cg"
!
displayPointX:x y:y in:aDrawableId with:aGCId
"draw a point. If x/y are not integers, an error is triggered."
<context: #return>
%{
GC gc;
Window win;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId)
&& __bothSmallInteger(x, y)) {
gc = __GCVal(aGCId);
win = __WindowVal(aDrawableId);
ENTER_XLIB();
XDrawPoint(myDpy, win, gc, __intVal(x), __intVal(y));
LEAVE_XLIB();
RETURN ( self );
}
%}.
"badGC, badDrawable or x/y not integer"
self primitiveFailedOrClosedConnection
!
displayPolygon:aPolygon in:aDrawableId with:aGCId
"draw a polygon, the argument aPolygon is a Collection of individual points, which
define the polygon.
If any coordinate is not integer, an error is triggered."
<context: #return>
|numberOfPoints newPoints|
numberOfPoints := aPolygon size.
%{
GC gc;
Window win;
OBJ point, x, y;
int i, num;
XPoint *points;
XPoint qPoints[100];
int mustFree = 0;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId)
&& __isSmallInteger(numberOfPoints)) {
gc = __GCVal(aGCId);
win = __WindowVal(aDrawableId);
num = __intVal(numberOfPoints);
/*
* avoid a (slow) malloc, if the number of points is small
*/
if (num > 100) {
points = (XPoint *)malloc(sizeof(XPoint) * num);
if (! points) goto fail;
mustFree = 1;
} else
points = qPoints;
for (i=0; i<num; i++) {
point = __AT_(aPolygon, __MKSMALLINT(i+1));
if (! __isPoint(point)) goto fail;
x = _point_X(point);
y = _point_Y(point);
if (! __bothSmallInteger(x, y))
goto fail;
points[i].x = __intVal(x);
points[i].y = __intVal(y);
}
ENTER_XLIB();
XDrawLines(myDpy, win, gc, points, num, CoordModeOrigin);
LEAVE_XLIB();
if (mustFree)
free(points);
RETURN ( self );
}
fail: ;
if (mustFree)
free(points);
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailedOrClosedConnection
!
displayRectangleX:x y:y width:width height:height in:aDrawableId with:aGCId
"draw a rectangle. If the coordinates are not integers, an error is triggered."
<context: #return>
%{
GC gc;
Window win;
int w, h;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId)
&& __bothSmallInteger(x, y)
&& __bothSmallInteger(width, height)) {
gc = __GCVal(aGCId);
win = __WindowVal(aDrawableId);
w = __intVal(width);
h = __intVal(height);
/*
* need this check here: some servers simply dump core with bad args
*/
if ((w >= 0) && (h >= 0)) {
ENTER_XLIB();
XDrawRectangle(myDpy, win, gc, __intVal(x), __intVal(y), w, h);
LEAVE_XLIB();
}
RETURN ( self );
}
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailedOrClosedConnection
!
displayString:aString from:index1 to:index2 x:x y:y in:aDrawableId with:aGCId opaque:opaque
"draw a sub-string - if opaque is false, draw foreground only; otherwise, draw both
foreground and background characters.
If the coordinates are not integers, an error is triggered."
<context: #return>
%{
GC gc;
Window win;
char *cp;
OBJ cls;
int i1, i2, l, n;
# define NLOCALBUFFER 200
XChar2b xlatebuffer[NLOCALBUFFER];
int nInstBytes;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId)
&& __isNonNilObject(aString)
&& __bothSmallInteger(index1, index2)
&& __bothSmallInteger(x, y)) {
int lMax = __intVal(@global(XWorkstation:MaxStringLength));
Display *dpy = myDpy;
gc = __GCVal(aGCId);
win = __WindowVal(aDrawableId);
cls = __qClass(aString);
i1 = __intVal(index1) - 1;
if (i1 >= 0) {
i2 = __intVal(index2) - 1;
if (i2 < i1) {
RETURN (self);
}
cp = (char *) __stringVal(aString);
l = i2 - i1 + 1;
if ((cls == @global(String)) || (cls == @global(Symbol))) {
n = __stringSize(aString);
if (i2 < n) {
cp += i1;
if (l > lMax) l = lMax;
ENTER_XLIB();
if (opaque == true)
XDrawImageString(dpy, win, gc, __intVal(x), __intVal(y), cp, l);
else
XDrawString(dpy, win, gc, __intVal(x), __intVal(y), cp, l);
LEAVE_XLIB();
RETURN ( self );
}
}
nInstBytes = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
cp += nInstBytes;
if (__isBytes(aString)) {
n = __byteArraySize(aString) - nInstBytes - 1;
if (i2 < n) {
cp += i1;
if (l > lMax) l = lMax;
ENTER_XLIB();
if (opaque == true)
XDrawImageString(dpy, win, gc, __intVal(x), __intVal(y), cp, l);
else
XDrawString(dpy, win, gc, __intVal(x), __intVal(y), cp, l);
LEAVE_XLIB();
RETURN ( self );
}
}
/* TWOBYTESTRINGS */
if (__isWords(aString)) {
n = (__byteArraySize(aString) - nInstBytes) / 2;
if (i2 < n) {
union {
char b[2];
unsigned short s;
} u;
int i;
XChar2b *cp2 = (XChar2b *)0;
int mustFree = 0;
cp += (i1 * 2);
if (l > lMax) l = lMax;
/*
* ST/X TwoByteStrings store the asciiValue in native byteOrder;
* X expects them MSB first
* convert as required
*/
u.s = 0x1234;
if (u.b[0] != 0x12) {
if (l <= NLOCALBUFFER) {
cp2 = xlatebuffer;
} else {
cp2 = (XChar2b *)(malloc(l * 2));
mustFree = 1;
}
for (i=0; i<l; i++) {
cp2[i].byte1 = (((XChar2b *)cp)[i]).byte2;
cp2[i].byte2 = (((XChar2b *)cp)[i]).byte1;
}
cp = (char *) cp2;
}
ENTER_XLIB();
if (opaque == true)
XDrawImageString16(dpy, win, gc, __intVal(x), __intVal(y), (XChar2b *)cp, l);
else
XDrawString16(dpy, win, gc, __intVal(x), __intVal(y), (XChar2b *)cp, l);
LEAVE_XLIB();
if (mustFree) {
free(cp2);
}
RETURN ( self );
}
}
}
}
#undef NLOCALBUFFER
%}.
"x/y not integer, badGC or drawable, or not a string"
self primitiveFailedOrClosedConnection
!
displayString:aString x:x y:y in:aDrawableId with:aGCId opaque:opaque
"draw a string - if opaque is false, draw foreground only; otherwise, draw both
foreground and background characters.
If the coordinates are not integers, an error is triggered."
<context: #return>
%{
GC gc;
Window win;
char *cp;
int n;
OBJ cls;
# define NLOCALBUFFER 200
XChar2b xlatebuffer[NLOCALBUFFER];
int nInstBytes;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId)
&& __isNonNilObject(aString)
&& __bothSmallInteger(x, y)) {
int lMax = __intVal(@global(XWorkstation:MaxStringLength));
Display *dpy = myDpy;
gc = __GCVal(aGCId);
win = __WindowVal(aDrawableId);
cls = __qClass(aString);
cp = (char *) __stringVal(aString);
if ((cls == @global(String)) || (cls == @global(Symbol))) {
n = __stringSize(aString);
if (n > lMax) n = lMax;
ENTER_XLIB();
if (opaque == true)
XDrawImageString(dpy, win, gc, __intVal(x), __intVal(y), cp, n);
else
XDrawString(dpy, win, gc, __intVal(x), __intVal(y), cp, n);
LEAVE_XLIB();
RETURN ( self );
}
nInstBytes = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
cp += nInstBytes;
if (__isBytes(aString)) {
n = __byteArraySize(aString) - nInstBytes - 1;
if (n > lMax) n = lMax;
ENTER_XLIB();
if (opaque == true)
XDrawImageString(dpy, win, gc, __intVal(x), __intVal(y), cp, n);
else
XDrawString(dpy, win, gc, __intVal(x), __intVal(y), cp, n);
LEAVE_XLIB();
RETURN ( self );
}
/* TWOBYTESTRINGS */
if (__isWords(aString)) {
union {
char b[2];
unsigned short s;
} u;
int i;
XChar2b *cp2;
int mustFree = 0;
n = (__byteArraySize(aString) - nInstBytes) / 2;
if (n > lMax) n = lMax;
/*
* ST/X TwoByteStrings store the asciiValue in native byteOrder;
* X expects them MSB first
* convert as required
*/
u.s = 0x1234;
if (u.b[0] != 0x12) {
if (n <= NLOCALBUFFER) {
cp2 = xlatebuffer;
} else {
cp2 = (XChar2b *)(malloc(n * 2));
mustFree = 1;
}
for (i=0; i<n; i++) {
cp2[i].byte1 = (((XChar2b *)cp)[i]).byte2;
cp2[i].byte2 = (((XChar2b *)cp)[i]).byte1;
}
cp = (char *) cp2;
}
ENTER_XLIB();
if (opaque == true)
XDrawImageString16(dpy, win, gc, __intVal(x), __intVal(y), (XChar2b *)cp, n);
else
XDrawString16(dpy, win, gc, __intVal(x), __intVal(y), (XChar2b *)cp, n);
LEAVE_XLIB();
if (mustFree) {
free(cp2);
}
RETURN ( self );
}
}
#undef NLOCALBUFFER
%}.
^ super displayString:aString x:x y:y in:aDrawableId with:aGCId opaque:opaque
!
drawBits:givenBits bitsPerPixel:bitsPerPixel depth:imageDepth padding:givenPadding
width:imageWidth height:imageHeight
x:srcx y:srcy
into:aDrawableId
x:dstx y:dsty
width:w height:h
with:aGCId
"draw a bitImage which has depth id, width iw and height ih into
the drawable. draw a region of w/h pixels from srcx/srcy to dstx/dsty.
Individual source pixels have bitsPerPixel bits, allowing to draw
depth and pixel-units to be different.
It has to be checked elsewhere, that the server can do it with the given
depth - otherwise, primitive failure will be signalled.
Also it is assumed, that the colormap is setup correctly and the
colors are allocated - otherwise the colors may be wrong."
|fmt padding bits wantedPadding|
padding := givenPadding.
bits := givenBits.
"/ the XF86_VGA16 server seems to report an error when we pass it an
"/ 8-bit padded image. (it wants it 32bit padded).
"/ as a workaround, repad it here (although, the server and/or Xlib should
"/ care for that.
((imageDepth == 4) and:[depth == 4]) ifTrue:[
fmt := self supportedImageFormatForDepth:4.
fmt isNil ifTrue:[
self primitiveFailed. "/ cannot represent this image
^ nil
].
wantedPadding := fmt at:#padding.
wantedPadding > givenPadding ifTrue:[
bits := self
repadBits:givenBits
width:imageWidth
height:imageHeight
depth:imageDepth
from:givenPadding
to:wantedPadding.
padding := wantedPadding.
]
].
"
sorry; I had to separate it into 2 methods, since XPutImage needs
an unlimited stack, and thus cannot send primitiveFailed
"
(self
primDrawBits:bits
bitsPerPixel:bitsPerPixel
depth:imageDepth
padding:padding
width:imageWidth height:imageHeight
x:srcx y:srcy
into:aDrawableId
x:dstx y:dsty
width:w height:h
with:aGCId)
ifFalse:[
"
also happens, if a segmentation violation occurs in the
XPutImage ...
"
self primitiveFailedOrClosedConnection
].
!
fillArcX:x y:y width:width height:height from:startAngle angle:angle
in:aDrawableId with:aGCId
"fill an arc. If any coordinate is not integer, an error is triggered.
The angles may be floats or integer - they are given in degrees."
<context: #return>
%{
GC gc;
Window win;
int w, h, angle1, angle2;
double f;
if (__isSmallInteger(startAngle))
angle1 = __intVal(startAngle) * 64;
else if (__isFloat(startAngle)) {
f = __floatVal(startAngle);
angle1 = f * 64;
} else if (__isShortFloat(startAngle)) {
f = __shortFloatVal(startAngle);
angle1 = f * 64;
} else goto bad;
if (__isSmallInteger(angle))
angle2 = __intVal(angle) * 64;
else if (__isFloat(angle)) {
f = __floatVal(angle);
angle2 = f * 64;
} else if (__isShortFloat(angle)) {
f = __shortFloatVal(angle);
angle2 = f * 64;
} else goto bad;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId)
&& __bothSmallInteger(x, y)
&& __bothSmallInteger(width, height)) {
gc = __GCVal(aGCId);
win = __WindowVal(aDrawableId);
w = __intVal(width);
h = __intVal(height);
/*
* need this check here: some servers simply dump core with bad args
*/
if ((w >= 0) && (h >= 0) && (angle1 >= 0) && (angle2 >= 0)) {
ENTER_XLIB();
XFillArc(myDpy, win, gc, __intVal(x), __intVal(y),
w, h, angle1, angle2);
LEAVE_XLIB();
}
RETURN ( self );
}
bad: ;
%}.
"badGC, badDrawable or coordinates not integer
or non float angle(s)"
self primitiveFailedOrClosedConnection
!
fillPolygon:aPolygon in:aDrawableId with:aGCId
"fill a polygon given by its points.
If any coordinate is not integer, an error is triggered."
<context: #return>
|numberOfPoints|
numberOfPoints := aPolygon size.
%{
GC gc;
Window win;
OBJ point, x, y;
int i, num;
XPoint *points;
XPoint qPoints[100];
int mustFree = 0;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId)
&& __isSmallInteger(numberOfPoints)) {
gc = __GCVal(aGCId);
win = __WindowVal(aDrawableId);
num = __intVal(numberOfPoints);
if (num < 3) {
RETURN ( self );
}
/*
* avoid (slow) malloc, if not many points
*/
if (num > 100) {
points = (XPoint *) malloc(sizeof(XPoint) * num);
if (! points) goto fail;
mustFree = 1;
} else
points = qPoints;
for (i=0; i<num; i++) {
point = __AT_(aPolygon, __MKSMALLINT(i+1));
if (! __isPoint(point)) goto fail;
x = _point_X(point);
y = _point_Y(point);
if (! __bothSmallInteger(x, y))
goto fail;
points[i].x = __intVal(x);
points[i].y = __intVal(y);
}
ENTER_XLIB();
XFillPolygon(myDpy, win, gc, points, num, Complex, CoordModeOrigin);
LEAVE_XLIB();
if (mustFree)
free(points);
RETURN ( self );
fail: ;
if (mustFree)
free(points);
}
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailedOrClosedConnection
!
fillRectangleX:x y:y width:width height:height in:aDrawableId with:aGCId
"fill a rectangle. If any coordinate is not integer, an error is triggered."
<context: #return>
%{
int w, h;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId)
&& __bothSmallInteger(x, y)
&& __bothSmallInteger(width, height)) {
w = __intVal(width);
h = __intVal(height);
/*
* need this check here: some servers simply dump core with bad args
*/
if ((w >= 0) && (h >= 0)) {
ENTER_XLIB();
XFillRectangle(myDpy,
__DrawableVal(aDrawableId), __GCVal(aGCId),
__intVal(x), __intVal(y), w, h);
LEAVE_XLIB();
}
RETURN ( self );
}
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailedOrClosedConnection
!
primDrawBits:imageBits bitsPerPixel:bitsPerPixel depth:imageDepth padding:bitPadding
width:imageWidth height:imageHeight
x:srcx y:srcy
into:aDrawableId
x:dstx y:dsty
width:w height:h
with:aGCId
<context: #return>
"since XPutImage may allocate huge amount of stack space
(some implementations use alloca), this must run with unlimited stack."
%{ /* UNLIMITEDSTACK */
/*
* need unlimited stack, since some Xlibs do a huge alloca in
* XPutImage
*/
GC gc;
Window win;
XImage image;
int imgWdth;
if (ISCONNECTED
&& __isExternalAddress(aGCId)
&& __isExternalAddress(aDrawableId)
&& __bothSmallInteger(srcx, srcy)
&& __bothSmallInteger(dstx, dsty)
&& __bothSmallInteger(w, h)
&& __bothSmallInteger(imageWidth, imageHeight)
&& __bothSmallInteger(imageDepth, bitsPerPixel)
&& __isSmallInteger(bitPadding)
&& __isByteArray(imageBits)) {
Display *dpy = myDpy;
int pad = __intVal(bitPadding);
gc = __GCVal(aGCId);
win = __WindowVal(aDrawableId);
if (! gc || !win)
goto fail;
#ifdef ARGDEBUG
printf("args ok\n");
#endif
image.data = (char *)__ByteArrayInstPtr(imageBits)->ba_element;
image.width = imgWdth = __intVal(imageWidth);
image.height = __intVal(imageHeight);
image.xoffset = 0;
image.format = ZPixmap;
image.byte_order = MSBFirst;
image.bitmap_unit = 8;
image.bitmap_bit_order = MSBFirst;
image.bitmap_pad = pad;
image.depth = __intVal(imageDepth);
image.bits_per_pixel = __intVal(bitsPerPixel);
/*
image.bytes_per_line = ((((imgWdth * image.depth) + (pad-1)) / pad) * pad) / 8;
*/
image.bytes_per_line = ((((imgWdth * image.bits_per_pixel) + (pad-1)) / pad) * pad) / 8;
switch (image.bits_per_pixel) {
case 1:
case 2:
case 4:
case 8:
case 16:
case 24:
case 32:
break;
default:
#ifdef ARGDEBUG
printf("bits_per_pixel=%d\n",image.bits_per_pixel);
#endif
goto fail;
}
image.red_mask = 0xFFFF;
image.green_mask = 0xFFFF;
image.blue_mask = 0xFFFF;
/* ENTER_XLIB(); */
XPutImage(dpy, win, gc, &image, __intVal(srcx), __intVal(srcy),
__intVal(dstx), __intVal(dsty),
__intVal(w), __intVal(h));
/* LEAVE_XLIB(); */
RETURN ( true );
}
#ifdef ARGDEBUG
if (!! __isExternalAddress(aGCId)) printf("GC\n");
if (!! __isExternalAddress(aDrawableId)) printf("aDrawableId\n");
if (!! __isSmallInteger(srcx)) printf("srcx\n");
if (!! __isSmallInteger(srcy)) printf("srcy\n");
if (!! __isSmallInteger(dstx)) printf("dstx\n");
if (!! __isSmallInteger(dsty)) printf("dsty\n");
if (!! __isSmallInteger(w)) printf("w\n");
if (!! __isSmallInteger(h)) printf("h\n");
if (!! __isSmallInteger(imageWidth)) printf("imageWidth\n");
if (!! __isSmallInteger(imageHeight)) printf("imageHeight\n");
if (!! __isSmallInteger(imageDepth)) printf("imageDepth\n");
if (!! __isSmallInteger(bitsPerPixel)) printf("bitsPerPixel\n");
if (!! __isByteArray(imageBits)) printf("imageBits\n");
#endif
fail: ;
%}
.
^ false
! !
!XWorkstation methodsFor:'event forwarding'!
buttonMotion:view state:state x:x y:y rootX:rX rootY:rY time:time
"forward a buttonMotion event for some view"
self buttonMotion:state x:x y:y view:view
!
buttonPress:view button:button state:state x:x y:y rootX:rX rootY:rY time:time
"forward a buttonPress event for some view"
|logicalButton nextMultiClickTime|
altDown := state bitTest:altModifierMask.
metaDown := state bitTest:metaModifierMask.
shiftDown := state bitTest:(self shiftModifierMask).
ctrlDown := state bitTest:(self ctrlModifierMask).
eventRootX := rX.
eventRootY := rY.
"/ physical to logical button translation
logicalButton := buttonTranslation at:button ifAbsent:button.
"/ special for mouse-wheel implementation
(logicalButton == #wheelFwd or:[logicalButton == #wheelBwd]) ifTrue:[
self mouseWheelMotion:state x:x y:y amount:(logicalButton == #wheelFwd ifTrue:[10] ifFalse:[-10]) deltaTime:10 view:view.
^ self.
].
logicalButton isInteger ifTrue:[
buttonsPressed := buttonsPressed bitOr:(1 bitShift:logicalButton-1).
].
multiClickTimeDelta notNil ifTrue:[
nextMultiClickTime := time + multiClickTimeDelta.
multiClickTime notNil ifTrue:[
time < multiClickTime ifTrue:[
multiClickTime := nextMultiClickTime.
self buttonMultiPress:logicalButton x:x y:y view:view.
^ self.
]
].
multiClickTime := nextMultiClickTime.
].
view isNil ifTrue:[
"/ event arrived, after I destroyed it myself
^ self
].
logicalButton == 1 ifTrue:[
activateOnClick == true ifTrue:[
"/ dont raise above an active popup view.
(activeKeyboardGrab isNil and:[activePointerGrab isNil]) ifTrue:[
view topView raise.
]
].
].
super buttonPress:logicalButton x:x y:y view:view
!
buttonRelease:view button:button state:state x:x y:y rootX:rX rootY:rY time:time
"forward a buttonPress event for some view"
|logicalButton|
altDown := state bitTest:altModifierMask.
metaDown := state bitTest:metaModifierMask.
shiftDown := state bitTest:(self shiftModifierMask).
ctrlDown := state bitTest:(self ctrlModifierMask).
eventRootX := rX.
eventRootY := rY.
"/ physical to logical button translation
logicalButton := buttonTranslation at:button ifAbsent:button.
"/ special for HPs mouse-wheel implementation
(logicalButton == #wheelFwd or:[logicalButton == #wheelBwd]) ifTrue:[
^ self
].
logicalButton isInteger ifTrue:[
buttonsPressed := buttonsPressed bitClear:(1 bitShift:logicalButton-1).
].
self buttonRelease:logicalButton x:x y:y view:view
!
circulateNotify:aView place:aSymbol
"sent, when the stacking order changes.
ignored for now."
!
circulateRequest:aView place:aSymbol
"sent, when the stacking order is about to change.
ignored for now."
!
clientMessage:targetView type:typeAtom format:format data:data
|sensor|
"/ DND drag&drop protocol
typeAtom == (self atomIDOf:#DndProtocol) ifTrue:[
format == 32 ifTrue:[
self dndMessage:nil data:data view:targetView.
^ self
]
].
(sensor := targetView sensor) notNil ifTrue:[
sensor clientMessage:typeAtom format:format eventData:data view:targetView
] ifFalse:[
"
not posted, if there is no sensor ...
"
]
"Created: 4.4.1997 / 17:49:26 / cg"
"Modified: 4.4.1997 / 18:00:18 / cg"
!
colorMapNotify:aView state:aBoolean
"sent, when another colormap is installed.
This is a very X-specific mechanism."
aView isNil ifTrue:[
"/ event arrived, after I destroyed it myself
^ self
].
"/ not yet implemented
"/ aView colorMapChange
!
configure:view x:x y:y width:w height:h above:above
"forward a size-change event for some view"
self configureX:x y:y width:w height:h view:view
!
configureRequest:view x:x y:y width:w height:h above:above detail:detail
"ignored for now"
"/ view configureRequest
!
dndMessage:event data:data view:targetView
"handle a DND drag&drop protocol message"
|sensor dropType dropValue names i1 i2 t|
dropType := data doubleWordAt:1.
"/ see def's in DragAndDropTypes.h
dropType := (self dndDropTypes) at:dropType+1 ifAbsent:#DndNotDnd.
self
getProperty:(self atomIDOf:#DndSelection)
from:rootId
into:[:type :value |
t := type.
dropValue := value
].
"/ preconvert into a collection
"/ of fileNames, string or byteArray
"/ Notice: we do not yet convert into dropObjects
"/ here, to allow arbitrary data to be handled by
"/ redefined dropMessage methods in applications.
"/ Conversion is done for some well known types
"/ in the default dropMessage handling of SimpleView.
dropType == #DndFiles ifTrue:[
"/ actually, a list of fileNames
t ~~ stringAtom ifTrue:[
'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
^ self
].
names := OrderedCollection new.
i1 := 1.
[i1 ~~ 0] whileTrue:[
i2 := dropValue indexOf:(Character value:0) startingAt:i1.
i2 ~~ 0 ifTrue:[
names add:(dropValue copyFrom:i1 to:(i2-1)).
i1 := i2 + 1.
] ifFalse:[
i1 := i2
].
].
dropValue := names.
dropValue := dropValue collect:[:nm | nm asFilename].
dropType := #files.
] ifFalse:[ (dropType == #DndFile) ifTrue:[
t ~~ stringAtom ifTrue:[
'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
^ self
].
dropValue := dropValue asFilename.
dropType := #file.
] ifFalse:[ (dropType == #DndDir) ifTrue:[
t ~~ stringAtom ifTrue:[
'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
^ self
].
dropValue := dropValue asFilename.
dropType := #directory.
] ifFalse:[ (dropType == #DndText) ifTrue:[
t ~~ stringAtom ifTrue:[
'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
^ self
].
dropValue := dropValue.
dropType := #text.
] ifFalse:[ (dropType == #DndExe) ifTrue:[
t ~~ stringAtom ifTrue:[
'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
^ self
].
dropValue := dropValue.
dropType := #executable.
] ifFalse:[ (dropType == #DndLink) ifTrue:[
t ~~ stringAtom ifTrue:[
'XWorkstation [info]: expected a string propertyValue in drop' infoPrintCR.
^ self
].
dropValue := dropValue.
dropType := #link.
] ifFalse:[ (dropType == #DndRawData) ifTrue:[
dropValue := dropValue.
dropType := #rawData.
] ifFalse:[
'XWorkstation [info]: unsupported dropType: ' infoPrint. dropType infoPrintCR.
'XWorkstation [info]: data: ' infoPrint. dropValue infoPrintCR.
dropValue := dropValue.
dropType := #unknown.
]]]]]]].
(sensor := targetView sensor) notNil ifTrue:[
sensor dropMessage:dropType data:dropValue view:targetView
] ifFalse:[
"
not posted, if there is no sensor ...
"
]
"Created: 4.4.1997 / 17:59:37 / cg"
"Modified: 6.4.1997 / 14:50:44 / cg"
!
expose:view x:x y:y width:w height:h count:count
"forward an expose event for some view"
self exposeX:x y:y width:w height:h view:view.
!
focusIn:view mode:mode detail:detail
"forward a key-press event for some view"
self focusInView:view
!
focusOut:view mode:mode detail:detail
"forward a key-press event for some view"
self focusOutView:view
!
graphicsExpose:view x:x y:y width:w height:h count:count
"forward a graphics-expose event for some view"
self graphicsExposeX:x y:y width:w height:h final:(count==0) view:view
!
gravityNotify:aView x:x y:y
"ignored for now"
"/ aView gravityNotify
!
keyPress:view key:key code:keyCode state:state x:x y:y rootX:rX rootY:rY time:time
"forward a key-press event for some view"
altDown := state bitTest:altModifierMask.
metaDown := state bitTest:metaModifierMask.
shiftDown := state bitTest:(self shiftModifierMask).
ctrlDown := state bitTest:(self ctrlModifierMask).
key isNil ifTrue:[
"/ happens sometimes on some systems
"/ (alt-graph on sun has no keysym)
^ self
].
eventRootX := rX.
eventRootY := rY.
self keyPress:key x:x y:y view:view.
!
keyRelease:view key:key code:keyCode state:state x:x y:y rootX:rX rootY:rY time:time
"forward a key-release event for some view"
altDown := state bitTest:altModifierMask.
metaDown := state bitTest:metaModifierMask.
shiftDown := state bitTest:(self shiftModifierMask).
ctrlDown := state bitTest:(self ctrlModifierMask).
key isNil ifTrue:[
"/ happens sometimes on some systems
"/ (alt-graph on sun has no keysym)
^ self
].
eventRootX := rX.
eventRootY := rY.
self keyRelease:key x:x y:y view:view.
!
keymapNotify:aView
"ignore for now"
!
mapRequest:aView
"ignored for now"
"/ aView mapRequest
!
mappingNotify:view request:what event:eB
"One of Keyboard-, Modifier- or PointerMap has changed, probably by xmodmap.
Tell xlib about the fact."
(what == #mappingKeyboard or:[what == #mappingModifier]) ifTrue:[
self refreshKeyboardMapping:eB.
"Maybe some of our modifiers have been changed"
self initializeModifierMappings.
].
!
pointerEnter:view x:x y:y rootX:rX rootY:rY state:state mode:mode detail:detail time:time
"forward a pointer enter event for some view"
altDown := state bitTest:altModifierMask.
metaDown := state bitTest:metaModifierMask.
shiftDown := state bitTest:(self shiftModifierMask).
ctrlDown := state bitTest:(self ctrlModifierMask).
eventRootX := rX.
eventRootY := rY.
self pointerEnter:state x:x y:y view:view
!
pointerLeave:view x:x y:y rootX:rX rootY:rY state:state mode:mode detail:detail time:time
"forward a pointer leave event for some view"
altDown := state bitTest:altModifierMask.
metaDown := state bitTest:metaModifierMask.
shiftDown := state bitTest:(self shiftModifierMask).
ctrlDown := state bitTest:(self ctrlModifierMask).
eventRootX := rX.
eventRootY := rY.
self pointerLeave:state view:view
!
propertyChange:aView atom:atom state:aSymbol time:time
"sent when an X property changes.
This is a very X-specific mechanism."
aView isNil ifTrue:[
"/ event arrived, after I destroyed it myself
^ self
].
aView propertyChange
!
reparentedView:aView
"ignored for now"
"/ aView reparented
!
resizeRequest:aView width:width height:height
"ignored for now"
"/ aView resizeRequest
!
selectionClear:aView atom:selectionID time:time
"sent when another X-client has created a selection.
This is a very X-specific mechanism."
"/
"/ workaround a bug in olvwm: it clears selections
"/ on window raise.
"/ In this case, keep my last own selection.
"/
self setLastCopyBuffer:(self getCopyBuffer).
self setCopyBuffer:nil
"/ noone is interested in that ...
"/ aView selectionClear:selectionID
!
selectionNotify:aView selection:selectionID target:targetID property:propertyID requestor:requestorID time:time
"sent when the server returns an answer from a request for a selection.
This is a very X-specific mechanism."
|s sensor|
propertyID == 0 ifTrue:[
"invalid olvwm behavior"
s := self getLastCopyBuffer
] ifFalse:[
targetID == (self atomIDOf:#STRING) ifTrue:[
"
a returned string
"
s := self getTextProperty:propertyID from:requestorID.
s notNil ifTrue:[
(s endsWith:Character cr) ifTrue:[
s := s asStringCollection copyWith:''
]
]
] ifFalse:[
"
a returned object
"
s := self getObjectProperty:propertyID from:requestorID.
].
].
s notNil ifTrue:[
(sensor := aView sensor) notNil ifTrue:[
sensor pasteFromClipBoard:s view:aView
] ifFalse:[
"
if there is no sensor ...
"
aView pasteFromClipBoard:s
]
]
!
selectionRequest:aView requestor:requestorID selection:selectionID target:targetID property:propertyID time:time
"sent by some other X-client to ask for the selection.
This is a very X-specific mechanism."
|o s stream stringAtom|
"/targetID printCR.
targetID == (self atomIDOf:#LENGTH) ifTrue:[
"/
"/ the other one wants to know the size of our selection ...
"/
s := self selectionAsString.
self
setLengthProperty:propertyID
value:s size
for:requestorID.
self
sendSelectionNotifySelection:selectionID
property:propertyID
target:targetID
time:time
from:aView id
to:requestorID.
^ self
].
stringAtom := self atomIDOf:#STRING.
(targetID == stringAtom or:[
targetID == (self atomIDOf:#'COMPOUND_TEXT')]) ifTrue:[
"/
"/ the other view wants the selection as string
"/
s := self selectionAsString.
self
sendSelection:s
selection:primaryAtom
property:propertyID
target:stringAtom "/ targetID, once I can provide compountText as well
time:time
from:requestorID
to:requestorID.
^ self
].
"/ (targetID == (self atomIDOf:#'TARGETS')) ifTrue:[
"/"/ TODO: implement this to avoid netscape paste-delay.
"/"/
"/ ^ self
"/ ].
(targetID == (self atomIDOf:#'ST_OBJECT')) ifTrue:[
"/
"/ send the selection in binaryStore format
"/ (assuming, that the other view knows how to handle it)
"/
o := self getCopyBuffer.
stream := WriteStream on:(ByteArray new:200).
o storeBinaryOn:stream.
^ self
sendSelection:(stream contents)
selection:primaryAtom
property:propertyID
target:targetID
time:time
from:aView id
to:requestorID
].
!
visibilityNotify:aView state:how
aView notNil ifTrue:[
aView visibilityChange:how
]
! !
!XWorkstation methodsFor:'event handling'!
decomposeEventBuffer:aByteArray into:eventArr
"extracet event fields and place them into an array:
the fields are:
1: windowID
2: eventType-ID
3: eventTypeSymbol
4.. args
"
%{
# define ANYBUTTON (Button1MotionMask | Button2MotionMask | Button3MotionMask)
OBJ eB;
XEvent *ev;
int ev_x, ev_y;
# define ae ((XAnyEvent *)ev)
# define ee ((XExposeEvent *)ev)
# define ke ((XKeyPressedEvent *)ev)
# define be ((XButtonPressedEvent *)ev)
# define ce ((XConfigureEvent *)ev)
# define cr ((XConfigureRequestEvent *)ev)
# define me ((XMotionEvent *)ev)
# define ele ((XCrossingEvent *)ev)
# define de ((XDestroyWindowEvent *)ev)
# define ve ((XVisibilityEvent *)ev)
# define fe ((XFocusChangeEvent *)ev)
# define cre ((XCreateWindowEvent *)ev)
# define mape ((XMappingEvent *)ev)
# define gre ((XGravityEvent *)ev)
# define rr ((XResizeRequestEvent *)ev)
# define cie ((XCirculateEvent *)ev)
# define pe ((XPropertyEvent *)ev)
# define sce ((XSelectionClearEvent *)ev)
# define cme ((XColormapEvent *)ev)
KeySym keySym;
unsigned char buffer[10];
int i, nchars;
char *keySymString;
char keySymStringBuffer[32];
unsigned INT nextMultiClickTime;
OBJ arg, sym, t, windowID;
eB = aByteArray;
if (__isByteArray(eB)) {
ev = (XEvent *)(__ByteArrayInstPtr(eB)->ba_element);
} else {
printf("DISPLAY: no eventBuffer\n");
RETURN (false);
}
if (!__isArray(eventArr)) {
printf("DISPLAY: bad argument\n");
RETURN (false);
}
if (__arraySize(eventArr) < 11) {
printf("DISPLAY: bad argument\n");
RETURN (false);
}
if (((t = __INST(lastId)) != nil)
&& __isExternalAddress(t)
&& (__WindowVal(t) == ae->window)) {
windowID = t;
} else {
windowID = __MKEXTERNALADDRESS(ae->window);
}
__ArrayInstPtr(eventArr)->a_element[0] = windowID; __STORE(eventArr, windowID);
__ArrayInstPtr(eventArr)->a_element[1] = __MKSMALLINT(ev->type);
switch (ev->type) {
case KeyRelease:
sym = @symbol(keyRelease:key:code:state:x:y:rootX:rootY:time:);
goto keyPressAndRelease;
case KeyPress:
sym = @symbol(keyPress:key:code:state:x:y:rootX:rootY:time:);
/* FALL INTO */
keyPressAndRelease:
arg = nil;
nchars = XLookupString(ke, (char *)buffer, sizeof(buffer), &keySym, NULL);
if (nchars
&& (((buffer[0] >= ' ') && (buffer[0] <= '~'))
|| (buffer[0] >= 0x80))) {
arg = _MKCHARACTER(buffer[0])/* *_CharacterTable[buffer[0]] */;
keySymString = NULL;
} else {
keySymString = XKeysymToString(keySym);
if (keySymString) {
arg = __MKSTRING(keySymString);
}
}
if (arg == nil) {
/* happens sometimes (alt-graph on sun has no keysym) */
RETURN (false);
}
__ArrayInstPtr(eventArr)->a_element[2] = sym;
__ArrayInstPtr(eventArr)->a_element[3] = arg; __STORE(eventArr, arg);
__ArrayInstPtr(eventArr)->a_element[4] = t = __MKUINT(ke->keycode); __STORE(eventArr, t);
__ArrayInstPtr(eventArr)->a_element[5] = __mkSmallInteger(ke->state);
__ArrayInstPtr(eventArr)->a_element[6] = __mkSmallInteger(ke->x);
__ArrayInstPtr(eventArr)->a_element[7] = __mkSmallInteger(ke->y);
__ArrayInstPtr(eventArr)->a_element[8] = __mkSmallInteger(ke->x_root);
__ArrayInstPtr(eventArr)->a_element[9] = __mkSmallInteger(ke->y_root);
__ArrayInstPtr(eventArr)->a_element[10] = t = __MKUINT(ke->time); __STORE(eventArr, t);
RETURN (true);
case ButtonPress:
sym = @symbol(buttonPress:button:state:x:y:rootX:rootY:time:);
goto buttonPressAndRelease;
case ButtonRelease:
sym = @symbol(buttonRelease:button:state:x:y:rootX:rootY:time:);
/* fall into */
buttonPressAndRelease:
__ArrayInstPtr(eventArr)->a_element[2] = sym;
__ArrayInstPtr(eventArr)->a_element[3] = __mkSmallInteger(be->button);
__ArrayInstPtr(eventArr)->a_element[4] = __mkSmallInteger(ke->state);
__ArrayInstPtr(eventArr)->a_element[5] = __mkSmallInteger(be->x);
__ArrayInstPtr(eventArr)->a_element[6] = __mkSmallInteger(be->y);
__ArrayInstPtr(eventArr)->a_element[7] = __mkSmallInteger(be->x_root);
__ArrayInstPtr(eventArr)->a_element[8] = __mkSmallInteger(be->y_root);
__ArrayInstPtr(eventArr)->a_element[9] = t = __MKUINT(be->time); __STORE(eventArr, t);
RETURN (true);
case MotionNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(buttonMotion:state:x:y:rootX:rootY:time:);
__ArrayInstPtr(eventArr)->a_element[3] = __mkSmallInteger(me->state);
__ArrayInstPtr(eventArr)->a_element[4] = __mkSmallInteger(me->x);
__ArrayInstPtr(eventArr)->a_element[5] = __mkSmallInteger(me->y);
__ArrayInstPtr(eventArr)->a_element[6] = __mkSmallInteger(me->x_root);
__ArrayInstPtr(eventArr)->a_element[7] = __mkSmallInteger(me->y_root);
__ArrayInstPtr(eventArr)->a_element[8] = t = __MKUINT(me->time); __STORE(eventArr, t);
RETURN (true);
case FocusIn:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(focusIn:mode:detail:);
goto focusInOut;
case FocusOut:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(focusOut:mode:detail:);
/* fall into */
focusInOut:
__ArrayInstPtr(eventArr)->a_element[3] = __mkSmallInteger(fe->mode);
__ArrayInstPtr(eventArr)->a_element[4] = __mkSmallInteger(fe->detail);
RETURN (true);
case EnterNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(pointerEnter:x:y:rootX:rootY:state:mode:detail:time:);
goto enterLeave;
case LeaveNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(pointerLeave:x:y:rootX:rootY:state:mode:detail:time:);
/* fall into */
enterLeave:
__ArrayInstPtr(eventArr)->a_element[3] = __mkSmallInteger(ele->x);
__ArrayInstPtr(eventArr)->a_element[4] = __mkSmallInteger(ele->y);
__ArrayInstPtr(eventArr)->a_element[5] = __mkSmallInteger(ele->x_root);
__ArrayInstPtr(eventArr)->a_element[6] = __mkSmallInteger(ele->y_root);
__ArrayInstPtr(eventArr)->a_element[7] = __mkSmallInteger(ele->state);
__ArrayInstPtr(eventArr)->a_element[8] = __mkSmallInteger(ele->mode);
__ArrayInstPtr(eventArr)->a_element[9] = __mkSmallInteger(ele->detail);
__ArrayInstPtr(eventArr)->a_element[10] = t = __MKUINT(ele->time); __STORE(eventArr, t);
RETURN (true);
case Expose:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(expose:x:y:width:height:count:);
goto expose;
case GraphicsExpose:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(graphicsExpose:x:y:width:height:count:);
/* fall into */
expose:
__ArrayInstPtr(eventArr)->a_element[3] = __mkSmallInteger(ee->x);
__ArrayInstPtr(eventArr)->a_element[4] = __mkSmallInteger(ee->y);
__ArrayInstPtr(eventArr)->a_element[5] = __mkSmallInteger(ee->width);
__ArrayInstPtr(eventArr)->a_element[6] = __mkSmallInteger(ee->height);
__ArrayInstPtr(eventArr)->a_element[7] = __mkSmallInteger(ee->count);
RETURN (true);
case NoExpose:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(noExposeView:);
RETURN (true);
case VisibilityNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(visibilityNotify:state:);
switch (ve->state) {
case VisibilityUnobscured:
__ArrayInstPtr(eventArr)->a_element[3] = @symbol(unobscured);
break;
case VisibilityPartiallyObscured:
__ArrayInstPtr(eventArr)->a_element[3] = @symbol(partiallyObscured);
break;
case VisibilityFullyObscured:
__ArrayInstPtr(eventArr)->a_element[3] = @symbol(fullyObscured);
break;
default:
__ArrayInstPtr(eventArr)->a_element[3] = __MKSMALLINT(ve->state);
break;
}
RETURN (true);
case CreateNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(createWindow:x:y:width:height:);
__ArrayInstPtr(eventArr)->a_element[3] = __mkSmallInteger(cre->x);
__ArrayInstPtr(eventArr)->a_element[4] = __mkSmallInteger(cre->y);
__ArrayInstPtr(eventArr)->a_element[5] = __mkSmallInteger(cre->width);
__ArrayInstPtr(eventArr)->a_element[6] = __mkSmallInteger(cre->height);
RETURN (true);
case DestroyNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(destroyedView:);
RETURN (true);
case UnmapNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(unmappedView:);
RETURN (true);
case MapNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(mappedView:);
RETURN (true);
case ConfigureNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(configure:x:y:width:height:above:);
__ArrayInstPtr(eventArr)->a_element[3] = __mkSmallInteger(ce->x);
__ArrayInstPtr(eventArr)->a_element[4] = __mkSmallInteger(ce->y);
__ArrayInstPtr(eventArr)->a_element[5] = __mkSmallInteger(ce->width);
__ArrayInstPtr(eventArr)->a_element[6] = __mkSmallInteger(ce->height);
__ArrayInstPtr(eventArr)->a_element[7] = nil;
if (ce->above != None) {
__ArrayInstPtr(eventArr)->a_element[7] = t = __MKEXTERNALADDRESS(ce->above); __STORE(eventArr, t);
}
RETURN (true);
case GravityNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(gravityNotify:x:y:);
__ArrayInstPtr(eventArr)->a_element[3] = __mkSmallInteger(gre->x);
__ArrayInstPtr(eventArr)->a_element[4] = __mkSmallInteger(gre->y);
RETURN (true);
break;
case ResizeRequest:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(resizeRequest:width:height:);
__ArrayInstPtr(eventArr)->a_element[3] = __mkSmallInteger(rr->width);
__ArrayInstPtr(eventArr)->a_element[4] = __mkSmallInteger(rr->height);
RETURN (true);
break;
case ConfigureRequest:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(configureRequest:x:y:width:height:above:detail:);
__ArrayInstPtr(eventArr)->a_element[3] = __mkSmallInteger(cr->x);
__ArrayInstPtr(eventArr)->a_element[4] = __mkSmallInteger(cr->y);
__ArrayInstPtr(eventArr)->a_element[5] = __mkSmallInteger(cr->width);
__ArrayInstPtr(eventArr)->a_element[6] = __mkSmallInteger(cr->height);
__ArrayInstPtr(eventArr)->a_element[7] = nil;
if (cr->above != None) {
__ArrayInstPtr(eventArr)->a_element[7] = t = __MKEXTERNALADDRESS(cr->above); __STORE(eventArr, t);
}
switch (cr->detail) {
case Above:
__ArrayInstPtr(eventArr)->a_element[8] = @symbol(above);
break;
case Below:
__ArrayInstPtr(eventArr)->a_element[8] = @symbol(below);
break;
case TopIf:
__ArrayInstPtr(eventArr)->a_element[8] = @symbol(topIf);
break;
case BottomIf:
__ArrayInstPtr(eventArr)->a_element[8] = @symbol(bottomIf);
break;
case Opposite:
__ArrayInstPtr(eventArr)->a_element[8] = @symbol(opposite);
break;
default:
__ArrayInstPtr(eventArr)->a_element[8] = __MKSMALLINT(cr->detail);
break;
}
RETURN (true);
break;
case CirculateNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(circulateNotify:place:);
goto circulate;
case CirculateRequest:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(circulateRequest:place:);
/* fall into */
circulate:
switch (cie->place) {
case PlaceOnTop:
__ArrayInstPtr(eventArr)->a_element[3] = @symbol(placeOnTop);
break;
case PlaceOnBottom:
__ArrayInstPtr(eventArr)->a_element[3] = @symbol(placeOnBottom);
break;
default:
__ArrayInstPtr(eventArr)->a_element[3] = __MKSMALLINT(cie->place);
break;
}
RETURN (true);
break;
case PropertyNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(propertyChange:atom:state:time:);
__ArrayInstPtr(eventArr)->a_element[3] = t = __MKATOMOBJ(pe->atom); __STORE(eventArr, t);
switch (pe->state) {
case PropertyNewValue:
__ArrayInstPtr(eventArr)->a_element[4] = @symbol(newValue);
break;
case PropertyDelete:
__ArrayInstPtr(eventArr)->a_element[4] = @symbol(deleted);
break;
default:
__ArrayInstPtr(eventArr)->a_element[4] = __MKSMALLINT(pe->state);
break;
}
__ArrayInstPtr(eventArr)->a_element[5] = t = __MKUINT(pe->time); __STORE(eventArr, t);
RETURN (true);
break;
case SelectionClear:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(selectionClear:atom:time:);
__ArrayInstPtr(eventArr)->a_element[3] = t = __MKATOMOBJ(sce->selection); __STORE(eventArr, t);
__ArrayInstPtr(eventArr)->a_element[4] = t = __MKUINT(sce->time); __STORE(eventArr, t);
RETURN (true);
break;
case SelectionRequest:
/*
* someone wants the selection
*/
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(selectionRequest:requestor:selection:target:property:time:);
__ArrayInstPtr(eventArr)->a_element[3] = t = __MKEXTERNALADDRESS(ev->xselectionrequest.requestor); __STORE(eventArr, t);
__ArrayInstPtr(eventArr)->a_element[4] = t = __MKATOMOBJ(ev->xselectionrequest.selection); __STORE(eventArr, t);
__ArrayInstPtr(eventArr)->a_element[5] = t = __MKATOMOBJ(ev->xselectionrequest.target); __STORE(eventArr, t);
__ArrayInstPtr(eventArr)->a_element[6] = t = __MKATOMOBJ(ev->xselectionrequest.property); __STORE(eventArr, t);
__ArrayInstPtr(eventArr)->a_element[7] = t = __MKUINT(ev->xselectionrequest.time); __STORE(eventArr, t);
RETURN (true);
case SelectionNotify:
/*
* returned selection value (answer from SelectionRequest)
*/
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(selectionNotify:selection:target:property:requestor:time:);
__ArrayInstPtr(eventArr)->a_element[3] = t = __MKATOMOBJ(ev->xselection.selection); __STORE(eventArr, t);
__ArrayInstPtr(eventArr)->a_element[4] = t = __MKATOMOBJ(ev->xselection.target); __STORE(eventArr, t);
__ArrayInstPtr(eventArr)->a_element[5] = t = __MKATOMOBJ(ev->xselection.property); __STORE(eventArr, t);
__ArrayInstPtr(eventArr)->a_element[6] = t = __MKEXTERNALADDRESS(ev->xselection.requestor); __STORE(eventArr, t);
__ArrayInstPtr(eventArr)->a_element[7] = t = __MKUINT(ev->xselection.time); __STORE(eventArr, t);
RETURN (true);
case ColormapNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(colormapNotify:state:);
__ArrayInstPtr(eventArr)->a_element[3] = cme->state == ColormapInstalled ? true : false;
RETURN (true);
break;
case ClientMessage:
if (ev->xclient.message_type == (int) __AtomVal(__INST(protocolsAtom))) {
if ((ev->xclient.data.l[0] == (int) __AtomVal(__INST(quitAppAtom)))
|| (ev->xclient.data.l[0] == (int) __AtomVal(__INST(deleteWindowAtom)))) {
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(terminateView:);
RETURN (true);
}
if (ev->xclient.data.l[0] == (int) __AtomVal(__INST(saveYourselfAtom))) {
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(saveAndTerminateView:);
RETURN (true);
}
}
/*
* any other client message
*/
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(clientMessage:type:format:data:);
__ArrayInstPtr(eventArr)->a_element[3] = __MKATOMOBJ(ev->xclient.message_type);
__ArrayInstPtr(eventArr)->a_element[4] = __MKSMALLINT(ev->xclient.format);
__ArrayInstPtr(eventArr)->a_element[5] = t = __MKBYTEARRAY(ev->xclient.data, sizeof(ev->xclient.data)); __STORE(eventArr, t);
RETURN (true);
break;
case MappingNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(mappingNotify:request:event:);
switch(mape->request) {
case MappingModifier:
arg = @symbol(mappingModifier);
break;
case MappingKeyboard:
arg = @symbol(mappingKeyboard);
break;
case MappingPointer:
arg = @symbol(mappingPointer);
break;
default:
arg = __MKSMALLINT(mape->request);
break;
}
__ArrayInstPtr(eventArr)->a_element[3] = arg;
__ArrayInstPtr(eventArr)->a_element[4] = t = __MKBYTEARRAY(ev, sizeof(*mape));
__STORE(eventArr, t);
RETURN (true);
case KeymapNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(keymapNotify:);
RETURN (true);
break;
case MapRequest:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(mapRequest:);
RETURN (true);
case ReparentNotify:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(reparentedView:);
break;
default:
__ArrayInstPtr(eventArr)->a_element[2] = @symbol(unknownX11Event);
break;
}
#undef ae
#undef ee
#undef ke
#undef be
#undef ce
#undef cr
#undef cre
#undef cle
#undef gre
#undef me
#undef ewe
#undef ele
#undef lwe
#undef de
#undef mape
#undef ve
#undef fe
#undef rr
#undef pe
#undef sce
#undef cme
%}.
^ true
!
defaultEventMask
"return a mask to enable some events by default."
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT( ExposureMask | StructureNotifyMask |
KeyPressMask | KeyReleaseMask |
PointerMotionMask |
EnterWindowMask | LeaveWindowMask |
ButtonPressMask | ButtonMotionMask | ButtonReleaseMask ));
%}
!
dispatchEventFor:aViewIdOrNil withMask:eventMask
"central event handling method:
get next event and send appropriate message to the sensor or view.
If the argument aViewIdOrNil is nil, events for any view are processed,
otherwise only events for the view with given id are processed.
If the argument aMask is nonNil, only events for this eventMask are
handled.
WARNING: this may block to wait for an event - you better check for a
pending event before calling this."
(self getEventFor:aViewIdOrNil withMask:eventMask) ifTrue:[
AbortSignal handle:[:ex |
ex return
] do:[
self newDispatchLastEvent.
]
].
"Modified: 19.8.1997 / 17:10:42 / cg"
!
dispatchExposeEventFor:aViewIdOrNil
"get next expose event and send appropriate message to the sensor or view.
If the argument aViewIdOrNil is nil, events for any view are processed,
otherwise only events for the view with given id are processed.
WARNING: this may block to wait for an event - you better check for a
pending event before calling this."
self dispatchEventFor:aViewIdOrNil withMask:(self eventMaskFor:#expose)
"Modified: 19.8.1997 / 17:10:26 / cg"
!
dispatchLastEvent:evArray
|viewId view evType arguments|
evArray size < 3 ifTrue:[
'********** bad event:' errorPrintCR.
evArray errorPrintCR.
'********** see newDispatchLastEvent' errorPrintCR.
^ self.
].
viewId := evArray at:1.
viewId notNil ifTrue:[
viewId = lastId ifTrue:[
view := lastView
] ifFalse:[
view := self viewFromId:viewId
].
].
evType := evArray at:3.
(self respondsTo:evType) ifTrue:[
arguments := evArray copyFrom:3 to:(3 + evType numArgs - 1).
arguments at:1 put:view.
self perform:evType withArguments:arguments.
^ true.
].
'********** unhandled event:' errorPrintCR.
evType errorPrintCR. (evArray at:2) errorPrintCR.
'********** see newDispatchLastEvent' errorPrintCR.
^ false
!
dispatchPendingEvents
"central event handling method for modal operation.
(i.e. this is now only used in the modal debugger)
Dispatch any pending events; return when no more are pending.
This code is somewhat special, since X has a concept of graphic
expose events (which are sent after a bitblt). After such a bitblt,
we only handle exposes until the graphicsExpose arrives.
Other systems may not need such a kludge"
"interested in exposes only ?"
dispatchingExpose notNil ifTrue:[
[self exposeEventPendingFor:dispatchingExpose withSync:false] whileTrue:[
self dispatchExposeEventFor:dispatchingExpose
].
^ self
].
[self eventPendingWithSync:false] whileTrue:[
(self getEventFor:nil withMask:nil) ifTrue:[
AbortSignal handle:[:ex |
ex return
] do:[
self newDispatchLastEvent
]
].
]
"Modified: 19.8.1997 / 17:11:18 / cg"
!
disposeEventsWithMask:aMask for:aWindowIdOrNil
"dispose (throw away) specific events. If aWindowId is nil,
events matching the mask are thrown away regardless of which
view they are for. Otherwise, only matching events for that
view are flushed."
<context: #return>
%{
XEvent ev;
Window win;
if (ISCONNECTED
&& __isSmallInteger(aMask)) {
Display *dpy = myDpy;
ENTER_XLIB();
if (__isExternalAddress(aWindowIdOrNil)) {
win = __WindowVal(aWindowIdOrNil);
while (XCheckWindowEvent(dpy, win, __intVal(aMask), &ev)) ;;
} else {
while (XCheckMaskEvent(dpy, __intVal(aMask), &ev)) ;;
}
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
eventMaskFor:anEventSymbol
"return the eventMask bit-constant corresponding to an event symbol"
%{ /* NOCONTEXT */
int m = 0;
if (anEventSymbol == @symbol(keyPress)) m = KeyPressMask;
else if (anEventSymbol == @symbol(keyRelease)) m = KeyReleaseMask;
else if (anEventSymbol == @symbol(buttonPress)) m = ButtonPressMask;
else if (anEventSymbol == @symbol(buttonRelease)) m = ButtonReleaseMask;
else if (anEventSymbol == @symbol(buttonMotion)) m = ButtonMotionMask;
else if (anEventSymbol == @symbol(pointerMotion)) m = PointerMotionMask;
else if (anEventSymbol == @symbol(expose)) m = ExposureMask;
else if (anEventSymbol == @symbol(focusChange)) m = FocusChangeMask;
else if (anEventSymbol == @symbol(enter)) m = EnterWindowMask;
else if (anEventSymbol == @symbol(leave)) m = LeaveWindowMask;
else if (anEventSymbol == @symbol(keymapState)) m = KeymapStateMask;
else if (anEventSymbol == @symbol(visibilityChange)) m = VisibilityChangeMask;
else if (anEventSymbol == @symbol(structureNotify)) m = StructureNotifyMask;
else if (anEventSymbol == @symbol(resizeRedirect)) m = ResizeRedirectMask;
else if (anEventSymbol == @symbol(propertyChange)) m = PropertyChangeMask;
else if (anEventSymbol == @symbol(colormapChange)) m = ColormapChangeMask;
RETURN (__MKSMALLINT(m));
%}
!
eventPending
"return true, if any event is pending.
This looks for both the internal queue and the display connection."
"/ ConservativeSync is required for some Xlib implementation,
"/ where eventPending returns wrong if we do not flush the buffer.
"/ (especially Win32 & Xlib)
ConservativeSync == true ifTrue:[self sync].
dispatchingExpose notNil ifTrue:[
^ self exposeEventPendingFor:dispatchingExpose withSync:false
].
^ self eventPendingWithSync:false
"Modified: / 28.4.1999 / 11:08:12 / cg"
!
eventPending:anEventSymbol for:aWindowIdOrNil
"return true, if a specific event is pending"
^ self eventsPending:(self eventMaskFor:anEventSymbol) for:aWindowIdOrNil withSync:false
!
eventPending:anEventMask for:aWindowIdOrNil withSync:doSync
"return true, if any of the masked events is pending"
<context: #return>
%{ /* UNLIMITEDSTACK */
XEvent ev;
Window win;
int thereIsOne;
OBJ rslt = false;
if (ISCONNECTED && __isSmallInteger(anEventMask)) {
Display *dpy = myDpy;
ENTER_XLIB();
if (doSync == true) {
XSync(dpy, 0); /* make certain everything is flushed */
}
if (__isExternalAddress(aWindowIdOrNil)) {
win = __WindowVal(aWindowIdOrNil);
thereIsOne = XCheckWindowEvent(dpy, win, __intVal(anEventMask), &ev);
} else {
thereIsOne = XCheckMaskEvent(dpy, __intVal(anEventMask), &ev);
}
if (thereIsOne) {
XPutBackEvent(dpy, &ev);
rslt = true;
}
LEAVE_XLIB();
}
RETURN ( rslt );
%}
!
eventPendingWithSync:doSync
"return true, if any event is pending.
If doSync is true, do a sync output buffer (i.e. send all to the display and wait until its processed)
before checking."
<context: #return>
%{ /* UNLIMITEDSTACK */
OBJ rslt = false;
if (ISCONNECTED) {
Display *dpy = myDpy;
if (XEventsQueued(dpy, QueuedAlready)) {
RETURN (true);
}
ENTER_XLIB();
if (doSync == true) {
XSync(dpy, 0); /* make certain everything is flushed */
}
if (XPending(dpy)) {
rslt = true;
}
LEAVE_XLIB();
}
RETURN ( rslt );
%}
!
eventQueued
"return true, if any event is queued"
dispatchingExpose notNil ifTrue:[
^ self exposeEventPendingFor:dispatchingExpose withSync:false
].
^ self eventQueuedAlready
"Created: 12.12.1995 / 21:43:00 / stefan"
!
eventQueuedAlready
"return true, if any event is queued internally.
(i.e. in X's internal event queue, which is both filled by explicit
nextEvent calls AND whenever drawing is done and events are pending on
the display connection)."
%{ /* UNLIMITEDSTACK */
OBJ rslt = false;
if (ISCONNECTED) {
/* ENTER ... LEAVE not needed; XEventsQueued will not block */
/* ENTER_XLIB(); */
if (XEventsQueued(myDpy, QueuedAlready)) {
rslt = true;
}
/* LEAVE_XLIB(); */
}
RETURN ( rslt );
%}
!
exposeEventPendingFor:aWindowIdOrNil withSync:doSync
"return true, if any expose event is pending for a specific view,
or any view (if the arg is nil).
This is an X specific, only required after a scroll operation."
<context: #return>
%{ /* UNLIMITEDSTACK */
XEvent ev;
Window win;
int thereIsOne;
OBJ rslt = false;
if (ISCONNECTED) {
Display *dpy = myDpy;
ENTER_XLIB();
if (doSync == true) {
XSync(dpy, 0); /* make certain everything is flushed */
}
if (__isExternalAddress(aWindowIdOrNil)) {
win = __WindowVal(aWindowIdOrNil);
thereIsOne = XCheckWindowEvent(dpy, win, ExposureMask, &ev);
} else {
thereIsOne = XCheckMaskEvent(dpy, ExposureMask, &ev);
}
if (thereIsOne) {
XPutBackEvent(dpy, &ev);
rslt = true;
}
LEAVE_XLIB();
}
RETURN ( rslt );
%}
!
getEventFor:aViewIdOrNil withMask:eventMask
"read next event - put into local eventBuffer.
If aViewIdOrNil is nil, events for any view are fetched;
otherwise only events for that specific view will be fetched.
Returns true, if there was an event, false otherwise.
This method may block - so you better check for pending events
before calling for it."
^ self getEventFor:aViewIdOrNil withMask:eventMask into:eventBuffer
!
getEventFor:aViewIdOrNil withMask:eventMask into:anEventBuffer
"read next event - put into anEventBuffer.
If aViewIdOrNil is nil, events for any view are fetched;
otherwise only events for that specific view will be fetched.
Returns true, if there was an event, false otherwise.
This method may block - so you better check for pending events
before calling for it.
Sorry I had to split dispatch into this fetch method and an extra
handle method to allow unlimitedstack here.
(some Xlibs do a big alloca there ...) which cannot be done in
dispatchLastEvent, since it dispatches out into ST-methods.
"
%{ /* UNLIMITEDSTACK */
Display *dpy;
Window win, wWanted;
int evMask;
XEvent *ev;
if (! ISCONNECTED) {
RETURN (false);
}
dpy = myDpy;
if (__isByteArray(anEventBuffer)) {
ev = (XEvent *)(__ByteArrayInstPtr(anEventBuffer)->ba_element);
} else {
printf("DISPLAY: bad eventBuffer\n");
RETURN (false);
}
ev->type = 0;
if (__isSmallInteger(eventMask)) {
evMask = __intVal(eventMask);
} else {
evMask = ~0;
}
if (__isExternalAddress(aViewIdOrNil)) {
wWanted = __WindowVal(aViewIdOrNil);
if (XCheckWindowEvent(dpy, wWanted, evMask, ev)) {
RETURN ( true );
}
} else {
if (evMask == ~0) {
XNextEvent(dpy, ev);
RETURN (true);
}
if (XCheckMaskEvent(dpy, evMask, ev)) {
RETURN (true);
}
}
RETURN (false);
%}.
^ self primitiveFailed
!
handleAllEvents
"from now on, handle any kind of event"
dispatchingExpose := nil
!
handleExposeOnlyFor:aView
"from now on, handle expose events only"
dispatchingExpose := aView id
!
newDispatchLastEvent
|arr|
arr := Array new:13.
(self decomposeEventBuffer:eventBuffer into:arr) ifTrue:[
(self dispatchLastEvent:arr) ifFalse:[
"if not implemented in new dispatch, fall back to old dispatch"
self dispatchLastEvent
].
].
!
setEventMask:aMask in:aWindowId
"tell X that we are only interested in events from aMask, which
is the bitwise or of the eventMask bits (see 'eventMaskFor:')"
<context: #return>
%{
int mask;
if (ISCONNECTED
&& __isExternalAddress(aWindowId)
&& __isSmallInteger(aMask)) {
mask = __intVal(aMask);
#ifdef OLD
/* these may not be disabled */
mask |= ExposureMask | StructureNotifyMask |
KeyPressMask | KeyReleaseMask |
EnterWindowMask | LeaveWindowMask |
ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
#endif
ENTER_XLIB();
XSelectInput(myDpy, __WindowVal(aWindowId), mask);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
startDispatch
"redefined to clear dispatchingExpose, which is a special X feature"
dispatching ifTrue:[^ self].
dispatchingExpose := nil.
super startDispatch
! !
!XWorkstation methodsFor:'event handling - old dispatch'!
buttonPress:button x:x y:y view:aView
"forward a button-press event for some view"
aView isNil ifTrue:[
"/ event arrived, after I destroyed it myself
^ self
].
button == 1 ifTrue:[
activateOnClick == true ifTrue:[
"/ dont raise above an active popup view.
(activeKeyboardGrab isNil and:[activePointerGrab isNil]) ifTrue:[
aView topView raise.
"/ ] ifFalse:[
"/ activeKeyboardGrab printCR.
"/ activePointerGrab printCR.
]
].
].
super buttonPress:button x:x y:y view:aView
!
circulateNotifyView:aView
"sent, when the stacking order changes.
ignored for now."
!
circulateRequestView:aView
"sent, when the stacking order is about to change.
ignored for now."
!
clientMessage:event type:type format:format dataOffset:offs view:targetView
|sensor data|
data := event copyFrom:offs + 1.
"/ DND drag&drop protocol
type == (self atomIDOf:#DndProtocol) ifTrue:[
format == 32 ifTrue:[
self dndMessage:event data:data view:targetView.
^ self
]
].
(sensor := targetView sensor) notNil ifTrue:[
sensor clientMessage:type format:format eventData:data view:targetView
] ifFalse:[
"
not posted, if there is no sensor ...
"
]
"Created: 4.4.1997 / 17:49:26 / cg"
"Modified: 4.4.1997 / 18:00:18 / cg"
!
colorMapChangeView:aView
"sent, when another colormap is installed.
This is a very X-specific mechanism."
aView isNil ifTrue:[
"/ event arrived, after I destroyed it myself
^ self
].
"/ not yet implemented
"/ aView colorMapChange
!
configureRequestView:aView
"ignored for now"
"/ aView configureRequest
!
createdView:aView
"ignored for now"
"/ aView created
!
dispatchLastEvent
|theView symS arg butt sibling
windowID siblingID propertyID selectionID targetID requestorID
evTime
eventType|
%{ /* STACK: 8000 */
# define ANYBUTTON (Button1MotionMask | Button2MotionMask | Button3MotionMask)
Display *dpy;
OBJ eB;
XEvent *ev;
int ev_x, ev_y;
# define ae ((XAnyEvent *)ev)
# define ee ((XExposeEvent *)ev)
# define ke ((XKeyPressedEvent *)ev)
# define be ((XButtonPressedEvent *)ev)
# define ce ((XConfigureEvent *)ev)
# define me ((XMotionEvent *)ev)
# define ewe ((XEnterWindowEvent *)ev)
# define lwe ((XLeaveWindowEvent *)ev)
# define de ((XDestroyWindowEvent *)ev)
# define ve ((XVisibilityEvent *)ev)
# define mape ((XMappingEvent *)ev)
KeySym keySym;
unsigned char buffer[10];
int i, nchars;
char *keySymString;
char keySymStringBuffer[32];
unsigned INT nextMultiClickTime;
OBJ upDown, t;
struct inlineCache *ipS;
static struct inlineCache vid = _ILC1;
static struct inlineCache expS = _ILC5;
static struct inlineCache gexpS = _ILC6;
static struct inlineCache nexpS = _ILC1;
static struct inlineCache motS = _ILC4;
static struct inlineCache bpS = _ILC4;
static struct inlineCache bmpS = _ILC4;
static struct inlineCache bspS = _ILC4;
static struct inlineCache brS = _ILC4;
static struct inlineCache focInS = _ILC1;
static struct inlineCache focOutS = _ILC1;
static struct inlineCache peS = _ILC4;
static struct inlineCache plS = _ILC2;
static struct inlineCache termS = _ILC1;
static struct inlineCache savtermS = _ILC1;
static struct inlineCache destrS = _ILC1;
static struct inlineCache unmapS = _ILC1;
static struct inlineCache mapS = _ILC1;
static struct inlineCache confS = _ILC5;
static struct inlineCache coveredS = _ILC2;
static struct inlineCache clientMsg = _ILC5;
static struct inlineCache keymap = _ILC0;
static struct inlineCache created = _ILC1;
static struct inlineCache mapReq = _ILC1;
static struct inlineCache repar = _ILC1;
static struct inlineCache confReq = _ILC1;
static struct inlineCache resReq = _ILC1;
static struct inlineCache circReq = _ILC1;
static struct inlineCache circNotify = _ILC1;
static struct inlineCache gravNotify = _ILC1;
static struct inlineCache prop = _ILC1;
static struct inlineCache selClear = _ILC2;
static struct inlineCache selReq = _ILC6;
static struct inlineCache selNotify = _ILC5;
static struct inlineCache colormap = _ILC1;
static struct inlineCache mapping = _ILC2;
static struct inlineCache vis = _ILC1;
static struct inlineCache skpS = _ILC4;
static struct inlineCache skrS = _ILC4;
if (! ISCONNECTED) {
RETURN (false);
}
dpy = myDpy;
eB = __INST(eventBuffer);
if (__isByteArray(eB)) {
ev = (XEvent *)(__ByteArrayInstPtr(eB)->ba_element);
} else {
printf("DISPLAY: no eventBuffer\n");
RETURN (false);
}
/*
* very often, its another event for the same view ...
* avoid creation & lookup then.
*/
if ((t = __INST(lastId)) != nil) {
if (__isExternalAddress(t)) {
if (__WindowVal(t) == ae->window) {
theView = __INST(lastView);
if (__isNonNilObject(theView)) {
if (__qClass(theView) == nil) {
theView = nil;
}
}
}
}
}
if (theView == nil) {
windowID = __MKEXTERNALADDRESS(ae->window);
theView = (*vid.ilc_func)(self, @symbol(viewFromId:), nil, &vid, windowID);
/*
* MKEXTERNALADDRESS and/or #viewFromId: could lead to a GC - refetch event ptr
*/
eB = __INST(eventBuffer);
ev = (XEvent *)(__ByteArrayInstPtr(eB)->ba_element);
}
if ((theView == nil) && (ev->type != MappingNotify)) {
RETURN (nil);
}
/*
* key, button and pointer events are sent to the sensor,
* or (if there is none) to the delegate.
* or (if there is none) to the view.
*
* expose events are sent to the sensor,
* or (if there is none) to the view
*
* sensor and delegate get view as additional argument
* all of this has been taken out of here to corresponding methods
* in DeviceWorkstation.
*/
#ifdef DEBUG
eventType = __MKSMALLINT(ev->type);
#endif
switch (ev->type) {
case KeyRelease:
symS = @symbol(keyRelease:x:y:view:);
ipS = &skrS;
upDown = false;
goto keyPressAndRelease;
case KeyPress:
symS = @symbol(keyPress:x:y:view:);
ipS = &skpS;
upDown = true;
/* FALL INTO */
keyPressAndRelease:
__INST(eventRootX) = __MKSMALLINT(ke->x_root);
__INST(eventRootY) = __MKSMALLINT(ke->y_root);
#ifdef OLD
__INST(altDown) = (ke->state & Mod2Mask) ? true : false;
__INST(metaDown) = (ke->state & Mod1Mask) ? true : false;
#else
__INST(altDown) = (ke->state & __intVal(__INST(altModifierMask))) ? true : false;
__INST(metaDown) = (ke->state & __intVal(__INST(metaModifierMask))) ? true : false;
#endif
__INST(shiftDown) = (ke->state & ShiftMask) ? true : false;
__INST(ctrlDown) = (ke->state & ControlMask) ? true : false;
ev_x = ke->x;
ev_y = ke->y;
arg = nil;
nchars = XLookupString(ke, (char *)buffer, sizeof(buffer), &keySym, NULL);
if (nchars
&& (((buffer[0] >= ' ') && (buffer[0] <= '~'))
|| (buffer[0] >= 0x80))) {
arg = _MKCHARACTER(buffer[0])/* *_CharacterTable[buffer[0]] */;
keySymString = NULL;
} else {
#ifdef OLD
switch (keySym) {
case XK_Control_L:
case XK_Control_R:
__INST(ctrlDown) = upDown;
break;
case XK_Shift_L:
case XK_Shift_R:
__INST(shiftDown) = upDown;
break;
case XK_Meta_L:
case XK_Meta_R:
__INST(metaDown) = upDown;
break;
case XK_Alt_L:
case XK_Alt_R:
__INST(altDown) = upDown;
break;
}
#endif
keySymString = XKeysymToString(keySym);
if (keySymString) {
#ifdef OLD
if (keySymString[0] == 'D') {
/*
* remove underscore, dont want it in symbols
*/
if (strcmp(keySymString, "Delete_line") == 0) {
keySymString = "DeleteLine";
} else if (strcmp(keySymString, "Delete_word") == 0) {
keySymString = "DeleteWord";
}
}
/*
* make names compatible
*/
if (strcmp(keySymString, "Down") == 0) {
keySymString = "CursorDown";
} else if (strcmp(keySymString, "Up") == 0) {
keySymString = "CursorUp";
} else if (strcmp(keySymString, "Left") == 0) {
keySymString = "CursorLeft";
} else if (strcmp(keySymString, "Right") == 0) {
keySymString = "CursorRight";
}
arg = __MKSYMBOL(keySymString, (OBJ *)0);
#else
arg = __MKSTRING(keySymString);
#endif
}
}
if (arg == nil) {
/* happens sometimes (alt-graph on sun has no keysym) */
break;
}
(*(*ipS).ilc_func)(self, symS, nil, ipS,
arg,
__MKSMALLINT(ev_x),
__MKSMALLINT(ev_y),
theView);
break;
case ButtonPress:
__INST(buttonsPressed) = __MKSMALLINT(__intVal(__INST(buttonsPressed)) | (1 << be->button));
__INST(eventRootX) = __MKSMALLINT(be->x_root);
__INST(eventRootY) = __MKSMALLINT(be->y_root);
if (__isSmallInteger(__INST(multiClickTimeDelta)))
nextMultiClickTime = be->time + __intVal(__INST(multiClickTimeDelta));
else
nextMultiClickTime = 0;
if ((t = __INST(multiClickTime)) != nil) {
INT _multiClickTime;
_multiClickTime = __longIntVal(t);
if (be->time < _multiClickTime) {
__INST(multiClickTime) = t = __MKUINT(nextMultiClickTime); __STORE(self, t);
/*
* MKUINT could lead to a GC - refetch event ptr
*/
eB = __INST(eventBuffer);
ev = (XEvent *)(__ByteArrayInstPtr(eB)->ba_element);
ipS = &bmpS;
symS = @symbol(buttonMultiPress:x:y:view:);
goto sendButtonEvent;
break;
}
}
__INST(multiClickTime) = t = __MKUINT(nextMultiClickTime); __STORE(self, t);
/*
* MKUINT could lead to a GC - refetch event ptr
*/
eB = __INST(eventBuffer);
ev = (XEvent *)(__ByteArrayInstPtr(eB)->ba_element);
#ifdef NO_LONGER
if (be->state & ShiftMask) {
ipS = &bspS;
symS = @symbol(buttonShiftPress:x:y:view:);
goto sendButtonEvent;
}
#endif
ipS = &bpS;
symS = @symbol(buttonPress:x:y:view:);
goto sendButtonEvent;
/* NOT REACHED */
case ButtonRelease:
__INST(buttonsPressed) = __MKSMALLINT(__intVal(__INST(buttonsPressed)) & ~(1 << be->button));
__INST(eventRootX) = __MKSMALLINT(be->x_root);
__INST(eventRootY) = __MKSMALLINT(be->y_root);
ipS = &brS;
symS = @symbol(buttonRelease:x:y:view:);
/* fall into */
sendButtonEvent:
butt = __MKSMALLINT(be->button);
#ifdef NOTDEF
/*
* this allows operation with single button mouses: meta-click is always Button 2
*/
if (__INST(metaDown) == true)
butt = __MKSMALLINT(2);
else
#endif
butt = __AT_(__INST(buttonTranslation), butt);
/*
* #at: could lead to a GC - refetch event ptr
*/
eB = __INST(eventBuffer);
ev = (XEvent *)(__ByteArrayInstPtr(eB)->ba_element);
(*(*ipS).ilc_func)(self,
symS, nil, ipS,
butt,
__MKSMALLINT(ke->x),
__MKSMALLINT(ke->y),
theView);
break;
case MotionNotify:
if (__INST(motionEventCompression) != false) {
while (XCheckWindowEvent(dpy, me->window, ANYBUTTON, ev)) ;;
}
__INST(eventRootX) = __MKSMALLINT(me->x_root);
__INST(eventRootY) = __MKSMALLINT(me->y_root);
#ifdef OLD
__INST(altDown) = (me->state & Mod2Mask) ? true : false;
__INST(metaDown) = (me->state & Mod1Mask) ? true : false;
#else
__INST(altDown) = (ke->state & __intVal(__INST(altModifierMask))) ? true : false;
__INST(metaDown) = (ke->state & __intVal(__INST(metaModifierMask))) ? true : false;
#endif
__INST(shiftDown) = (me->state & ShiftMask) ? true : false;
__INST(ctrlDown) = (me->state & ControlMask) ? true : false;
(*motS.ilc_func)(self,
@symbol(buttonMotion:x:y:view:), nil, &motS,
__MKSMALLINT(me->state),
__MKSMALLINT(me->x),
__MKSMALLINT(me->y),
theView);
break;
case FocusIn:
(*focInS.ilc_func)(self,
@symbol(focusInView:), nil, &focInS,
theView);
break;
case FocusOut:
(*focOutS.ilc_func)(self,
@symbol(focusOutView:), nil, &focOutS,
theView);
break;
case EnterNotify:
#ifdef OLD
__INST(altDown) = (ewe->state & Mod2Mask) ? true : false;
__INST(metaDown) = (ewe->state & Mod1Mask) ? true : false;
#else
__INST(altDown) = (ke->state & __intVal(__INST(altModifierMask))) ? true : false;
__INST(metaDown) = (ke->state & __intVal(__INST(metaModifierMask))) ? true : false;
#endif
__INST(shiftDown) = (ewe->state & ShiftMask) ? true : false;
__INST(ctrlDown) = (ewe->state & ControlMask) ? true : false;
(*peS.ilc_func)(self,
@symbol(pointerEnter:x:y:view:), nil, &peS,
__MKSMALLINT(ewe->state),
__MKSMALLINT(ewe->x),
__MKSMALLINT(ewe->y),
theView);
break;
case LeaveNotify:
(*plS.ilc_func)(self,
@symbol(pointerLeave:view:), nil, &plS,
__MKSMALLINT(lwe->state),
theView);
break;
case GraphicsExpose:
(*gexpS.ilc_func)(self,
@symbol(graphicsExposeX:y:width:height:final:view:), nil, &gexpS,
__MKSMALLINT(ee->x),
__MKSMALLINT(ee->y),
__MKSMALLINT(ee->width),
__MKSMALLINT(ee->height),
ee->count == 0 ? true : false,
theView);
if (ee->count != 0) {
break;
}
/* fall into */
case NoExpose:
(*nexpS.ilc_func)(self,
@symbol(noExposeView:), nil, &nexpS,
theView);
break;
case Expose:
(*expS.ilc_func)(self,
@symbol(exposeX:y:width:height:view:), nil, &expS,
__MKSMALLINT(ee->x),
__MKSMALLINT(ee->y),
__MKSMALLINT(ee->width),
__MKSMALLINT(ee->height),
theView);
break;
case ConfigureNotify:
if (ce->above != None) {
siblingID = __MKEXTERNALADDRESS(ce->above);
sibling = (*vid.ilc_func)(self, @symbol(viewFromId:), nil, &vid, siblingID);
/*
* MKEXTERNALADDRESS or #viewFromId: could lead to a GC - refetch event ptr
*/
eB = __INST(eventBuffer);
ev = (XEvent *)(__ByteArrayInstPtr(eB)->ba_element);
}
(*confS.ilc_func)(self,
@symbol(configureX:y:width:height:view:), nil, &confS,
__MKSMALLINT(ce->x),
__MKSMALLINT(ce->y),
__MKSMALLINT(ce->width),
__MKSMALLINT(ce->height),
theView);
if (sibling != nil) {
(*coveredS.ilc_func)(self,
@symbol(coveredBy:view:), nil, &coveredS,
theView,
sibling);
}
break;
case ClientMessage:
if (ev->xclient.message_type == (int) __AtomVal(__INST(protocolsAtom))) {
if ((ev->xclient.data.l[0] == (int) __AtomVal(__INST(quitAppAtom)))
|| (ev->xclient.data.l[0] == (int) __AtomVal(__INST(deleteWindowAtom)))) {
(*termS.ilc_func)(self,
@symbol(terminateView:), nil, &termS, theView);
break;
}
if (ev->xclient.data.l[0] == (int) __AtomVal(__INST(saveYourselfAtom))) {
(*savtermS.ilc_func)(self,
@symbol(saveAndTerminateView:)
, nil, &savtermS, theView);
break;
}
}
/*
* any other client message
*/
i = (char *)(&(ev->xclient.data)) - (char *)ev;
(*clientMsg.ilc_func)(self,
@symbol(clientMessage:type:format:dataOffset:view:)
, nil, &clientMsg
, __INST(eventBuffer)
,__MKSMALLINT(ev->xclient.message_type)
,__MKSMALLINT(ev->xclient.format)
,__MKSMALLINT(i),
theView);
break;
case DestroyNotify:
(*destrS.ilc_func)(self, @symbol(destroyedView:)
, nil, &destrS, theView);
break;
case UnmapNotify:
(*unmapS.ilc_func)(self, @symbol(unmappedView:)
, nil, &unmapS, theView);
break;
case MapNotify:
(*mapS.ilc_func)(self,
@symbol(mappedView:)
, nil, &mapS, theView);
break;
case KeymapNotify:
(*keymap.ilc_func)(theView,
@symbol(keyMapChange)
, nil, &keymap);
break;
case VisibilityNotify:
switch (ve->state) {
case VisibilityUnobscured:
arg = @symbol(unobscured);
break;
case VisibilityPartiallyObscured:
arg = @symbol(partiallyObscured);
break;
case VisibilityFullyObscured:
arg = @symbol(fullyObscured);
break;
}
(*vis.ilc_func)(theView, @symbol(visibilityChange:), nil, &vis, arg);
break;
case CreateNotify:
(*created.ilc_func)(self, @symbol(createdView:), nil, &created, theView);
break;
case MapRequest:
(*mapReq.ilc_func)(self, @symbol(mapRequestView:), nil, &mapReq, theView);
break;
case ReparentNotify:
(*repar.ilc_func)(self, @symbol(reparentedView:), nil, &repar, theView);
break;
case ConfigureRequest:
(*confReq.ilc_func)(self, @symbol(configureRequestView:), nil, &confReq, theView);
break;
case GravityNotify:
(*gravNotify.ilc_func)(self, @symbol(gravityNotifyView:), nil, &resReq, theView);
break;
case ResizeRequest:
(*resReq.ilc_func)(self, @symbol(resizeRequestView:), nil, &resReq, theView);
break;
case CirculateNotify:
(*circNotify.ilc_func)(self, @symbol(circulateNotifyView:), nil, &circNotify, theView);
break;
case CirculateRequest:
(*circReq.ilc_func)(self, @symbol(circulateRequestView:), nil, &circReq, theView);
break;
case PropertyNotify:
(*prop.ilc_func)(self,
@symbol(propertyChangeView:)
, nil, &prop,
theView);
break;
case SelectionClear:
selectionID = __MKATOMOBJ(ev->xselectionclear.selection);
(*selClear.ilc_func)(self,
@symbol(selectionClear:view:)
, nil, &selClear,
selectionID,
theView);
break;
case SelectionNotify:
/*
* returned selection value (answer from SelectionRequest)
*/
DPRINTF(("SelectionNotify prop=%x target=%x selection= %x requestor=%x\n",
ev->xselection.property, ev->xselection.target,
ev->xselection.selection, ev->xselection.requestor));
{
INT _property = ev->xselection.property;
INT _target = ev->xselection.target;
INT _selection = ev->xselection.selection;
INT _requestor = ev->xselection.requestor;
propertyID = __MKATOMOBJ(_property);
targetID = __MKATOMOBJ(_target);
selectionID = __MKATOMOBJ(_selection);
requestorID = __MKEXTERNALADDRESS(_requestor);
}
/*
* MKATOMOBJ/MKEXTERNALADDRESS could lead to a GC - refetch event ptr
*/
eB = __INST(eventBuffer);
ev = (XEvent *)(__ByteArrayInstPtr(eB)->ba_element);
(*selNotify.ilc_func)(self,
@symbol(selectionNotify:target:selection:from:view:)
, nil, &selNotify,
propertyID, targetID, selectionID, requestorID,
theView);
break;
case SelectionRequest:
/*
* someone wants the selection
*/
DPRINTF(("SelectionRequest prop=%x target=%x selection=%x requestor=%x\n",
ev->xselectionrequest.property,
ev->xselectionrequest.target,
ev->xselectionrequest.selection,
ev->xselectionrequest.requestor));
{
INT _property = ev->xselectionrequest.property;
INT _target = ev->xselectionrequest.target;
INT _selection = ev->xselectionrequest.selection;
INT _requestor = ev->xselectionrequest.requestor;
INT _t = ev->xselectionrequest.time;
propertyID = __MKATOMOBJ(_property);
targetID = __MKATOMOBJ(_target);
selectionID = __MKATOMOBJ(_selection);
requestorID = __MKEXTERNALADDRESS(_requestor);
evTime = __MKEXTERNALADDRESS(_t);
}
/*
* MKATOMOBJ/MKEXTERNALADDR could lead to a GC - refetch event ptr
*/
eB = __INST(eventBuffer);
ev = (XEvent *)(__ByteArrayInstPtr(eB)->ba_element);
(*selReq.ilc_func)(self,
@symbol(selectionRequest:target:selection:time:from:view:)
, nil, &selReq,
propertyID, targetID, selectionID, evTime, requestorID,
theView);
break;
case ColormapNotify:
(*colormap.ilc_func)(self,
@symbol(colorMapChangeView:)
, nil, &colormap,
theView);
break;
case MappingNotify:
switch(mape->request) {
case MappingModifier:
arg = @symbol(mappingModifier);
break;
case MappingKeyboard:
arg = @symbol(mappingKeyboard);
break;
case MappingPointer:
arg = @symbol(mappingPointer);
break;
default:
arg = nil;
break;
}
(*mapping.ilc_func)(self,
@symbol(mappingChanged:event:)
, nil, &mapping, arg, eB);
break;
}
#undef ae
#undef ee
#undef ke
#undef be
#undef ce
#undef me
#undef ewe
#undef lwe
#undef de
#undef mape
%}.
^ true
!
gravityNotifyView:aView
"ignored for now"
"/ aView gravityNotify
!
mapRequestView:aView
"ignored for now"
"/ aView mapRequest
!
mappingChanged:what event:eB
"OBSOLETE with newDispatchLastEvent!!
One of Keyboard-, Modifier- or PointerMap has change, probably by xmodmap.
Tell xlib about the fact."
(what == #mappingKeyboard or:[what == #mappingModifier]) ifTrue:[
self refreshKeyboardMapping:eB.
"Maybe some of our modifiers have been changed"
self initializeModifierMappings.
].
"Created: 1.12.1995 / 16:28:23 / stefan"
!
propertyChangeView:aView
"sent when an X property changes.
This is a very X-specific mechanism."
aView isNil ifTrue:[
"/ event arrived, after I destroyed it myself
^ self
].
aView propertyChange
!
resizeRequestView:aView
"ignored for now"
"/ aView resizeRequest
!
selectionClear:selectionID view:aView
"OBSOLETE - this will vanish"
"sent when another X-client has created a selection.
This is a very X-specific mechanism."
"/
"/ workaround a bug in olvwm: it clears selections
"/ on window raise.
"/ In this case, keep my last own selection.
"/
self setLastCopyBuffer:(self getCopyBuffer).
self setCopyBuffer:nil
"/ noone is interested in that ...
"/ aView selectionClear:selectionID
!
selectionNotify:propertyID target:targetID selection:selectionID from:requestorID view:aView
"sent when the server returns an answer from a request for a selection.
This is a very X-specific mechanism."
|s sensor|
propertyID == 0 ifTrue:[
"invalid olvwm behavior"
s := self getLastCopyBuffer
] ifFalse:[
targetID == (self atomIDOf:#STRING) ifTrue:[
"
a returned string
"
s := self getTextProperty:propertyID from:requestorID.
s notNil ifTrue:[
(s endsWith:Character cr) ifTrue:[
s := s asStringCollection copyWith:''
]
]
] ifFalse:[
"
a returned object
"
s := self getObjectProperty:propertyID from:requestorID.
].
].
s notNil ifTrue:[
(sensor := aView sensor) notNil ifTrue:[
sensor pasteFromClipBoard:s view:aView
] ifFalse:[
"
if there is no sensor ...
"
aView pasteFromClipBoard:s
]
]
!
selectionRequest:propertyID target:targetID selection:selectionID time:t from:windowID view:aView
"sent by some other X-client to ask for the selection.
This is a very X-specific mechanism."
|o s stream stringAtom|
targetID == (self atomIDOf:#LENGTH) ifTrue:[
"/
"/ the other one wants to know the size of our selection ...
"/
s := self selectionAsString.
self
setLengthProperty:propertyID
value:s size
for:windowID.
self
sendSelectionNotifySelection:selectionID
property:propertyID
target:targetID
time:t
from:aView id
to:windowID.
^ self
].
stringAtom := self atomIDOf:#STRING.
(targetID == stringAtom or:[
targetID == (self atomIDOf:#'COMPOUND_TEXT')]) ifTrue:[
"/
"/ the other view wants the selection as string
"/
s := self selectionAsString.
self
sendSelection:s
selection:primaryAtom
property:propertyID
target:stringAtom "/ targetID
time:t
from:windowID
to:windowID.
^ self
].
"/ (targetID == (self atomIDOf:#'TARGETS')) ifTrue:[
"/"/ TODO: implement this to avoid netscape paste-delay.
"/"/
"/ ^ self
"/ ].
(targetID == (self atomIDOf:#'ST_OBJECT')) ifTrue:[
"/
"/ send the selection in binaryStore format
"/ (assuming, that the other view knows how to handle it)
"/
o := self getCopyBuffer.
stream := WriteStream on:(ByteArray new:200).
o storeBinaryOn:stream.
^ self
sendSelection:(stream contents)
selection:primaryAtom
property:propertyID
target:targetID
time:t
from:windowID
to:windowID
].
"Created: / 17.6.1998 / 19:33:10 / cg"
"Modified: / 17.6.1998 / 20:24:40 / cg"
! !
!XWorkstation methodsFor:'event sending'!
sendClientEvent:msgType format:msgFormat to:targetWindowID data1:d1 data2:d2 data3:d3 data4:d4 data5:d5
"send a ClientMessage to some other (possibly: non-ST/X) view.
The client message gets message_type and msgFormat as specified by
the arguments. The additional data arguments specify up to
5 longWords of user data; each may be an integer or nil.
It is passed transparently in the events data field.
See XProtocol specification for more details."
"/ Event.xclient.type = ClientMessage;
"/ Event.xclient.display = dpy;
"/ Event.xclient.message_type = msgType;
"/ Event.xclient.format = msgFormat;
"/ Event.xclient.window = targetWindowID;
"/ Event.xclient.data.l[0] = d1
"/ Event.xclient.data.l[1] = d2
"/ Event.xclient.data.l[2] = d3
"/ Event.xclient.data.l[3] = d4
"/ Event.xclient.data.l[4] = d5
"/
"/ XSendEvent(dpy,DispatchWindow,True,NoEventMask,&Event);
<context: #return>
%{
int type;
int state;
if (ISCONNECTED
&& __isInteger(msgType)
&& __isInteger(msgFormat)
&& (__isExternalAddress(targetWindowID) || __isInteger(targetWindowID))) {
Display *dpy = myDpy;
XEvent ev;
Status result;
if (__isInteger(d1)) {
ev.xclient.data.l[0] = __longIntVal(d1);
} else {
if (__isExternalAddress(d1)) {
ev.xclient.data.l[0] = (int)__externalAddressVal(d1);
} else {
ev.xclient.data.l[0] = 0;
}
}
if (__isInteger(d2)) {
ev.xclient.data.l[1] = __longIntVal(d2);
} else {
if (__isExternalAddress(d2)) {
ev.xclient.data.l[1] = (int)__externalAddressVal(d2);
} else {
ev.xclient.data.l[1] = 0;
}
}
if (__isInteger(d3)) {
ev.xclient.data.l[2] = __longIntVal(d3);
} else {
if (__isExternalAddress(d3)) {
ev.xclient.data.l[2] = (int)__externalAddressVal(d3);
} else {
ev.xclient.data.l[2] = 0;
}
}
if (__isInteger(d4)) {
ev.xclient.data.l[3] = __longIntVal(d4);
} else {
if (__isExternalAddress(d4)) {
ev.xclient.data.l[3] = (int)__externalAddressVal(d4);
} else {
ev.xclient.data.l[3] = 0;
}
}
if (__isInteger(d5)) {
ev.xclient.data.l[4] = __longIntVal(d5);
} else {
if (__isExternalAddress(d5)) {
ev.xclient.data.l[4] = (int)__externalAddressVal(d5);
} else {
ev.xclient.data.l[4] = 0;
}
}
if (__isExternalAddress(targetWindowID)) {
ev.xclient.window = __WindowVal(targetWindowID);
} else {
ev.xclient.window = (Window)__longIntVal(targetWindowID);
}
ev.xclient.type = ClientMessage;
ev.xclient.display = dpy;
ev.xclient.message_type = __longIntVal(msgType);
ev.xclient.format = __longIntVal(msgFormat);
ENTER_XLIB();
result = XSendEvent(dpy, ev.xclient.window, True, NoEventMask , &ev);
LEAVE_XLIB();
if ((result == BadValue) || (result == BadWindow)) {
DPRINTF(("bad status in sendClientEvent\n"));
RETURN ( false )
}
RETURN (true)
}
%}.
self primitiveFailedOrClosedConnection.
^ false
!
sendKeyOrButtonEvent:typeSymbol x:xPos y:yPos keyOrButton:keySymCodeOrButtonNr state:stateMask toViewId:targetId
"send a keyPress/Release or buttonPress/Release event to some (possibly alien) view.
TypeSymbol must be one of: #keyPress, #keyRelease, #buttonPress , #buttonRelease.
For buttonEvents, the keySymCodeOrButtonNr must be the buttons number (1, 2 ...);
for key events, it can be either a symbol (as listen in X's keySyms)
or a numeric keysym code. If state is nil, the modifier bits (shift & control)
are computed from the keyboardMap - if non-nil, these are passed as modifierbits.
The non-nil case is the lowlevel entry, where state must include any shift/ctrl information
(not very user friendly)"
<context: #return>
%{
int type;
int state;
if (__isSmallInteger(stateMask)) {
state = __intVal(stateMask);
} else {
state = 0;
}
if (ISCONNECTED
&& __isSmallInteger(xPos) && __isSmallInteger(yPos)
&& (__isSmallInteger(keySymCodeOrButtonNr) || __isSymbol(keySymCodeOrButtonNr) || __isString(keySymCodeOrButtonNr))
&& (__isExternalAddress(targetId) || __isInteger(targetId))) {
Display *dpy = myDpy;
XEvent ev;
Window target;
Status result;
KeySym keySym, *syms;
int screen = __intVal(__INST(screen));
char s[2];
int nSyms;
if ((typeSymbol == @symbol(keyPress))
|| (typeSymbol == @symbol(keyRelease))) {
if (__isSymbol(keySymCodeOrButtonNr) || __isString(keySymCodeOrButtonNr)) {
keySym = XStringToKeysym(__stringVal(keySymCodeOrButtonNr));
} else {
if (__isCharacter(keySymCodeOrButtonNr)) {
s[0] = __intVal(__characterVal(keySymCodeOrButtonNr));
s[1] = '\0';
keySym = XStringToKeysym(s);
} else {
keySym = (KeySym) __intVal(keySymCodeOrButtonNr);
}
}
ev.xkey.keycode = XKeysymToKeycode(dpy, keySym);
if (stateMask == nil) {
/*
* get the modifier from the keySym
*/
nSyms = 0;
syms = XGetKeyboardMapping(dpy, ev.xkey.keycode, 1, &nSyms);
if (syms) {
int i;
for (i=0; i<nSyms; i++) {
if (syms[i] == keySym) {
#ifdef MODIFIERDEBUG
printf("modifier-index is %d\n", i);
#endif
if (i) state = (1 << (i-1));
break;
}
}
XFree(syms);
}
}
} else {
if ((typeSymbol == @symbol(buttonPress))
|| (typeSymbol == @symbol(buttonRelease))) {
if (__isSmallInteger(keySymCodeOrButtonNr)) {
ev.xbutton.button = __intVal(keySymCodeOrButtonNr);
} else {
ev.xbutton.button = 1;
}
} else {
DPRINTF(("invalid sendEvent typeSymbol\n"));
RETURN (false);
}
}
if (typeSymbol == @symbol(keyPress))
ev.xany.type = KeyPress;
else if (typeSymbol == @symbol(keyRelease))
ev.xany.type = KeyRelease;
else if (typeSymbol == @symbol(buttonPress))
ev.xany.type = ButtonPress;
else if (typeSymbol == @symbol(buttonRelease))
ev.xany.type = ButtonRelease;
if (__isExternalAddress(targetId)) {
target = __WindowVal(targetId);
} else {
target = (Window) __longIntVal(targetId);
}
ev.xkey.window = target;
ev.xkey.same_screen = 1;
ev.xkey.subwindow = 0;
ev.xkey.root = RootWindow(dpy, screen);
ev.xkey.x = __intVal(xPos);
ev.xkey.y = __intVal(yPos);
ev.xkey.state = state;
ev.xkey.time = CurrentTime;
ENTER_XLIB();
result = XSendEvent(dpy, target, False, 0 , &ev);
LEAVE_XLIB();
if ((result == BadValue) || (result == BadWindow)) {
DPRINTF(("bad status\n"));
RETURN ( false )
}
RETURN (true)
}
%}.
self primitiveFailedOrClosedConnection.
^ false
! !
!XWorkstation methodsFor:'font stuff'!
createFontFor:aFontName
"a basic method for X-font allocation; this method allows
any font to be aquired (even those not conforming to
standard naming conventions, such as cursor, fixed or k14)"
<context: #return>
%{ /* UNLIMITEDSTACK */
/* xxUNLIMITEDSTACK xxSTACK:100000 */
XFontStruct *newFont;
if (ISCONNECTED
&& __isNonNilObject(aFontName)
&& (__qIsString(aFontName) || __qIsSymbol(aFontName))) {
ENTER_XLIB();
newFont = XLoadQueryFont(myDpy, (char *)__stringVal(aFontName));
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
if (newFont)
__cnt_font++;
#endif
RETURN ( newFont ? __MKEXTERNALADDRESS(newFont) : nil );
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
!
decomposeXFontName:aString into:aBlock
"extract family, face, style and size from an
X-font name
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
-brand-family-face-style-moreStyle- -height-size-resX-resY-??-??-registry-encoding;
evaluate aBlock with these"
|family face style moreStyle fheight size
resX resY registry encoding coding fields|
aString isNil ifTrue:[^ false].
fields := aString asCollectionOfSubstringsSeparatedBy:$-.
fields size == 3 ifTrue:[
"take care of old font names: family-style-size"
family := fields at:1.
style := fields at:2.
size := Number readFromString:(fields at:3) onError:[^ false].
] ifFalse:[fields size == 2 ifTrue:[
"take care of old font names: family-size"
family := fields at:1.
size := Number readFromString:(fields at:2) onError:[^ false].
] ifFalse:[fields size >= 15 ifTrue:[
family := fields at:3.
face := fields at:4.
style := fields at:5.
style = 'o' ifTrue:[
style := 'oblique'
] ifFalse:[style = 'i' ifTrue:[
style := 'italic'
] ifFalse:[style = 'r' ifTrue:[
style := 'roman'
]]].
moreStyle := fields at:6.
(moreStyle ~= 'normal' and:[moreStyle size > 1]) ifTrue:[
style := style, '-', moreStyle.
].
fheight := fields at:8.
size := (Number readFromString:(fields at:9) onError:[^ false]) / 10.
resX := fields at:10.
resY := fields at:11.
registry := fields at:14.
encoding := fields at:15.
coding := registry , '-' , encoding.
] ifFalse:[
^ false
]]].
aBlock value:family value:face value:style value:size value:coding.
^ true
!
encodingOf:aFontId
"the fonts encoding - if the font does not provide that info,
return nil (and assume #ascii, which is a subset of #iso8859)."
|info a|
info := self fontProperties:#(#'CHARSET_REGISTRY' #'CHARSET_ENCODING'
#'CHARSET_COLLECTIONS')
of:aFontId.
^ self
extractEncodingFromRegistry:((a := info at:1) notNil ifTrue:[self atomName:a] ifFalse:[])
encoding:((a := info at:2) notNil ifTrue:[self atomName:a] ifFalse:[])
charSetCollections:((a := info at:3) notNil ifTrue:[self atomName:a] ifFalse:[])
"
Screen current encodingOf:Screen current getDefaultFont
"
!
extractEncodingFromRegistry:registry encoding:encoding charSetCollections:charSetCollections
"this is pure magic ..."
|enc charSets|
(registry size ~~ 0) ifTrue:[
enc := registry asLowercase.
encoding size ~~ 0 ifTrue:[
enc := enc, '-', encoding asLowercase.
].
enc := enc asSymbol.
] ifFalse:[
(encoding size ~~ 0) ifTrue:[
enc := encoding asLowercase asSymbol
] ifFalse:[
charSets := charSetCollections.
(charSets notNil and:[charSets notEmpty]) ifTrue:[
charSets := charSets asUppercase asCollectionOfWords.
(charSets includes:'ISO8859-1') ifTrue:[
enc := #'iso8859-1'
] ifFalse:[
(charSets includes:'ISO8859') ifTrue:[
enc := #iso8859
] ifFalse:[
(charSets includes:'ASCII') ifTrue:[
enc := #ascii
] ifFalse:[
(charSets includes:'ADOBE-STANDARD') ifTrue:[
enc := #iso8859
]
]
]
]
]
]
].
^ enc
"Created: 17.4.1996 / 14:57:06 / cg"
"Modified: 17.4.1996 / 17:22:35 / cg"
!
flushListOfAvailableFonts
"flush the cached list of all available fonts on this display.
Required if new fonts have been added on the display server."
listOfXFonts := nil
"
Display flushListOfAvailableFonts.
Display listOfAvailableFonts
"
"Modified: 27.9.1995 / 10:54:47 / stefan"
"Created: 20.2.1996 / 22:55:52 / cg"
!
fontMetricInfoOf:fontId
"evaluate aBlock, passing a fonts metrics as arguments"
<context: #return>
|avgAscent avgDescent
maxAscent maxDescent minWidth maxWidth avgWidth|
%{
XFontStruct *f;
int len;
if (ISCONNECTED) {
if (__isExternalAddress(fontId)) {
f = __FontVal(fontId);
if (f) {
avgAscent = __MKSMALLINT(f->ascent);
avgDescent = __MKSMALLINT(f->descent);
maxAscent = __MKSMALLINT(f->max_bounds.ascent);
maxDescent = __MKSMALLINT(f->max_bounds.descent);
minWidth = __MKSMALLINT(f->min_bounds.width);
maxWidth = __MKSMALLINT(f->max_bounds.width);
ENTER_XLIB();
len = XTextWidth(f, " ", 1);
LEAVE_XLIB();
avgWidth = __MKSMALLINT( len );
}
}
}
%}.
avgAscent == nil ifTrue:[
self primitiveFailedOrClosedConnection.
^ nil
].
maxAscent == 0 ifTrue:[
"DingBats font does not define this"
maxAscent := avgAscent.
].
maxDescent == 0 ifTrue:[
"DingBats font does not define this"
maxDescent := avgDescent
].
^ Array
with:avgAscent
with:avgDescent
with:maxAscent
with:maxDescent
with:minWidth
with:maxWidth
with:avgWidth
!
fontMetricsOf:fontId into:aBlock
"evaluate aBlock, passing a fonts metrics as arguments"
|info encoding avgAscent avgDescent
maxAscent maxDescent minWidth maxWidth avgWidth|
info := self fontMetricInfoOf:fontId.
avgAscent := info at:1.
avgDescent := info at:2.
maxAscent := info at:3.
maxDescent := info at:4.
minWidth := info at:5.
maxWidth := info at:6.
avgWidth := info at:7.
encoding := self encodingOf:fontId.
aBlock value:encoding
value:avgAscent
value:avgDescent
value:maxAscent
value:maxDescent
value:minWidth
value:maxWidth
value:avgWidth
!
fontProperties:propertyNames of:aFontId
"Answer an array with selected property values of a font.
This is X11-Specific.
PropertyNames is an array with property names (symbols or strings).
Nonexistant properties are returned as nil"
|props propIds propValues|
propIds := propertyNames collect:[:n|
self atomIDOf:n.
].
props := self fontPropertiesOf:aFontId.
propValues := Array new:propertyNames size.
props pairWiseDo:[:p :v| |i|
i := propIds indexOf:p.
i > 0 ifTrue:[
propValues at:i put:v
].
].
^ propValues
"
Screen current fontProperties:#(#'PIXEL_SIZE' #'POINT_SIZE' #'RESOLUTION' notExistant) of:Screen current getDefaultFont
"
!
fontPropertiesOf:aFontId
"Answer an array with all the properties of a font.
This is X11-Specific.
Odd indices contain the property name (atom)
Even indices contain the property value (atom)
Answer nil, if there are no properties"
|props|
%{
XFontStruct *f;
XFontProp *prop;
int n, i;
OBJ x;
if (__isExternalAddress(aFontId)) {
f = __FontVal(aFontId);
if (f && (prop = f->properties) != 0) {
n = f->n_properties;
props = __ARRAY_NEW_INT(n*2);
for (i = 0; n; n--, prop++) {
__ArrayInstPtr(props)->a_element[i++] = x = __MKUINT(prop->name); __STORE(props, x);
__ArrayInstPtr(props)->a_element[i++] = x = __MKUINT(prop->card32); __STORE(props, x);
}
}
}
%}.
^ props.
"
Screen current fontPropertiesOf:Screen current getDefaultFont
Dictionary withKeysAndValues:(Screen current fontPropertiesOf:Screen current getDefaultFont)
|d|
d := Dictionary new.
(Screen current fontPropertiesOf:Screen current getDefaultFont) pairWiseDo:[:name :value|
d at:((Screen current atomName:name) ? name) put:value
].
d
"
!
fontResolutionOf:fontId
"return the resolution (as dpiX @ dpiY) of the font - this is usually the displays resolution,
but due to errors in some XServer installations, some use 75dpi fonts on higher
resolution displays and vice/versa."
|props res resX resY|
props := self fontProperties:#(#'RESOLUTION_X' #'RESOLUTION_Y' RESOLUTION)
of:fontId.
resX := props at:1.
resY := props at:2.
(resX notNil and:[resY notNil]) ifTrue:[
^ resX @ resY
].
res := props at:3.
res notNil ifTrue:[
^ res @ res
].
^ self resolution
"
Screen current fontResolutionOf:(Screen current getDefaultFont)
"
!
fullFontNameOf:aFontId
"the fonts fullName - this is very device specific and should only be
used for user feed-back (for example: in the fontPanel).
If the display/font does not provide that info, return nil."
|props fullName|
props := self fontProperties:#(#'FULL_NAME' FONT)
of:aFontId.
fullName := props at:1.
(fullName notNil and:[(fullName := self atomName:fullName) size ~~ 0]) ifTrue:[
^ fullName
].
fullName := props at:2.
fullName notNil ifTrue:[
^ self atomName:fullName.
].
^ nil.
"
Screen current fullFontNameOf:(Screen current getDefaultFont)
"
!
getAvailableFontsMatching:pattern
"return an Array filled with font names matching aPattern"
<context: #return>
%{ /* UNLIMITEDSTACK */
int nnames = 1500;
int available = nnames + 1;
char **fonts;
OBJ arr, str;
int i;
if (ISCONNECTED) {
if (__isString(pattern)) {
for (;;) {
ENTER_XLIB();
fonts = XListFonts(myDpy, __stringVal(pattern), nnames, &available);
LEAVE_XLIB();
if (fonts == 0) RETURN(nil);
if (available < nnames) break;
XFreeFontNames(fonts);
nnames = available * 2;
}
/*
* now, that we know the number of font names,
* create the array ...
*/
arr = __ARRAY_NEW_INT(available);
if (! arr) {
XFreeFontNames(fonts);
RETURN (nil);
}
/*
* ... and fill it
*/
for (i=0; i<available; i++) {
__PROTECT__(arr);
str = __MKSTRING(fonts[i]);
__UNPROTECT__(arr);
__ArrayInstPtr(arr)->a_element[i] = str; __STORE(arr, str);
}
XFreeFontNames(fonts);
RETURN (arr);
}
}
%}.
^ nil
!
getDefaultFont
"return a default font id - used when class Font cannot
find anything usable"
^ self createFontFor:'fixed'
"
Screen current getDefaultFont
"
!
getFontWithFamily:familyString face:faceString
style:styleArgString size:sizeArg encoding:encoding
"try to get the specified font, if not available, try next smaller
font. Access to X-fonts by name is possible, by passing the X font name
as family and the other parameters as nil. For example, the cursor font
can be aquired that way."
|styleString theName theId xlatedStyle
id spacing encodingMatch registryMatch idx|
styleString := styleArgString.
"special: if face is nil, allow access to X-fonts"
faceString isNil ifTrue:[
sizeArg notNil ifTrue:[
theName := familyString , '-' , sizeArg printString
] ifFalse:[
theName := familyString
].
theName isNil ifTrue:[
"
mhmh - fall back to the default font
"
theName := 'fixed'
].
theId := self createFontFor:theName.
theId isNil ifTrue:[
theId := self getDefaultFont
].
^ theId
].
"/ spacing other than 'normal' is contained as last component
"/ in style
(styleString notNil
and:[(styleString endsWith:'-narrow')
or:[styleString endsWith:'-semicondensed']]) ifTrue:[
|i|
i := styleString lastIndexOf:$-.
spacing := styleString copyFrom:(i+1).
styleString := styleString copyTo:(i-1).
] ifFalse:[
spacing := 'normal'.
].
xlatedStyle := styleString.
xlatedStyle notNil ifTrue:[
xlatedStyle := xlatedStyle first asString
].
registryMatch := '*'.
encoding isNil ifTrue:[
encodingMatch := '*'.
] ifFalse:[
idx := encoding indexOf:$-.
idx ~~ 0 ifTrue:[
registryMatch := encoding copyTo:idx - 1.
encodingMatch := encoding copyFrom:idx + 1
] ifFalse:[
registryMatch := encoding.
].
].
id := self
getFontWithFoundry:'*'
family:familyString asLowercase
weight:faceString
slant:xlatedStyle
spacing:spacing
pixelSize:nil
size:sizeArg
registry:registryMatch
encoding:encodingMatch.
id isNil ifTrue:[
(registryMatch notNil and:[registryMatch ~= '*']) ifTrue:[
"/ too stupid: registries come in both cases
"/ and X does not ignore case
"/
id := self
getFontWithFoundry:'*'
family:familyString asLowercase
weight:faceString
slant:xlatedStyle
spacing:spacing
pixelSize:nil
size:sizeArg
registry:registryMatch asUppercase
encoding:encodingMatch.
id isNil ifTrue:[
id := self
getFontWithFoundry:'*'
family:familyString asLowercase
weight:faceString
slant:xlatedStyle
spacing:spacing
pixelSize:nil
size:sizeArg
registry:registryMatch asLowercase
encoding:encodingMatch.
]
]
].
^ id
"Modified: 4.7.1996 / 11:38:47 / stefan"
"Modified: 10.4.1997 / 19:20:06 / cg"
!
getFontWithFoundry:foundry family:family weight:weight
slant:slant spacing:spc pixelSize:pSize size:size
registry:registry encoding:encoding
"get the specified font, if not available, return nil.
This is the new font creation method - all others will be changed to
use this entry.
Individual attributes can be left empty (i.e. '') or nil to match any.
foundry: 'adobe', 'misc', 'dec', 'schumacher' ... usually '*'
family: 'helvetica' 'courier' 'times' ...
weight: 'bold' 'medium' 'demi' ...
slant: 'r(oman)' 'i(talic)' 'o(blique)'
spacing: 'narrow' 'normal' semicondensed' ... usually '*'
pixelSize: 16,18 ... usually left empty
size: size in point (1/72th of an inch)
registry: iso8859, sgi ... '*'
encoding: registry specific encoding (usually '*')
"
|theName sizeMatch
foundryMatch familyMatch weightMatch slantMatch spcMatch
pSizeMatch registryMatch encodingMatch|
"this works only on 'Release >= 3' - X-servers"
"name is:
-foundry-family -weight -slant-
sony helvetica bold r
adobe courier medium i
msic fixed o
... ...
"
size isNil ifTrue:[
sizeMatch := '*'
] ifFalse:[
sizeMatch := size printString , '0'
].
foundry isNil ifTrue:[
foundryMatch := '*'
] ifFalse:[
foundryMatch := foundry
].
family isNil ifTrue:[
familyMatch := '*'
] ifFalse:[
familyMatch := family
].
weight isNil ifTrue:[
weightMatch := '*'
] ifFalse:[
weightMatch := weight
].
slant isNil ifTrue:[
slantMatch := '*'
] ifFalse:[
slantMatch := slant
].
spc isNil ifTrue:[
spcMatch := '*'
] ifFalse:[
spcMatch := spc
].
pSize isNil ifTrue:[
pSizeMatch := '*'
] ifFalse:[
pSizeMatch := pSize printString
].
registry isNil ifTrue:[
registryMatch := '*'
] ifFalse:[
registryMatch := registry
].
encoding isNil ifTrue:[
encodingMatch := '*'
] ifFalse:[
encodingMatch := encoding
].
theName := ('-' , foundryMatch,
'-' , familyMatch,
'-' , weightMatch ,
'-' , slantMatch ,
'-' , spcMatch ,
'-*' ,
'-' , pSizeMatch ,
'-' , sizeMatch ,
'-*-*-*-*' ,
'-' , registryMatch ,
'-' , encodingMatch).
"/ Transcript showCR:theName; endEntry.
^ self createFontFor:theName.
"
Display getFontWithFoundry:'*'
family:'courier'
weight:'medium'
slant:'r'
spacing:nil
pixelSize:nil
size:13
registry:'iso8859'
encoding:'*'
"
"Modified: 10.4.1997 / 19:15:44 / cg"
!
listOfAvailableFonts
"return a list with all available fonts on this display.
Since this takes some time, keep the result of the query for the
next time. The elements of the returned collection are instances of
FontDescription."
|names|
listOfXFonts isNil ifTrue:[
names := self getAvailableFontsMatching:'*'.
names isNil ifTrue:[
"no names returned ..."
^ nil
].
listOfXFonts := names collect:[:aName |
|fntDescr|
(self decomposeXFontName:aName into:
[:family :face :style :size :coding |
family notNil ifTrue:[
fntDescr := FontDescription
family:family
face:face
style:style
size:size
encoding:coding.
] ifFalse:[
fntDescr := FontDescription
name:aName
]
]
) ifFalse:[
fntDescr := FontDescription name:aName.
].
fntDescr
].
].
^ listOfXFonts
"
Display listOfAvailableFonts.
Display getAvailableFontsMatching:'fixed'.
Display fontsInFamily:'fixed' filtering:nil.
"
"Modified: 27.9.1995 / 10:54:47 / stefan"
"Modified: 17.4.1996 / 15:27:57 / cg"
!
releaseFont:aFontId
<context: #return>
%{
XFontStruct *f;
if (! ISCONNECTED) {
RETURN ( self );
}
if (__isExternalAddress(aFontId)) {
f = __FontVal(aFontId);
if (f) {
ENTER_XLIB();
XFreeFont(myDpy, f);
LEAVE_XLIB();
#ifdef COUNT_RESOURCES
__cnt_font--;
#endif
RETURN ( self );
}
}
%}.
self primitiveFailed
!
sizesInFamily:aFamilyName face:aFaceName style:aStyleName filtering:filter
"return a set of all available font sizes in aFamily/aFace/aStyle
on this display.
Redefined to handle X's special case of 0-size (which stands for any)"
|sizes|
sizes := super sizesInFamily:aFamilyName face:aFaceName style:aStyleName filtering:filter.
(sizes notNil and:[sizes includes:0]) ifTrue:[
"special: in X11R5 and above, size 0 means:
there are scaled versions in all sizes available"
^ #(4 5 6 7 8 9 10 11 12 14 16 18 20 22 24 28 32 48 64 72 96)
].
^ sizes
"
Display sizesInFamily:'courier' face:'bold' style:'roman'
"
"Created: 27.2.1996 / 01:38:15 / cg"
!
widthOf:aString from:index1 to:index2 inFont:aFontId
<context: #return>
%{
XFontStruct *f;
char *cp;
int len, n, i1, i2, l;
OBJ cls;
# define NLOCALBUFFER 200
XChar2b xlatebuffer[NLOCALBUFFER];
int nInstBytes;
if (ISCONNECTED) {
if (__bothSmallInteger(index1, index2)
&& __isExternalAddress(aFontId)
&& __isNonNilObject(aString)) {
int lMax = __intVal(@global(XWorkstation:MaxStringLength));
f = __FontVal(aFontId);
if (! f) goto fail;
i1 = __intVal(index1) - 1;
cls = __qClass(aString);
if (i1 >= 0) {
i2 = __intVal(index2) - 1;
if (i2 < i1) {
RETURN ( __MKSMALLINT(0) );
}
cp = (char *) __stringVal(aString);
l = i2 - i1 + 1;
if ((cls == @global(String)) || (cls == @global(Symbol))) {
n = __stringSize(aString);
if (i2 < n) {
cp += i1;
ENTER_XLIB();
len = XTextWidth(f, cp, l);
LEAVE_XLIB();
RETURN ( __MKSMALLINT(len) );
}
}
nInstBytes = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
cp += nInstBytes;
if (__isBytes(aString)) {
n = __byteArraySize(aString) - nInstBytes;
if (i2 < n) {
cp += i1;
ENTER_XLIB();
len = XTextWidth(f, cp, l);
LEAVE_XLIB();
RETURN ( __MKSMALLINT(len) );
}
}
/* TWOBYTESTRINGS */
if (__isWords(aString)) {
n = (__byteArraySize(aString) - nInstBytes) / 2;
if (i2 < n) {
union {
char b[2];
unsigned short s;
} u;
int i;
XChar2b *cp2 = (XChar2b *)0;
int mustFree = 0;
cp += (i1 * 2);
if (l > lMax) l = lMax;
/*
* ST/X TwoByteStrings store the asciiValue in native byteOrder;
* X expects them MSB first
* convert as required
*/
u.s = 0x1234;
if (u.b[0] != 0x12) {
if (l <= NLOCALBUFFER) {
cp2 = xlatebuffer;
} else {
cp2 = (XChar2b *)(malloc(l * 2));
mustFree = 1;
}
for (i=0; i<l; i++) {
cp2[i].byte1 = (((XChar2b *)cp)[i]).byte2;
cp2[i].byte2 = (((XChar2b *)cp)[i]).byte1;
}
cp = (char *) cp2;
}
ENTER_XLIB();
len = XTextWidth16(f, (XChar2b *)cp, l);
LEAVE_XLIB();
if (mustFree) {
free(cp2);
}
RETURN ( __MKSMALLINT(len) );
}
}
}
}
}
#undef NLOCALBUFFER
fail: ;
%}.
self primitiveFailedOrClosedConnection.
^ 0
!
widthOf:aString inFont:aFontId
<context: #return>
%{
XFontStruct *f;
char *cp;
int len, n;
OBJ cls;
# define NLOCALBUFFER 200
XChar2b xlatebuffer[NLOCALBUFFER];
int nInstBytes;
if (ISCONNECTED) {
if (__isExternalAddress(aFontId)
&& __isNonNilObject(aString)) {
int lMax = __intVal(@global(XWorkstation:MaxStringLength));
f = __FontVal(aFontId);
if (! f) goto fail;
cls = __qClass(aString);
cp = (char *) __stringVal(aString);
if ((cls == @global(String)) || (cls == @global(Symbol))) {
n = __stringSize(aString);
ENTER_XLIB();
len = XTextWidth(f, cp, n);
LEAVE_XLIB();
RETURN ( __MKSMALLINT(len) );
}
nInstBytes = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
cp += nInstBytes;
if (__isBytes(aString)) {
n = __byteArraySize(aString) - nInstBytes;
ENTER_XLIB();
len = XTextWidth(f, cp, n);
LEAVE_XLIB();
RETURN ( __MKSMALLINT(len) );
}
/* TWOBYTESTRINGS */
if (__isWords(aString)) {
union {
char b[2];
unsigned short s;
} u;
int i;
XChar2b *cp2;
int mustFree = 0;
n = (__byteArraySize(aString) - nInstBytes) / 2;
if (n > lMax) n = lMax;
/*
* ST/X TwoByteStrings store the asciiValue in native byteOrder;
* X expects them MSB first
* convert as required
*/
u.s = 0x1234;
if (u.b[0] != 0x12) {
if (n <= NLOCALBUFFER) {
cp2 = xlatebuffer;
} else {
cp2 = (XChar2b *)(malloc(n * 2));
mustFree = 1;
}
for (i=0; i<n; i++) {
cp2[i].byte1 = (((XChar2b *)cp)[i]).byte2;
cp2[i].byte2 = (((XChar2b *)cp)[i]).byte1;
}
cp = (char *) cp2;
}
ENTER_XLIB();
len = XTextWidth16(f, (XChar2b *)cp, n);
LEAVE_XLIB();
if (mustFree) {
free(cp2);
}
RETURN ( __MKSMALLINT(len) );
}
}
}
#undef NLOCALBUFFER
fail: ;
%}.
^ super widthOf:aString inFont:aFontId
! !
!XWorkstation methodsFor:'grabbing'!
allowEvents:mode
<context: #return>
%{
int _mode, ok = 1;
if (mode == @symbol(asyncPointer))
_mode = AsyncPointer;
else if (mode == @symbol(syncPointer))
_mode = SyncPointer;
else if (mode == @symbol(asyncKeyboard))
_mode = AsyncKeyboard;
else if (mode == @symbol(syncKeyboard))
_mode = SyncKeyboard;
else if (mode == @symbol(syncBoth))
_mode = SyncBoth;
else if (mode == @symbol(asyncBoth))
_mode = AsyncBoth;
else if (mode == @symbol(replayPointer))
_mode = ReplayPointer;
else if (mode == @symbol(replayKeyboard))
_mode = ReplayKeyboard;
else
ok = 0;
if (ok
&& ISCONNECTED) {
ENTER_XLIB();
XAllowEvents(myDpy, _mode, CurrentTime);
LEAVE_XLIB();
RETURN (self);
}
%}.
self primitiveFailedOrClosedConnection
!
grabKeyboardIn:aWindowId
"grab the keyboard"
<context: #return>
%{
int result, ok;
if (ISCONNECTED) {
if (__isExternalAddress(aWindowId)) {
ENTER_XLIB();
result = XGrabKeyboard(myDpy,
__WindowVal(aWindowId),
True /* False */,
GrabModeAsync,
GrabModeAsync,
CurrentTime);
LEAVE_XLIB();
ok = 0;
switch(result) {
case AlreadyGrabbed:
if (@global(ErrorPrinting) == true) {
fprintf(stderr, "XWorkstation [warning]: grab keyboard: AlreadyGrabbed\n");
}
break;
case GrabNotViewable:
if (@global(ErrorPrinting) == true) {
fprintf(stderr, "XWorkstation [warning]: grab keyboard: GrabNotViewable\n");
}
break;
case GrabInvalidTime:
if (@global(ErrorPrinting) == true) {
fprintf(stderr, "XWorkstation [warning]: grab keyboard: InvalidTime\n");
}
break;
case GrabFrozen:
if (@global(ErrorPrinting) == true) {
fprintf(stderr, "XWorkstation [warning]: grab keyboard: Frozen\n");
}
break;
default:
ok = 1;
break;
}
if (! ok) {
ENTER_XLIB();
XUngrabKeyboard(myDpy, CurrentTime);
LEAVE_XLIB();
RETURN (false);
}
RETURN ( true );
}
}
%}.
self primitiveFailedOrClosedConnection.
^ false
!
grabPointerIn:aWindowId withCursor:aCursorId eventMask:eventMask pointerMode:pMode keyboardMode:kMode confineTo:confineId
"grap the pointer - return true if ok"
<context: #return>
%{
int result, ok, evMask;
Window confineWin;
Cursor curs;
int pointer_mode, keyboard_mode;
if (ISCONNECTED) {
if (__isExternalAddress(aWindowId)) {
if (__isExternalAddress(confineId))
confineWin = __WindowVal(confineId);
else
confineWin = (Window) None;
if (__isExternalAddress(aCursorId))
curs = __CursorVal(aCursorId);
else
curs = (Cursor) None;
if (pMode == @symbol(sync))
pointer_mode = GrabModeSync;
else
pointer_mode = GrabModeAsync;
if (kMode == @symbol(sync))
keyboard_mode = GrabModeSync;
else
keyboard_mode = GrabModeAsync;
if (__isSmallInteger(eventMask))
evMask = __intVal(eventMask);
else
evMask = ButtonPressMask | ButtonMotionMask | PointerMotionMask | ButtonReleaseMask;
/*
ENTER_XLIB();
*/
result = XGrabPointer(myDpy,
__WindowVal(aWindowId),
False,
evMask,
pointer_mode, keyboard_mode,
confineWin,
curs,
CurrentTime);
/*
LEAVE_XLIB();
*/
ok = 0;
switch (result) {
case AlreadyGrabbed:
if (@global(ErrorPrinting) == true) {
fprintf(stderr, "XWorkstation [warning]: grab pointer: AlreadyGrabbed\n");
}
break;
case GrabNotViewable:
if (@global(ErrorPrinting) == true) {
fprintf(stderr, "XWorkstation [warning]: grab pointer: GrabNotViewable\n");
}
break;
case GrabInvalidTime:
if (@global(ErrorPrinting) == true) {
fprintf(stderr, "XWorkstation [warning]: grab pointer: InvalidTime\n");
}
break;
case GrabFrozen:
if (@global(ErrorPrinting) == true) {
fprintf(stderr, "XWorkstation [warning]: grab pointer: Frozen\n");
}
break;
default:
ok = 1;
break;
}
if (! ok) {
/*
ENTER_XLIB();
*/
XUngrabPointer(myDpy, CurrentTime);
/*
LEAVE_XLIB();
*/
RETURN (false);
}
RETURN ( true );
}
}
%}.
self primitiveFailedOrClosedConnection.
^ false
!
grabPointerIn:aWindowId withCursor:aCursorId pointerMode:pMode keyboardMode:kMode confineTo:confineId
"grap the pointer - return true if ok"
^ self
grabPointerIn:aWindowId
withCursor:aCursorId
eventMask:nil
pointerMode:pMode
keyboardMode:kMode
confineTo:confineId
"Modified: / 28.7.1998 / 02:47:51 / cg"
!
primUngrabKeyboard
"release the keyboard"
<context: #return>
%{
if (ISCONNECTED) {
Display *dpy = myDpy;
ENTER_XLIB();
XUngrabKeyboard(dpy, CurrentTime);
XSync(dpy, 0);
LEAVE_XLIB();
}
%}.
!
primUngrabPointer
"release the pointer"
<context: #return>
%{
if (ISCONNECTED) {
Display *dpy = myDpy;
ENTER_XLIB();
XUngrabPointer(dpy, CurrentTime);
XSync(dpy, 0);
LEAVE_XLIB();
}
%}.
!
ungrabKeyboard
"release the keyboard"
self primUngrabKeyboard.
activeKeyboardGrab := nil
!
ungrabPointer
"release the pointer"
self primUngrabPointer.
activePointerGrab := nil.
! !
!XWorkstation methodsFor:'graphic context stuff'!
noClipIn:aDrawableId gc:aGCId
"disable clipping rectangle"
<context: #return>
%{
XGCValues gcv;
GC gc;
if (ISCONNECTED) {
if (__isExternalAddress(aGCId)) {
gc = __GCVal(aGCId);
gcv.clip_mask = None;
ENTER_XLIB();
XChangeGC(myDpy, gc, GCClipMask, &gcv);
LEAVE_XLIB();
RETURN ( self );
}
}
%}.
self primitiveFailedOrClosedConnection
!
setBackground:bgColorIndex in:aGCId
"set background color to be drawn with"
<context: #return>
%{
if (ISCONNECTED) {
if (__isExternalAddress(aGCId)
&& __isSmallInteger(bgColorIndex)) {
ENTER_XLIB();
XSetBackground(myDpy, __GCVal(aGCId), __intVal(bgColorIndex));
LEAVE_XLIB();
RETURN ( self );
}
}
%}.
self primitiveFailedOrClosedConnection
!
setBitmapMask:aBitmapId in:aGCId
"set or clear the drawing mask - a bitmap mask using current fg/bg"
<context: #return>
%{
GC gc;
Pixmap bitmap;
if (ISCONNECTED) {
Display *dpy = myDpy;
if (__isExternalAddress(aGCId)) {
gc = __GCVal(aGCId);
if (__isExternalAddress(aBitmapId)) {
bitmap = __PixmapVal(aBitmapId);
ENTER_XLIB();
XSetStipple(dpy, gc, bitmap);
XSetFillStyle(dpy, gc, FillOpaqueStippled);
LEAVE_XLIB();
RETURN ( self );
}
if (aBitmapId == nil) {
ENTER_XLIB();
XSetFillStyle(dpy, gc, FillSolid);
LEAVE_XLIB();
RETURN ( self );
}
}
}
%}.
self primitiveFailedOrClosedConnection
!
setClipByChildren:aBool in:aDrawableId gc:aGCId
"enable/disable drawing into child views"
<context: #return>
%{
XGCValues gcv;
GC gc;
if (ISCONNECTED) {
if (__isExternalAddress(aGCId)) {
gc = __GCVal(aGCId);
if (aBool == true)
gcv.subwindow_mode = ClipByChildren;
else
gcv.subwindow_mode = IncludeInferiors;
ENTER_XLIB();
XChangeGC(myDpy, gc, GCSubwindowMode, &gcv);
LEAVE_XLIB();
RETURN ( self );
}
}
%}.
self primitiveFailedOrClosedConnection
!
setClipX:clipX y:clipY width:clipWidth height:clipHeight in:drawableId gc:aGCId
"clip to a rectangle"
<context: #return>
%{
XRectangle r;
if (ISCONNECTED) {
if (__isExternalAddress(aGCId)
&& __bothSmallInteger(clipX, clipY)
&& __bothSmallInteger(clipWidth, clipHeight)) {
r.x = __intVal(clipX);
r.y = __intVal(clipY);
r.width = __intVal(clipWidth);
r.height = __intVal(clipHeight);
ENTER_XLIB();
XSetClipRectangles(myDpy, __GCVal(aGCId), 0, 0, &r, 1, Unsorted);
LEAVE_XLIB();
RETURN ( self );
}
}
%}.
self primitiveFailedOrClosedConnection
!
setDashes:dashList dashOffset:offset in:aGCId
"set line attributes"
<context: #return>
%{
if (ISCONNECTED) {
if (__isExternalAddress(aGCId)
&& __isSmallInteger(offset)
&& __isByteArray(dashList)) {
ENTER_XLIB();
XSetDashes(myDpy, __GCVal(aGCId),
__intVal(offset),
__ByteArrayInstPtr(dashList)->ba_element,
__byteArraySize(dashList));
LEAVE_XLIB();
RETURN ( self );
}
}
bad: ;
%}.
"
either aGCId is invalid,
and/or dashList is not a byteArray
and/or offset is not a smallInteger
"
self primitiveFailedOrClosedConnection
!
setFont:aFontId in:aGCId
"set font to be drawn in"
<context: #return>
%{
XFontStruct *f;
if (ISCONNECTED) {
if (__isExternalAddress(aFontId)
&& __isExternalAddress(aGCId)) {
f = (XFontStruct *) __FontVal(aFontId);
ENTER_XLIB();
XSetFont(myDpy, __GCVal(aGCId), f->fid);
LEAVE_XLIB();
RETURN ( self );
}
}
%}.
"
aGCId and/or aFontId are invalid
"
self primitiveFailedOrClosedConnection
!
setForeground:fgColorIndex background:bgColorIndex in:aGCId
"set foreground and background colors to be drawn with"
<context: #return>
%{
GC gc;
if (ISCONNECTED) {
Display *dpy = myDpy;
if (__bothSmallInteger(fgColorIndex, bgColorIndex)
&& __isExternalAddress(aGCId)) {
gc = __GCVal(aGCId);
ENTER_XLIB();
XSetForeground(dpy, gc, __intVal(fgColorIndex));
XSetBackground(dpy, gc, __intVal(bgColorIndex));
LEAVE_XLIB();
RETURN ( self );
}
}
%}.
self primitiveFailedOrClosedConnection
!
setForeground:fgColorIndex in:aGCId
"set foreground color to be drawn with"
<context: #return>
%{
if (ISCONNECTED) {
if (__isExternalAddress(aGCId)
&& __isSmallInteger(fgColorIndex)) {
ENTER_XLIB();
XSetForeground(myDpy, __GCVal(aGCId), __intVal(fgColorIndex));
LEAVE_XLIB();
RETURN ( self );
}
}
%}.
self primitiveFailedOrClosedConnection
!
setFunction:aFunctionSymbol in:aGCId
"set alu function to be drawn with"
<context: #return>
%{
GC gc;
int fun = -1;
if (ISCONNECTED) {
if (__isExternalAddress(aGCId)) {
gc = __GCVal(aGCId);
if (aFunctionSymbol == @symbol(copy)) fun = GXcopy;
else if (aFunctionSymbol == @symbol(copyInverted)) fun = GXcopyInverted;
else if (aFunctionSymbol == @symbol(xor)) fun = GXxor;
else if (aFunctionSymbol == @symbol(and)) fun = GXand;
else if (aFunctionSymbol == @symbol(andReverse)) fun = GXandReverse;
else if (aFunctionSymbol == @symbol(andInverted)) fun = GXandInverted;
else if (aFunctionSymbol == @symbol(or)) fun = GXor;
else if (aFunctionSymbol == @symbol(orReverse)) fun = GXorReverse;
else if (aFunctionSymbol == @symbol(orInverted)) fun = GXorInverted;
else if (aFunctionSymbol == @symbol(invert)) fun = GXinvert;
else if (aFunctionSymbol == @symbol(clear)) fun = GXclear;
else if (aFunctionSymbol == @symbol(set)) fun = GXset;
else if (aFunctionSymbol == @symbol(noop)) fun = GXnoop;
else if (aFunctionSymbol == @symbol(equiv)) fun = GXequiv;
else if (aFunctionSymbol == @symbol(nand)) fun = GXnand;
if (fun != -1) {
ENTER_XLIB();
XSetFunction(myDpy, gc, fun);
LEAVE_XLIB();
RETURN ( self );
}
}
}
%}.
"
either aGCId is not an integer, or an invalid symbol
was passed ... valid functions are #copy, #copyInverted, #xor, #and, #andReverse,
#andInverted, #or, #orReverse, #orInverted. See Xlib documentation for more details.
"
self primitiveFailedOrClosedConnection
!
setGraphicsExposures:aBoolean in:aGCId
"set or clear the graphics exposures flag"
<context: #return>
%{
if (ISCONNECTED) {
if (__isExternalAddress(aGCId)) {
ENTER_XLIB();
XSetGraphicsExposures(myDpy, __GCVal(aGCId), (aBoolean==true)?1:0);
LEAVE_XLIB();
RETURN ( self );
}
}
%}.
self primitiveFailedOrClosedConnection
!
setLineWidth:aNumber style:lineStyle cap:capStyle join:joinStyle in:aGCId
"set line attributes;
lineStyle must be one of #solid, #dashed or #doubleDashed;
capStyle one of: #notLast, #butt, #round or #projecting;
joinStyle one of: #miter, #bevel or #round."
<context: #return>
%{
int x_style, x_cap, x_join;
static char dashList[2] = { 1,1 };
static char dotList[2] = { 4,4 };
static char dashDotList[4] = { 4,1 , 1,1 };
static char dashDotDotList[6] = { 4,1 , 1,1 , 1,1 };
char *x_dashes = 0;
int x_nDash;
if (ISCONNECTED) {
if (__isExternalAddress(aGCId)
&& __isSmallInteger(aNumber)) {
Display *dpy = myDpy;
if (lineStyle == @symbol(solid)) {
x_dashes = (char *)0;
x_style = LineSolid;
} else if (lineStyle == @symbol(dashed)) {
x_dashes = dashList;
x_nDash = sizeof(dashList);
x_style = LineOnOffDash;
} else if (lineStyle == @symbol(doubleDashed)) {
x_dashes = dashList;
x_nDash = sizeof(dashList);
x_style = LineDoubleDash;
} else if (lineStyle == @symbol(dotted)) {
x_dashes = dotList;
x_nDash = sizeof(dotList);
x_style = LineOnOffDash;
} else if (lineStyle == @symbol(dashDot)) {
x_dashes = dashDotList;
x_nDash = sizeof(dashDotList);
x_style = LineOnOffDash;
} else if (lineStyle == @symbol(dashDotDot)) {
x_dashes = dashDotDotList;
x_nDash = sizeof(dashDotDotList);
x_style = LineOnOffDash;
} else goto bad;
if (capStyle == @symbol(notLast)) x_cap = CapNotLast;
else if (capStyle == @symbol(butt)) x_cap = CapButt;
else if (capStyle == @symbol(round)) x_cap = CapRound;
else if (capStyle == @symbol(projecting)) x_cap = CapProjecting;
else goto bad;
if (joinStyle == @symbol(miter)) x_join = JoinMiter;
else if (joinStyle == @symbol(bevel)) x_join = JoinBevel;
else if (joinStyle == @symbol(round)) x_join = JoinRound;
else goto bad;
ENTER_XLIB();
if (x_dashes) {
XSetDashes(dpy, __GCVal(aGCId), 0, x_dashes, x_nDash);
}
XSetLineAttributes(dpy,
__GCVal(aGCId), __intVal(aNumber),
x_style, x_cap, x_join);
LEAVE_XLIB();
RETURN ( self );
}
}
bad: ;
%}.
"
either aGCId is invalid,
and/or lineWidth is not a smallInteger,
and/or lineStyle is none of #solid, #dashed, #doubleDashed
and/or capStyle is none of #notLast, #butt, #round, #projecting
and/or joinStyle is none of #miter, #bevel, #round
"
self primitiveFailedOrClosedConnection
!
setMaskOriginX:orgX y:orgY in:aGCid
"set the mask origin"
<context: #return>
%{
if (ISCONNECTED) {
if (__bothSmallInteger(orgX, orgY) && __isExternalAddress(aGCid)) {
ENTER_XLIB();
XSetTSOrigin(myDpy, __GCVal(aGCid), __intVal(orgX), __intVal(orgY));
LEAVE_XLIB();
RETURN ( self );
}
}
%}.
self primitiveFailedOrClosedConnection
!
setPixmapMask:aPixmapId in:aGCId
"set or clear the drawing mask - a pixmap mask providing full color"
<context: #return>
%{
GC gc;
Pixmap pixmap;
if (ISCONNECTED) {
Display *dpy = myDpy;
if (__isExternalAddress(aGCId)) {
gc = __GCVal(aGCId);
if (__isExternalAddress(aPixmapId)) {
pixmap = __PixmapVal(aPixmapId);
ENTER_XLIB();
XSetTile(dpy, gc, pixmap);
XSetFillStyle(dpy, gc, FillTiled);
LEAVE_XLIB();
RETURN ( self );
}
if (aPixmapId == nil) {
ENTER_XLIB();
XSetFillStyle(dpy, gc, FillSolid);
LEAVE_XLIB();
RETURN ( self );
}
}
}
%}.
self primitiveFailedOrClosedConnection
! !
!XWorkstation methodsFor:'initialize / release'!
closeConnection
"close down the connection to the X-server"
<context: #return>
"/ 'closing' errorPrintCR.
"/ thisContext fullPrintAll.
%{
if (ISCONNECTED) {
Display *dpy = myDpy;
__INST(displayId) = nil;
ENTER_XLIB();
XCloseDisplay(dpy);
LEAVE_XLIB();
}
%}
!
emergencyCloseConnection
"low level close of the displays connection (without sending any buffered
requests to the display). Only used in case of emergency (brokenConnection)"
%{
if (ISCONNECTED) {
Display *dpy = myDpy;
__INST(displayId) = nil;
close(ConnectionNumber(dpy));
}
%}
!
eventBufferSize
%{
RETURN ( __MKSMALLINT(sizeof(XEvent) + 100) );
%}
!
initializeDefaultValues
activateOnClick := false.
super initializeDefaultValues.
!
initializeDeviceSignals
super initializeDeviceSignals.
deviceIOTimeoutErrorSignal := deviceIOErrorSignal newSignal.
deviceIOTimeoutErrorSignal nameClass:self message:#deviceIOTimeoutErrorSignal.
ObjectMemory registerErrorInterruptHandler:self class forID:#DisplayError.
ObjectMemory registerErrorInterruptHandler:self class forID:#DisplayIOError.
ObjectMemory registerErrorInterruptHandler:self class forID:#DisplayIOTimeoutError.
!
initializeEventBuffer
eventBuffer isNil ifTrue:[
eventBuffer := ByteArray new:(self eventBufferSize).
].
!
initializeFor:aDisplayName
"initialize the receiver for a connection to an X-Server;
the argument, aDisplayName may be nil (for the default server from
DISPLAY-variable or command line argument) or the name of the server
as hostname:number"
|dpyName index arguments|
displayId notNil ifTrue:[
"/ already connected - you bad guy try to trick me manually ?
^ self
].
dpyName := aDisplayName.
dpyName isNil ifTrue:[
"look for a '-display xxx' argument"
(arguments := Smalltalk commandLineArguments) notNil ifTrue:[
index := arguments indexOf:'-display'.
(index between:1 and:(arguments size - 1)) ifTrue:[
dpyName := arguments at:index+1
]
].
dpyName isNil ifTrue:[
dpyName := OperatingSystem getEnvironment:'DISPLAY'.
].
].
displayId := self openConnectionTo:dpyName.
displayId isNil ifTrue:[
"/ could not connect.
"/ only output a message, if running under X
((OperatingSystem isMSWINDOWSlike not) or:[WinWorkstation isNil]) ifTrue:[
'XWorkstation [warning]: cannot connect to Display (' infoPrint.
(dpyName ? ((OperatingSystem getEnvironment:'Display') ? 'default')) infoPrint.
')' infoPrintCR.
].
^ nil
].
dispatching := false.
dispatchingExpose := false.
isSlow := false.
shiftDown := false.
ctrlDown := false.
metaDown := false.
altDown := false.
motionEventCompression := true.
buttonsPressed := 0.
displayName := dpyName.
listOfXFonts := nil.
atoms := nil.
protocolsAtom := nil.
deleteWindowAtom := nil.
saveYourselfAtom := nil.
quitAppAtom := nil.
self initializeDeviceResourceTables.
self initializeScreenProperties.
self initializeDefaultValues.
self initializeEventBuffer.
self initializeSpecialFlags.
self initializeKeyboardMap.
self initializeDeviceSignals.
self initializeViewStyle.
!
initializeModifierMappings
"initialize keyboard modifiers.
We assume that mod1 are the META modifiers and mod2 are the ALT modifiers,
but if any of them contains the Num_Lock key, it is disregarded."
|map mod|
super initializeModifierMappings.
rawKeySymTranslation := RawKeySymTranslation.
map := self modifierMapping.
map isNil ifTrue:[
"/
"/ mhmh - a crippled Xlib which does not provide modifier mappings
"/ setup some reasonable default. If that is not sufficient,
"/ you have to change things from your display.rc file.
"/
altModifierMask := self modifier1Mask.
metaModifierMask := self modifier2Mask.
] ifFalse:[
altModifierMask := 0.
metaModifierMask := 0.
mod := map at:1.
mod notNil ifTrue:[
shiftModifiers := mod collect:[ :key | self stringFromKeycode:key ].
].
mod := map at:3.
mod notNil ifTrue:[
ctrlModifiers := mod collect:[ :key | self stringFromKeycode:key ].
].
mod := map at:4.
mod notNil ifTrue:[
mod := mod collect:[ :key | self stringFromKeycode:key ].
(mod includes:'Num_Lock') ifFalse:[
metaModifiers := mod.
metaModifierMask := 1 bitShift:(4-1).
].
].
mod := map at:5.
mod notNil ifTrue:[
mod := mod collect:[ :key | self stringFromKeycode:key ].
(mod includes:'Num_Lock') ifFalse:[
altModifiers := mod.
altModifierMask := 1 bitShift:(5-1).
].
]
].
"
Display initializeModifierMappings
"
"Modified: 1.12.1995 / 23:44:40 / stefan"
!
initializeScreenProperties
|masks|
super initializeScreenProperties.
hasShapeExtension := self queryShapeExtension.
hasShmExtension := self querySHMExtension.
hasDPSExtension := self queryDPSExtension.
hasXVideoExtension := self queryXVideoExtension.
hasMbufExtension := self queryMBUFExtension.
hasPEXExtension := self queryPEXExtension.
hasImageExtension := self queryXIEExtension.
hasInputExtension := self queryXIExtension.
primaryAtom := self atomIDOf:#PRIMARY.
stringAtom := self atomIDOf:#STRING.
cutBuffer0Atom := self atomIDOf:#'CUT_BUFFER0'.
altModifierMask := self modifier2Mask.
metaModifierMask := self modifier1Mask.
screen := self queryDefaultScreen.
depth := self queryDepth.
ncells := self queryCells.
width := self queryWidth.
height := self queryHeight.
widthMM := self queryWidthMM.
heightMM := self queryHeightMM.
blackpixel := self queryBlackPixel.
whitepixel := self queryWhitePixel.
monitorType := #unknown.
visualType := self queryDefaultVisualType.
hasColors := hasGreyscales := true.
(visualType == #StaticGray
or:[ visualType == #GrayScale]) ifTrue:[
hasColors := false.
monitorType := #monochrome.
].
ncells == 2 ifTrue:[
hasColors := hasGreyscales := false.
].
masks := self queryRGBMasks.
redMask := masks at:1.
greenMask := masks at:2.
blueMask := masks at:3.
bitsPerRGB := masks at:4.
visualType == #TrueColor ifTrue:[
redShift := redMask lowBit - 1.
greenShift := greenMask lowBit - 1.
blueShift := blueMask lowBit - 1.
bitsRed := redMask highBit - redMask lowBit + 1.
bitsGreen := greenMask highBit - greenMask lowBit + 1.
bitsBlue := blueMask highBit - blueMask lowBit + 1.
].
%{
Display *dpy;
int scr;
Visual *visual;
XVisualInfo viproto;
XVisualInfo *vip; /* retured info */
int maxRGBDepth;
int rgbRedMask, rgbGreenMask, rgbBlueMask;
int rgbVisualID;
int nvi, i;
char *type, *nm;
int dummy;
if (ISCONNECTED) {
dpy = myDpy;
/*
* look for RGB visual
*/
nvi = 0;
viproto.screen = scr;
vip = XGetVisualInfo (dpy, VisualScreenMask, &viproto, &nvi);
maxRGBDepth = 0;
for (i = 0; i < nvi; i++) {
switch (vip[i].class) {
case TrueColor:
if (vip[i].depth > maxRGBDepth) {
maxRGBDepth = vip[i].depth;
rgbRedMask = vip[i].red_mask;
rgbGreenMask = vip[i].green_mask;
rgbBlueMask = vip[i].blue_mask;
rgbVisualID = vip[i].visualid;
}
break;
}
}
if (vip) XFree ((char *) vip);
if (maxRGBDepth) {
__INST(rgbVisual) = __MKEXTERNALADDRESS(rgbVisualID); __STORESELF(rgbVisual);
}
}
%}.
!
initializeSpecialFlags
"perform additional special server implementation flags"
"/
"/ assume we have it ... (should check)
"/
hasSaveUnder := true.
ignoreBackingStore := false.
(self serverVendor = 'X11/NeWS') ifTrue:[
"/
"/ this is a kludge around a bug in the X11/NeWS server,
"/ which does not correctly handle saveUnder
"/
hasSaveUnder := false.
].
!
openConnectionTo:dpyName
"open a connection to some display;
return displayId if ok, nil of not ok"
%{
Display *dpy;
int i;
char *nm;
if (__isString(dpyName))
nm = (char *) __stringVal(dpyName);
else {
nm = NULL;
}
dpy = XOpenDisplay(nm);
if (dpy) {
static int firstCall = 1;
OBJ dpyID;
dpyID = __MKEXTERNALADDRESS(dpy);
if (firstCall) {
firstCall = 0;
XSetErrorHandler(__XErrorHandler__);
XSetIOErrorHandler(__XIOErrorHandler__);
}
RETURN (dpyID);
}
%}.
^ nil
!
reinitialize
virtualRootId := rootId := nil.
super reinitialize.
dispatchingExpose := nil
! !
!XWorkstation methodsFor:'keyboard mapping'!
altModifierMask
"return the mask (in motionEvents) for the alt-key modifier.
Notice: ST/X may use the left ALT key as CMD/Meta key,
therefore return a variable here, which can be changed during startup."
^ altModifierMask
"Created: 23.3.1996 / 12:43:22 / cg"
"Modified: 23.3.1996 / 12:44:56 / cg"
!
altModifierMask:aSmallInteger
"define which key takes the role of an alt-key.
By default, this is X's modifier1, which is the ALT key on
most keyboards. However, there may be exceptions to this,
and the setting can be changed with:
Display altModifierMask:(Display modifier2Mask)
Setting the mask to 0 disables the ALT key (in ST/X) altogether.
"
altModifierMask := aSmallInteger
!
ctrlModifierMask
"return the Xlib mask bit for the control modifier key"
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT(ControlMask));
%}
!
metaModifierMask
"return the mask (in motionEvents) for the meta-key modifier.
Notice: ST/X may use the left ALT key as CMD/Meta key,
therefore return a variable here, which can be changed during startup."
^ metaModifierMask
"Created: 23.3.1996 / 12:43:39 / cg"
"Modified: 23.3.1996 / 12:45:09 / cg"
!
metaModifierMask:aSmallInteger
"define which key takes the role of a meta key.
By default, this is X's modifier2, which is the 2nd ALT key on
most keyboards (if present at all).
However, there may be exceptions to this, and the setting can
be changed with:
Display metaModifierMask:(Display modifier1Mask)
Setting the mask to 0 disables the META key (in ST/X) altogether.
As reported, some Xservers place the Meta-key onto NumLock,
and having NumLock enabled makes ST/X think, that meta is pressed
all the time. On those, you should disable the meta key by setting
the mask to 0.
"
metaModifierMask := aSmallInteger
!
modifier1Mask
"return the Xlib mask bit for the 1st modifier key.
See comment in altModifierMask: / metaModifierMask: for what
this could be used."
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT(Mod1Mask));
%}
!
modifier2Mask
"return the Xlib mask bit for the 2nd modifier key.
See comment in altModifierMask: / metaModifierMask: for what
this could be used."
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT(Mod2Mask));
%}
!
modifier3Mask
"return the Xlib mask bit for the 3rd modifier key.
See comment in altModifierMask: / metaModifierMask: for what
this could be used."
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT(Mod3Mask));
%}
!
modifier4Mask
"return the Xlib mask bit for the 4th modifier key.
See comment in altModifierMask: / metaModifierMask: for what
this could be used."
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT(Mod4Mask));
%}
!
modifier5Mask
"return the Xlib mask bit for the 5th modifier key.
See comment in altModifierMask: / metaModifierMask: for what
this could be used."
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT(Mod5Mask));
%}
!
modifierMapping
"Get the Modifier Mapping.
We return an array of arrays of keycodes"
|modifierKeyMap maxKeyPerMod ret nextKey|
modifierKeyMap := self rawModifierMapping.
maxKeyPerMod := modifierKeyMap size // 8.
modifierKeyMap isNil ifTrue:[^ nil].
ret := Array new:8.
nextKey := 1.
1 to:8 do:[ :i |
(modifierKeyMap at:nextKey) ~= 0 ifTrue:[
|mod|
mod := OrderedCollection new:maxKeyPerMod.
modifierKeyMap from:nextKey to:(nextKey+maxKeyPerMod-1) do:[ :key |
key ~= 0 ifTrue:[
mod add:key
].
].
ret at:i put:mod.
].
nextKey := nextKey+maxKeyPerMod.
].
^ ret
"
Display modifierMapping
"
"
|mapping|
mapping := Display modifierMapping.
^ mapping collect:[:eachRow |
eachRow notNil ifTrue:[
eachRow collect:[ :key | Display stringFromKeycode:key ].
] ifFalse:[
nil
]
].
"
!
rawKeySymTranslation
"Get the raw keyboard mapping (maps some special X-keySyms to STX-internal names
and can also be used to untranslate a stupid x-mapping (as on hpux)."
^ rawKeySymTranslation
"
Display rawKeySymTranslation
"
!
rawModifierMapping
"Get the raw Modifier Mapping."
|modifierKeyMap maxKeyPerMod |
%{
XModifierKeymap *modmap;
OBJ __BYTEARRAY_UNINITIALIZED_NEW_INT();
if (ISCONNECTED) {
Display *dpy = myDpy;
if ((modmap = XGetModifierMapping(dpy)) != 0) {
maxKeyPerMod = __MKSMALLINT(modmap->max_keypermod);
modifierKeyMap = __BYTEARRAY_UNINITIALIZED_NEW_INT(modmap->max_keypermod * 8);
if (modifierKeyMap != nil) {
memcpy((char *)__ByteArrayInstPtr(modifierKeyMap)->ba_element,
(char *)modmap->modifiermap, modmap->max_keypermod * 8);
}
XFreeModifiermap(modmap);
}
}
%}.
^ modifierKeyMap
"
Display rawModifierMapping
"
!
shiftModifierMask
"return the Xlib mask bit for the shift modifier key"
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT(ShiftMask));
%}
!
stringFromKeycode:code
"Get a KeySymbol (a smalltalk symbol) from the keycode."
|str|
%{
KeySym keysym;
char *keystring;
if (ISCONNECTED
&& __isSmallInteger(code)) {
Display *dpy = myDpy;
if ((keysym = XKeycodeToKeysym(dpy, __intVal(code), 0)) != NoSymbol &&
(keystring = XKeysymToString(keysym)) != 0)
str = __MKSTRING(keystring);
}
%}.
^ str
"
Display stringFromKeycode:28
"
!
superModifierMask
"return the Xlib mask bit for the super modifier key"
^ self modifier4Mask
!
translateKey:untranslatedKey forView:aView
"Return the key translated via the translation table.
Here, we preTranslate the key into a common ST/X symbolic name,
which gets further processed in the superclasses translation method."
|key|
key := untranslatedKey.
(rawKeySymTranslation includesKey:key) ifTrue:[
key := rawKeySymTranslation at:key.
].
key isCharacter ifFalse:[
key := key asSymbol
].
^ super translateKey:key forView:aView
! !
!XWorkstation methodsFor:'misc'!
beep
"output an audible beep or bell"
UserPreferences current beepEnabled ifTrue:[
self beep:50
]
"Modified: / 3.12.1999 / 17:13:59 / ps"
!
beep:volumeInPercent
"output an audible beep"
<context: #return>
%{
int volume;
if (__isSmallInteger(volumeInPercent)
&& ISCONNECTED) {
/* stupid: X wants -100 .. 100 and calls this percent */
volume = __intVal(volumeInPercent) * 2 - 100;
if (volume < -100) volume = -100;
else if (volume > 100) volume = 100;
ENTER_XLIB();
XBell(myDpy, volume);
LEAVE_XLIB();
}
%}
!
buffered
"buffer drawing - do not send it immediately to the display.
This is the default anyway.
See #unBuffered for additional info."
<context: #return>
%{
if (ISCONNECTED) {
ENTER_XLIB();
XSynchronize(myDpy, 0);
LEAVE_XLIB();
}
%}
"
Display buffered
"
!
flush
"send all buffered drawing to the display.
This may be required to make certain, that all previous operations
are really sent to the display before continuing. For example,
after a cursor-change with a followup long computation.
(otherwise, the cursor change request may still be in the output buffer)
See also #sync, which even waits until the request has been processed."
<context: #return>
%{
if (ISCONNECTED) {
ENTER_XLIB();
XFlush(myDpy);
LEAVE_XLIB();
}
%}
!
flushDpsContext:aDPSContext
<context: #return>
%{
#ifdef DPS
if (ISCONNECTED
&& __isExternalAddress(aDPSContext)) {
ENTER_XLIB();
DPSFlushContext(__DPSContextVal(aDPSContext));
LEAVE_XLIB();
RETURN ( self );
}
#endif
%}.
self primitiveFailedOrClosedConnection
!
primSync
"send all buffered drawing to the display AND wait until the display
has finished drawing it.
This is almost never needed, except if you are about to read previously
drawn pixels back from the display screen, or you want to wait for a beep
to be finished. See also #flush."
<context: #return>
%{
if (ISCONNECTED) {
ENTER_XLIB();
XSync(myDpy, 0);
LEAVE_XLIB();
}
%}
!
refreshKeyboardMapping:eB
<context: #return>
%{
XMappingEvent *ev;
if (ISCONNECTED
&& __isByteArray(eB)) {
ev = (XMappingEvent *)(__ByteArrayInstPtr(eB)->ba_element);
ENTER_XLIB();
XRefreshKeyboardMapping(ev);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setInputFocusTo:aWindowId
"set the focus to the view as defined by aWindowId.
When released, return the focus to the root window"
"/ self setInputFocusTo:aWindowId revertTo:#parent
self setInputFocusTo:aWindowId revertTo:#root
!
setInputFocusTo:aWindowId revertTo:revertSymbol
"set the focus to the view as defined by aWindowId.
Passing nil set the focus to no window and lets the display discard all
input until a new focus is set.
RevertSymbol specifies what should happen if the view becomes invisible;
passing one of #parent, #root or nil specifies that the focus should be
given to the parent view, the root view or no view."
<context: #return>
%{
int arg;
Window focusWindow;
if (ISCONNECTED) {
if (__isExternalAddress(aWindowId)) {
focusWindow = __WindowVal(aWindowId);
} else {
focusWindow = None;
}
if (revertSymbol == @symbol(parent))
arg = RevertToParent;
else if (revertSymbol == @symbol(root))
arg = RevertToPointerRoot;
else
arg = RevertToNone;
ENTER_XLIB();
XSetInputFocus(myDpy, focusWindow, arg, CurrentTime);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
sync
"send all buffered drawing to the display AND wait until the display
has finished drawing it.
This is almost never needed, except if you are about to read previously
drawn pixels back from the display screen, or you want to wait for a beep
to be finished. See also #flush."
self primSync.
self dispatchPendingEvents.
!
unBuffered
"make all drawing be sent immediately to the display.
This makes all graphics synchronous and turns off any buffering
(i.e. each individual draw-request is sent immediately without
packing multiple requests into a larger message buffer).
Be prepared, that this slows down graphics considerably.
However, it allows display errors to be handled immediately and
may be useful if you get Xdisplay errors and want to find the request
which was responsible for it. See also #buffered."
<context: #return>
%{
if (ISCONNECTED) {
ENTER_XLIB();
XSynchronize(myDpy, 1);
LEAVE_XLIB();
}
%}
"
Display unBuffered
"
! !
!XWorkstation methodsFor:'pointer stuff'!
anyButtonStateMask
"return an integer for masking out any button from a
buttonStates value."
"/ should use ``Display buttonXMotionMask bitOr:....''
^ 256 + 512 + 1024
"Modified: 23.3.1996 / 12:41:33 / cg"
"Created: 23.3.1996 / 12:46:35 / cg"
!
buttonStates
"return an integer representing the state of the pointer buttons;
a one-bit in positions 0.. represent a pressed button.
See the button1Mask/button2Mask/button3Mask,
shiftMask/controlMask and modifierMask methods for the meaning of the bits."
<context: #return>
%{
Window w;
int screen = __intVal(__INST(screen));
Window rootRet, childRet;
int rootX, rootY, winX, winY;
unsigned int mask;
if (ISCONNECTED) {
Display *dpy = myDpy;
#ifdef VIRTUAL_ROOT
w = getRootWindow(dpy, screen);
#else
w = RootWindow(dpy, screen);
#endif
if (w) {
ENTER_XLIB();
XQueryPointer(dpy, w, &rootRet, &childRet,
&rootX, &rootY,
&winX, &winY,
&mask);
LEAVE_XLIB();
RETURN (__MKSMALLINT(mask));
}
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
"
Display buttonStates
"
"is the control-key pressed ?
Display buttonStates bitTest:(Display controlMask)
"
"is the alt/meta-key pressed ?
Display buttonStates bitTest:(Display altModifierMask)
Display buttonStates bitTest:(Display metaModifierMask)
"
!
leftButtonStateMask
"return an integer for masking out the left button from a
buttonStates value"
"/ should use ``Display button1MotionMask''
^ 256
"Modified: 23.3.1996 / 12:41:33 / cg"
!
middleButtonStateMask
"return an integer for masking out the middle button from a
buttonStates value"
"/ should use ``Display button2MotionMask''
^ 512
"Modified: 23.3.1996 / 12:41:43 / cg"
!
pointerPosition
"return the current pointer position in root-window coordinates"
<context: #return>
|xpos ypos|
%{
Window w;
int screen = __intVal(__INST(screen));
Window rootRet, childRet;
int rootX, rootY, winX, winY;
unsigned int mask;
if (ISCONNECTED) {
Display *dpy = myDpy;
#ifdef VIRTUAL_ROOT
w = getRootWindow(dpy, screen);
#else
w = RootWindow(dpy, screen);
#endif
ENTER_XLIB();
XQueryPointer(dpy, w, &rootRet, &childRet,
&rootX, &rootY,
&winX, &winY,
&mask);
LEAVE_XLIB();
xpos = __MKSMALLINT(rootX);
ypos = __MKSMALLINT(rootY);
}
%}.
xpos isNil ifTrue:[
self primitiveFailedOrClosedConnection.
^ nil
].
^ xpos @ ypos
!
rightButtonStateMask
"return an integer for masking out the right button from a
buttonStates value"
"/ should use ``Display button3MotionMask''
^ 1024
"Modified: 23.3.1996 / 12:41:52 / cg"
!
rootPositionOfLastEvent
"return the position in root-window coordinates
of the last button, key or pointer event"
^ eventRootX @ eventRootY
!
setPointerPosition:newPosition in:aWindowId
"change the pointer position to a new position relative to the
given windows origin (which may be the rootWindow).
Be careful with this - its usually not very ergonomically
to change the mousePointer position.
This interface is provided for special applications (presentation
playback) and should not be used in normal applications."
<context: #return>
|xpos ypos|
xpos := newPosition x.
ypos := newPosition y.
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)
&& __bothSmallInteger(xpos, ypos)) {
Display *dpy = myDpy;
Window w = __WindowVal(aWindowId);
ENTER_XLIB();
XWarpPointer(dpy,
None, /* src window */
w, /* dst window */
0, /* src_x */
0, /* src_y */
0, /* src_w */
0, /* src_h */
__intVal(xpos), /* dst_x */
__intVal(ypos) /* dst_y */
);
LEAVE_XLIB();
}
%}.
^ self
"
Display setPointerPosition:1000@1000
"
! !
!XWorkstation methodsFor:'properties'!
getObjectProperty:propertyID from:aWindowID
"get an object property from the server; return object or nil"
self getProperty:propertyID from:aWindowID into:[:type :value |
type == stringAtom ifTrue:[
^ value
].
(value isMemberOf:ByteArray) ifTrue:[
^ (Object readBinaryFrom:(ReadStream on:value) onError:[nil])
]
].
^ nil
"Modified: 6.4.1997 / 13:27:07 / cg"
!
getProperty:propertySymbolOrID from:aWindowID into:aTwoArgBlock
"get a property, evaluate aTwoArgBlock with typeID and value"
<context: #return>
|val typeID cls propertyID|
propertySymbolOrID isString ifTrue:[
propertyID := self atomIDOf:propertySymbolOrID create:false.
] ifFalse:[
propertyID := propertySymbolOrID.
].
cls := ByteArray.
%{
Window window;
Atom property;
char *cp, *cp2;
Atom actual_type;
int actual_format,i;
unsigned long nitems, bytes_after, nread;
unsigned char *data;
int ok = 1;
# define PROP_SIZE 2048
if (ISCONNECTED) {
Display *dpy = myDpy;
if (__isAtomID(propertyID)) {
property = __AtomVal(propertyID);
if (__isExternalAddress(aWindowID)) {
window = __WindowVal(aWindowID);
} else {
window = DefaultRootWindow(dpy);
}
nread = 0;
cp = 0;
/*
fprintf(stderr, "getProperty: ");
*/
do {
int retVal;
ENTER_XLIB();
retVal = XGetWindowProperty(dpy, window, property, nread/4, PROP_SIZE, False,
AnyPropertyType, &actual_type, &actual_format,
&nitems, &bytes_after, (unsigned char **)&data);
LEAVE_XLIB();
if (retVal != Success) {
ok = 0;
break;
}
typeID = __MKATOMOBJ(actual_type);
if (! cp) {
cp = cp2 = (char *)malloc(nitems+1);
} else {
cp = (char *)realloc(cp, nread + nitems + 1);
cp2 = cp + nread;
}
if (! cp) {
XFree(data);
goto fail;
}
nread += nitems;
bcopy(data, cp2, nitems);
XFree(data);
/*
fprintf(stderr, "<nitems:%d bytes_after:%d>", nitems, bytes_after);
*/
} while (bytes_after > 0);
/*
fprintf(stderr, "\n");
*/
if (ok) {
if (actual_type == XA_STRING) {
cp[nread] = '\0';
val = __MKSTRING_L(cp, nread);
} else {
val = __STX___new(nread + OHDR_SIZE);
val->o_class = cls;
bcopy(cp, __ByteArrayInstPtr(val)->ba_element, nread);
}
}
if (cp)
free(cp);
}
}
fail: ;
%}.
typeID isNil ifTrue:[
^ false
].
aTwoArgBlock value:typeID value:val.
^ true
!
getTextProperty:propertyID from:aWindowID
"get a text property; return string or nil"
|stringClass|
self getProperty:propertyID from:aWindowID into:[:type :value |
type == stringAtom ifTrue:[
clipBoardEncoding notNil ifTrue:[
stringClass := (CharacterArray classForEncoding:clipBoardEncoding).
stringClass ~~ String ifTrue:[
^ stringClass fromBytes:(value asByteArray)
].
^ value decodeFrom:clipBoardEncoding
].
^ value
]
].
^ nil
"Modified: 30.6.1997 / 20:54:59 / cg"
!
setLengthProperty:propertyID value:aNumber for:aWindowID
"set a size property"
^ self
setProperty:propertyID
type:(self atomIDOf:#LENGTH)
value:aNumber
for:aWindowID
"Modified: 6.4.1997 / 13:27:26 / cg"
!
setObjectProperty:propertyID value:anObject for:aWindowID
"set a property to a smalltalk object in the XServer.
Non-strings can only be retrieved by another ST/X smalltalk"
|s|
(anObject isMemberOf:String) ifTrue:[
^ self setTextProperty:propertyID value:anObject for:aWindowID
].
s := WriteStream on:(ByteArray new:200).
anObject storeBinaryOn:s.
^ self
setProperty:propertyID
type:(self atomIDOf:#'ST_OBJECT')
value:(s contents)
for:aWindowID
"Modified: / 17.6.1998 / 17:23:49 / cg"
!
setProperty:propertyID type:typeID value:anObject for:aWindowID
"set a property in the XServer"
<context: #return>
%{ /* UNLIMITEDSTACK */
if (__isAtomID(propertyID)
&& __isAtomID(typeID)
&& ISCONNECTED
&& (__isString(anObject)
|| __isSmallInteger(anObject)
|| __isSymbol(anObject)
|| __isByteArray(anObject)
|| __isWords(anObject))) {
Display *dpy = myDpy;
Atom prop, type;
Window window;
unsigned INT value;
prop = __AtomVal(propertyID);
type = __AtomVal(typeID);
if (__isExternalAddress(aWindowID)) {
window = __WindowVal(aWindowID);
} else if (__isSmallInteger(aWindowID)) {
window = (Window)__smallIntegerVal(aWindowID);
} else if (aWindowID == nil) {
window = DefaultRootWindow(dpy);
} else {
window = (Window)__unsignedLongIntVal(aWindowID);
}
ENTER_XLIB();
if (__isSmallInteger(anObject)) {
value = __intVal(anObject);
XChangeProperty(dpy, window, prop, type, 32,
PropModeReplace,
(unsigned char *)(&value), sizeof(unsigned int));
} else {
if (__isByteArray(anObject)) {
XChangeProperty(dpy, window, prop, type, 8,
PropModeReplace,
__ByteArrayInstPtr(anObject)->ba_element,
__byteArraySize(anObject));
} else {
/* string or symbol or wordArray-like (16bit-string) object */
if (__isWords(__qClass(anObject))) {
XChangeProperty(dpy, window, prop, type, 16,
PropModeReplace,
__stringVal(anObject),
__wordArraySize(anObject));
} else {
/* must be string or symbol */
XChangeProperty(dpy, window, prop, type, 8,
PropModeReplace,
__stringVal(anObject),
__stringSize(anObject));
}
}
}
LEAVE_XLIB();
DPRINTF(("changeProp win=%x prop=%x type=%x\n", window, prop, type));
RETURN (true);
}
%}.
^ false
!
setTextProperty:propertyID value:aString for:aWindowID
"set a property to a stringValue in the XServer"
^ self
setProperty:propertyID
type:(self atomIDOf:#STRING)
value:aString
for:aWindowID
"Modified: 6.4.1997 / 13:26:32 / cg"
! !
!XWorkstation methodsFor:'resources'!
atomIDOf:aStringOrSymbol
"return an X11 atoms ID; dont create if not already present.
This is highly X specific and only for local use (with selections).
The default is to create the atom, if it does not exist, in order to
speed up future lookups"
^ self atomIDOf:aStringOrSymbol create:true
"
Display atomIDOf:#'FACE_NAME'
Display atomIDOf:#'FULL_NAME'
Display atomIDOf:#DndProtocol
Display atomIDOf:#DndSelection
"
"Modified: 4.4.1997 / 13:38:48 / cg"
!
atomIDOf:aStringOrSymbol create:create
"return an Atoms ID; if create is true, create it if not already present.
This is highly X specific and only for local use (with selections)."
|atomSymbol atom|
atomSymbol := aStringOrSymbol asSymbol.
(atoms notNil and:[(atom := atoms at:atomSymbol ifAbsent:nil) notNil]) ifTrue:[
^ atom.
].
atom := self primAtomIDOf:atomSymbol create:create.
atom notNil ifTrue:[
atoms isNil ifTrue:[
atoms := IdentityDictionary new.
].
atoms at:atomSymbol put:atom.
].
^ atom
"
Display atomIDOf:#'VT_SELECTION' create:false
Display atomIDOf:#'CUT_BUFFER0' create:false
Display atomIDOf:'STRING' create:false
Display atomIDOf:'PRIMARY' create:false
"
!
atomName:anAtomID
"given an AtomID, return its name.
This is highly X specific and only for local use (with selections)."
%{ /* NOCONTEXT */
OBJ str;
char *name;
if (ISCONNECTED && __isAtomID(anAtomID)) {
name = XGetAtomName(myDpy, __AtomVal(anAtomID));
if (name == 0) {
RETURN (nil);
}
str = __MKSTRING(name);
XFree(name);
RETURN ( str );
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
"
Display atomName:1 'PRIMARY'
Display atomName:130 '_DEC_DEVICE_FONTNAMES'
Display atomName:132 'FONTNAME_REGISTRY'
Display atomName:135 'FOUNDRY'
Display atomName:150 'CHARSET_REGISTRY'
Display atomName:151 'ISO8859'
Display atomName:152 'CHARSET_ENCODING'
Display atomName:154
"
!
getResource:name class:cls
"access the displays resource database for a default value
of name in a resource class.
This is highly X specific and currently not used.
Notice:
we do not plan to use X's resources for ST/X's defaults,
styles or resources. This would make porting of applications
to different platforms much more difficult (Windows has no resource
database). If you stay within ST/X's resource files, these can be
easily transported to other platforms.
This method is provided for special applications which want to access
existing X resources and are not planned to be ever ported to other
platforms."
%{
char *rslt;
if (ISCONNECTED
&& __isNonNilObject(name)
&& (__qIsString(name) || __qIsSymbol(name))
&& __isNonNilObject(cls)
&& (__qIsString(cls) || __qIsSymbol(cls))) {
rslt = XGetDefault(myDpy, (char *) __stringVal(cls),
(char *) __stringVal(name));
RETURN (rslt ? __MKSTRING(rslt) : nil );
}
%}.
self primitiveFailedOrClosedConnection.
^ nil.
"if your ~/.Xdefaults contains an entry such as:
OpenWindows.Beep: notices
the following returns 'notices'.
Display getResource:'Beep' class:'OpenWindows'
if your ~/.Xdefaults contains an entry such as:
*.beNiceToColormap: false
the following return 'false'.
Display getResource:'beNiceToColormap' class:'any'
Display getResource:'beNiceToColormap' class:''
"
!
primAtomIDOf:aStringOrSymbol create:create
"return an Atoms ID; if create is true, create it if not already present.
This is highly X specific and only for local use (with selections)."
%{ /* NOCONTEXT */
Atom prop;
if (ISCONNECTED
&& __isNonNilObject(aStringOrSymbol)
&& (__qIsString(aStringOrSymbol) || __qIsSymbol(aStringOrSymbol))) {
prop = XInternAtom(myDpy, __stringVal(aStringOrSymbol),
(create == true) ? False : True);
if (prop == None) {
RETURN (nil);
}
RETURN ( __MKATOMOBJ(prop) );
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
"
Display primAtomIDOf:'VT_SELECTION' create:false
Display primAtomIDOf:'CUT_BUFFER0' create:false
Display primAtomIDOf:'STRING' create:false
Display primAtomIDOf:'PRIMARY' create:false
"
! !
!XWorkstation methodsFor:'retrieving pixels'!
getBitsFromId:aDrawableId x:srcx y:srcy width:w height:h into:imageBits
"get bits from a drawable into the imageBits. The storage for the bits
must be big enough for the data to fit. If ok, returns an array with some
info and the bits in imageBits. The info contains the depth, bitOrder and
number of bytes per scanline. The number of bytes per scanline is not known
in advance, since the X-server is free to return whatever it thinks is a good padding."
|rawInfo info|
((w <= 0) or:[h <= 0]) ifTrue:[
self primitiveFailed.
^ nil
].
rawInfo := Array new:8.
"1 -> bit order"
"2 -> depth"
"3 -> bytes_per_line"
"4 -> byte_order"
"5 -> format"
"6 -> bitmap_unit"
"7 -> bitmap_pad"
"8 -> bits_per_pixel"
"/ had to extract the getPixel call into a separate method, to specify
"/ unlimitedStack (some implementations use alloca and require huge amounts
"/ of temporary stack space
(self primGetBitsFrom:aDrawableId x:srcx y:srcy width:w height:h into:imageBits infoInto:rawInfo) ifTrue:[
info := IdentityDictionary new.
info at:#bitOrder put:(rawInfo at:1).
info at:#depth put:(rawInfo at:2).
info at:#bytesPerLine put:(rawInfo at:3).
info at:#byteOrder put:(rawInfo at:4).
info at:#format put:(rawInfo at:5).
info at:#bitmapUnit put:(rawInfo at:6).
info at:#bitmapPad put:(rawInfo at:7).
info at:#bitsPerPixel put:(rawInfo at:8).
^ info
].
"
some error occured - either args are not smallintegers, imageBits is not a ByteArray
or is too small to hold the bits
"
self primitiveFailedOrClosedConnection.
^ nil
!
getPixelX:x y:y from:aDrawableId with:dummyGCId
"return the pixel value at x/y; coordinates start at 0/0 for the upper left.
Nil is returned for invalid coordinates or if any other problem arises."
<context: #return>
%{ /* UNLIMITEDSTACK */
Window win;
XImage *img;
int ret;
int xpos, ypos;
if (ISCONNECTED
&& __isExternalAddress(aDrawableId) && __bothSmallInteger(x, y)) {
win = __WindowVal(aDrawableId);
xpos = __intVal(x);
ypos = __intVal(y);
if ((xpos < 0) || (ypos < 0)) {
RETURN ( __MKSMALLINT(0) );
}
ENTER_XLIB();
img = XGetImage(myDpy, win, xpos, ypos, 1, 1, (unsigned)~0, ZPixmap);
LEAVE_XLIB();
if (img != 0) {
ret = XGetPixel(img, 0, 0);
XDestroyImage(img);
RETURN ( __MKSMALLINT(ret) );
}
}
%}.
^ nil
!
primGetBitsFrom:aDrawableId x:srcx y:srcy width:w height:h into:imageBits infoInto:info
"since XGetImage may allocate huge amount of stack space
(some implementations use alloca), this must run with unlimited stack."
<context: #return>
%{ /* UNLIMITEDSTACK */
Window win;
XImage *image = (XImage *)0;
int pad, bytes_per_line, numBytes;
if (ISCONNECTED
&& __isExternalAddress(aDrawableId)
&& __bothSmallInteger(srcx, srcy)
&& __bothSmallInteger(w, h)
&& __isArray(info)
&& __isByteArray(imageBits)) {
Display *dpy = myDpy;
win = __WindowVal(aDrawableId);
ENTER_XLIB();
image = XGetImage(dpy, win, __intVal(srcx), __intVal(srcy),
__intVal(w), __intVal(h),
(unsigned)AllPlanes, ZPixmap);
LEAVE_XLIB();
if (! image) {
RETURN ( false );
}
pad = image->bitmap_pad;
#ifdef SUPERDEBUG
printf("pad:%d depth:%d\n", image->bitmap_pad, image->depth);
#endif
switch (image->depth) {
case 1:
case 2:
case 4:
case 8:
case 16:
case 24:
case 32:
numBytes = image->bytes_per_line * image->height;
break;
default:
/* unsupported depth ? */
printf("possibly unsupported depth:%d in primGetBits\n", image->depth);
numBytes = image->bytes_per_line * image->height;
break;
}
#ifdef SUPERDEBUG
printf("bytes need:%d bytes given:%d\n", numBytes, __byteArraySize(imageBits));
#endif
if (numBytes > __byteArraySize(imageBits)) {
/* imageBits too small */
fprintf(stderr, "Workstation [warning]: byteArray too small in primGetBits\n");
fprintf(stderr, " bytes need:%d given:%d\n", numBytes, __byteArraySize(imageBits));
fprintf(stderr, " pad:%d depth:%d imgBytesPerLine:%d\n",
image->bitmap_pad, image->depth, image->bytes_per_line);
goto fail;
}
if (image->bitmap_bit_order == MSBFirst)
__ArrayInstPtr(info)->a_element[0] = @symbol(msbFirst);
else
__ArrayInstPtr(info)->a_element[0] = @symbol(lsbFirst);
__ArrayInstPtr(info)->a_element[1] = __MKSMALLINT(image->depth);
__ArrayInstPtr(info)->a_element[2] = __MKSMALLINT(image->bytes_per_line);
if (image->byte_order == MSBFirst)
__ArrayInstPtr(info)->a_element[3] = @symbol(msbFirst);
else
__ArrayInstPtr(info)->a_element[3] = @symbol(lsbFirst);
if (image->format == XYBitmap)
__ArrayInstPtr(info)->a_element[4] = @symbol(XYBitmap);
else if (image->format == XYPixmap)
__ArrayInstPtr(info)->a_element[4] = @symbol(XYPixmap);
else if (image->format == ZPixmap)
__ArrayInstPtr(info)->a_element[4] = @symbol(ZPixmap);
__ArrayInstPtr(info)->a_element[5] = __MKSMALLINT(image->bitmap_unit);
__ArrayInstPtr(info)->a_element[6] = __MKSMALLINT(image->bitmap_pad);
__ArrayInstPtr(info)->a_element[7] = __MKSMALLINT(image->bits_per_pixel);
bcopy(image->data, __ByteArrayInstPtr(imageBits)->ba_element, numBytes);
XDestroyImage(image);
RETURN ( true );
}
fail:
if (image) {
XDestroyImage(image);
}
%}.
^ false
! !
!XWorkstation methodsFor:'selections'!
getSelectionFor:drawableId
"get the object selection - either immediate, or asynchronous.
Returns nil, if async request is on its way"
(self getSelectionOwnerOf:primaryAtom) isNil ifTrue:[
"no primary selection - use cut buffer"
^ self getObjectProperty:cutBuffer0Atom from:nil.
].
self requestSelection:primaryAtom
property:(self atomIDOf:#'ST_SELECTION')
type:(self atomIDOf:#'ST_OBJECT')
for:drawableId.
^ nil
"Modified: / 17.6.1998 / 17:11:15 / cg"
!
getSelectionOwnerOf:selectionAtomSymbolOrID
"get the owner of a selection"
|selectionAtomID|
selectionAtomSymbolOrID isString ifTrue:[
selectionAtomID := self atomIDOf:selectionAtomSymbolOrID create:false.
] ifFalse:[
selectionAtomID := selectionAtomSymbolOrID.
].
%{
Atom selection;
Window window;
if (__isAtomID(selectionAtomID)
&& ISCONNECTED) {
Display *dpy = myDpy;
window = XGetSelectionOwner(dpy, __AtomVal(selectionAtomID));
RETURN ((window == None) ? nil : __MKEXTERNALADDRESS(window));
}
%}.
self primitiveFailedOrClosedConnection.
^ nil
!
getTextSelectionFor:drawableId
"get the text selection - either immediate, or asynchronous.
Returns nil, if async request is on its way"
(self getSelectionOwnerOf:primaryAtom) isNil ifTrue:[
"no primary selection - use cut buffer"
^ self getTextProperty:cutBuffer0Atom from:nil.
].
self requestSelection:primaryAtom
property:(self atomIDOf:#'VT_SELECTION')
type:stringAtom
for:drawableId.
^ nil
"Modified: / 17.6.1998 / 17:12:05 / cg"
!
requestSelection:selectionID property:propertyID type:typeID for:aWindowId
"ask the server to send us the selection - the view with id aWindowID
will later receive a SelectionNotify event for it (once the Xserver replies
with the selections value)."
%{ /* NOCONTEXT */
Atom sel_prop;
char *cp;
if (__isExternalAddress(aWindowId)
&& ISCONNECTED
&& __isSmallInteger(typeID)
&& __isAtomID(selectionID)) {
Display *dpy = myDpy;
if (XGetSelectionOwner(dpy, __AtomVal(selectionID)) == None) {
/*
* no owner of primary selection
*/
RETURN (false);
}
/*
* PRIMARY selection
*/
XConvertSelection(dpy, __AtomVal(selectionID), __AtomVal(typeID),
__AtomVal(propertyID), __WindowVal(aWindowId), CurrentTime);
RETURN (true);
}
%}.
self primitiveFailedOrClosedConnection.
^ false
"
Display requestSelection:(Display atomIDOf:'PRIMARY')
property:(Display atomIDOf:'VT_SELECTION')
for:0
"
!
sendSelection:something selection:selectionID property:propertyID target:targetID time:t from:windowID to:requestorID
"send aString back from a SelectionRequest"
self
setProperty:propertyID
type:targetID
value:something
for:requestorID.
self
sendSelectionNotifySelection:selectionID
property:propertyID
target:targetID
time:t
from:windowID
to:requestorID.
"Modified: / 17.6.1998 / 17:03:20 / cg"
"Created: / 17.6.1998 / 19:44:03 / cg"
!
sendSelectionNotifySelection:selectionID property:propertyID target:targetID time:t from:windowID to:requestorID
"send a selectionNotify back from a SelectionRequest"
<context: #return>
%{
if (__isAtomID(propertyID)
&& ISCONNECTED
&& __isAtomID(targetID)
&& __isAtomID(selectionID)) {
Display *dpy = myDpy;
XEvent ev;
Window requestor, originator;
Atom property = __AtomVal(propertyID);
Atom target = __AtomVal(targetID);
Atom selection = __AtomVal(selectionID);
Status result;
if (__isExternalAddress(requestorID)) {
requestor = __WindowVal(requestorID);
} else if (__isSmallInteger(requestorID)) {
requestor = (Window)__smallIntegerVal(requestorID);
} else if (requestorID == nil) {
requestor = DefaultRootWindow(dpy);
} else {
requestor = (Window)__unsignedLongIntVal(requestorID);
}
if (__isExternalAddress(windowID)) {
originator = __WindowVal(windowID);
} else if (__isSmallInteger(windowID)) {
originator = (Window)__smallIntegerVal(windowID);
} else if (windowID == nil) {
originator = DefaultRootWindow(dpy);
} else {
originator = (Window)__unsignedLongIntVal(windowID);
}
ev.xselection.type = SelectionNotify;
ev.xselection.display = dpy;
ev.xselection.selection = selection;
ev.xselection.target = target;
ev.xselection.requestor = originator;
if (__isExternalAddress(t)) {
ev.xselection.time = (INT)(__externalAddressVal(t));
} else if (__isSmallInteger(t)) {
ev.xselection.time = __smallIntegerVal(t);
} else if (t == nil) {
ev.xselection.time = CurrentTime;
} else {
ev.xselection.time = (INT)__unsignedLongIntVal(t);
}
#if 0
printf("ev.xselection.selection: %x\n", ev.xselection.selection);
printf("ev.xselection.target: %x\n", ev.xselection.target);
printf("ev.xselection.requestor: %x\n", ev.xselection.requestor);
printf("ev.xselection.time: %x\n", ev.xselection.time);
printf("requestor: %x\n", requestor);
#endif
if (property == None)
ev.xselection.property = target;
else
ev.xselection.property = property;
DPRINTF(("sending SelectionNotify sel=%x prop=%x target=%x requestor=%x to %x\n",
ev.xselection.selection,
ev.xselection.property,
ev.xselection.target,
ev.xselection.requestor,
requestor));
ENTER_XLIB();
result = XSendEvent(dpy, requestor, False, 0 , &ev);
LEAVE_XLIB();
if ((result == BadValue) || (result == BadWindow)) {
DPRINTF(("bad status\n"));
RETURN (false);
}
ENTER_XLIB();
XFlush(dpy);
LEAVE_XLIB();
RETURN (true)
}
%}.
self primitiveFailedOrClosedConnection.
^ false
"Modified: / 17.6.1998 / 20:23:20 / cg"
!
setSelection:anObject owner:aWindowId
"set the object selection, and make aWindowId be the owner.
This can be used by other Smalltalk(X) applications only."
(self setSelectionOwner:aWindowId of:primaryAtom) ifFalse:[
^ false
].
"/ ^ self setObjectProperty:cutBuffer0Atom value:anObject for:nil
^ true
!
setSelectionOwner:aWindowId of:selectionAtomSymbolOrID
"set the owner of a selection; return false if failed"
<context: #return>
|selectionAtomID|
selectionAtomSymbolOrID isString ifTrue:[
selectionAtomID := self atomIDOf:selectionAtomSymbolOrID create:false.
] ifFalse:[
selectionAtomID := selectionAtomSymbolOrID.
].
%{
Window win;
if (__isExternalAddress(aWindowId)
&& __isAtomID(selectionAtomID)
&& ISCONNECTED) {
Display *dpy = myDpy;
Window owner;
win = __WindowVal(aWindowId);
DPRINTF(("setOwner prop=%x win=%x\n", __AtomVal(selectionAtomID), win));
ENTER_XLIB();
XSetSelectionOwner(dpy, __AtomVal(selectionAtomID), win, CurrentTime);
owner = XGetSelectionOwner(dpy, __AtomVal(selectionAtomID));
LEAVE_XLIB();
if (owner != win) {
RETURN (false);
}
RETURN (true);
}
%}.
self primitiveFailedOrClosedConnection.
^ false
!
setTextSelection:aString owner:aWindowId
"set the text selection, and make aWindowId be the owner.
This can be used by any other X application."
(self setSelectionOwner:aWindowId of:primaryAtom) ifFalse:[
'XWorkstation [warning]: selection ownerchange failed' errorPrintCR.
].
^ self setTextProperty:cutBuffer0Atom value:aString for:rootId.
"Modified: / 17.6.1998 / 19:48:54 / cg"
! !
!XWorkstation methodsFor:'window stuff'!
clearRectangleX:x y:y width:width height:height in:aWindowId
"clear a rectangular area to viewbackground"
<context: #return>
%{
int w, h;
if (ISCONNECTED) {
if (__isExternalAddress(aWindowId)
&& __bothSmallInteger(x, y)
&& __bothSmallInteger(width, height)) {
w = __intVal(width);
h = __intVal(height);
/*
* need this check here: some servers simply dump core with bad args
*/
if ((w >= 0) && (h >= 0)) {
ENTER_XLIB();
XClearArea(myDpy, __WindowVal(aWindowId), __intVal(x), __intVal(y), w, h, 0);
LEAVE_XLIB();
}
RETURN ( self );
}
}
%}.
self primitiveFailedOrClosedConnection.
!
clearWindow:aWindowId
"clear a window to viewbackground"
<context: #return>
%{
if (ISCONNECTED) {
if (__isExternalAddress(aWindowId)) {
ENTER_XLIB();
XClearWindow(myDpy, __WindowVal(aWindowId));
LEAVE_XLIB();
RETURN ( self );
}
}
%}.
self primitiveFailedOrClosedConnection
!
configureWindow:aWindowId sibling:siblingId stackMode:modeSymbol
"configure stacking operation of aWindowId w.r.t siblingId"
<context: #return>
%{
XWindowChanges chg;
int mask = CWSibling | CWStackMode;
if (ISCONNECTED) {
if (__isExternalAddress(aWindowId)
&& __isExternalAddress(siblingId)) {
if (modeSymbol == @symbol(above)) {
chg.stack_mode = Above;
} else if (modeSymbol == @symbol(below)) {
chg.stack_mode = Below;
} else if (modeSymbol == @symbol(topIf)) {
chg.stack_mode = TopIf;
} else if (modeSymbol == @symbol(bottomIf)) {
chg.stack_mode = BottomIf;
} else if (modeSymbol == @symbol(opposite)) {
chg.stack_mode = Opposite;
} else {
mask = CWSibling;
}
chg.sibling = __WindowVal(siblingId);
ENTER_XLIB();
XConfigureWindow(myDpy, __WindowVal(aWindowId),
mask, &chg);
LEAVE_XLIB();
RETURN ( self );
}
}
bad: ;
%}.
self primitiveFailedOrClosedConnection
!
isValidWindowId:aWindowId
"return true, if the given window ID is (still) valid.
Especially useful, if the passed windowID is
an alien (external) windows id."
|ret|
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
char *name = NULL;
Status ok;
Window root, parent, *children = NULL;
int nChildren;
/* ENTER_XLIB(); */
ok = XQueryTree(myDpy, __WindowVal(aWindowId),
&root, &parent, &children, &nChildren);
if (children) {
XFree(children);
}
/* LEAVE_XLIB(); */
if (ok) {
RETURN (true);
}
RETURN (false);
}
%}.
self primitiveFailedOrClosedConnection.
^ false
"
|v aWindowId ok|
v := StandardSystemView new.
v label:'hello'.
v openAndWait.
aWindowId := v id.
ok := Display isValidWindowId:aWindowId.
Transcript showCR:'ok is: ' , ok printString.
Delay waitForSeconds:1.
v destroy.
ok := Display isValidWindowId:aWindowId.
Transcript showCR:'ok is: ' , ok printString.
"
!
lowerWindow:aWindowId
"bring a window to back"
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
ENTER_XLIB();
XLowerWindow(myDpy, __WindowVal(aWindowId));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
mapView:aView id:aWindowId iconified:aBoolean atX:xPos y:yPos
width:w height:h minExtent:minExt maxExtent:maxExt
<context: #return>
"make a window visible - either as icon or as a real view
in addition, allow change of extend, position, minExtend and maxExtent.
Needed for restart, to allow recreating a view as iconified,
and to collaps/expand windows."
|wicon wiconId wiconView wiconViewId wlabel minW minH maxW maxH|
aBoolean ifTrue:[
wicon := aView icon.
wicon notNil ifTrue:[
wiconId := wicon id
].
wiconView := aView iconView.
wiconView notNil ifTrue:[
wiconViewId := wiconView id
].
wlabel := aView label.
].
minExt notNil ifTrue:[
minW := minExt x.
minH := minExt y.
].
maxExt notNil ifTrue:[
maxW := maxExt x.
maxH := maxExt y.
].
%{
XWMHints wmhints;
XSizeHints szhints;
Window win;
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
Display *dpy = myDpy;
win = __WindowVal(aWindowId);
szhints.flags = 0;
if (__bothSmallInteger(xPos, yPos)) {
szhints.x = __intVal(xPos);
szhints.y = __intVal(yPos);
szhints.flags |= USPosition;
}
if (__bothSmallInteger(w, h)) {
szhints.width = __intVal(w);
szhints.height = __intVal(h);
szhints.flags |= USSize;
}
if (__bothSmallInteger(minW, minH)) {
szhints.flags |= PMinSize;
szhints.min_width = __intVal(minW);
szhints.min_height = __intVal(minH);
}
if (__bothSmallInteger(maxW, maxH)) {
szhints.flags |= PMaxSize;
szhints.max_width = __intVal(maxW);
szhints.max_height = __intVal(maxH);
}
if (aBoolean == true) {
char *windowName;
Pixmap iconBitmap = (Pixmap)0;
Window iconWindow;
if (__isExternalAddress(wiconId))
iconBitmap = __PixmapVal(wiconId);
else
iconBitmap = (Pixmap)0;
if (__isExternalAddress(wiconViewId))
iconWindow = __WindowVal(wiconViewId);
else
iconWindow = (Window)0;
if (__isString(wlabel) || __isSymbol(wlabel))
windowName = (char *) __stringVal(wlabel);
else
windowName = "";
if (iconBitmap || windowName) {
ENTER_XLIB();
XSetStandardProperties(dpy, win,
windowName, windowName,
iconBitmap,
0, 0, &szhints);
LEAVE_XLIB();
}
wmhints.flags = 0;
if (iconBitmap) {
wmhints.flags |= IconPixmapHint;
wmhints.icon_pixmap = iconBitmap;
}
if (iconWindow) {
wmhints.flags |= IconWindowHint;
wmhints.icon_window = iconWindow;
}
wmhints.initial_state = IconicState;
wmhints.flags |= StateHint;
ENTER_XLIB();
XSetWMHints(dpy, win, &wmhints);
LEAVE_XLIB();
}
if (szhints.flags) {
ENTER_XLIB();
XSetNormalHints(dpy, win, &szhints);
LEAVE_XLIB();
}
ENTER_XLIB();
XMapWindow(dpy, win);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
mapWindow:aWindowId
"make a window visible"
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
ENTER_XLIB();
XMapWindow(myDpy, __WindowVal(aWindowId));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
moveResizeWindow:aWindowId x:x y:y width:w height:h
"move and resize a window"
<context: #return>
%{
int newWidth, newHeight;
if (ISCONNECTED
&& __isExternalAddress(aWindowId)
&& __bothSmallInteger(w, h)
&& __bothSmallInteger(x, y)) {
newWidth = __intVal(w);
newHeight = __intVal(h);
if (newWidth < 1) newWidth = 1;
if (newHeight < 1) newHeight = 1;
ENTER_XLIB();
XMoveResizeWindow(myDpy, __WindowVal(aWindowId),
__intVal(x), __intVal(y),
newWidth, newHeight);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
moveWindow:aWindowId x:x y:y
"move a window"
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId) && __bothSmallInteger(x, y)) {
ENTER_XLIB();
XMoveWindow(myDpy, __WindowVal(aWindowId), __intVal(x), __intVal(y));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
raiseWindow:aWindowId
"bring a window to front"
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
ENTER_XLIB();
XRaiseWindow(myDpy, __WindowVal(aWindowId));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
reparentWindow:windowId to:newParentWindowId
"change a windows parent (an optional interface)"
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(windowId)
&& __isExternalAddress(newParentWindowId)) {
Display *dpy = myDpy;
Window _child, _newParent;
int i;
_child = __WindowVal(windowId);
_newParent = __WindowVal(newParentWindowId);
ENTER_XLIB();
#if 0
XWithdrawWindow (dpy, _child, DefaultScreen(dpy));
XSync (dpy, 0);
#endif
/*
* Code 'stolen' from xswallow source ...
* ... mhmh - what is this loop for ?
*/
for (i=0; i<5; i++) {
XReparentWindow (dpy, _child, _newParent, 0, 0);
XSync (dpy, 0);
}
#if 0
XMapWindow (dpy, _child);
XSync (dpy, 0);
#endif
LEAVE_XLIB();
RETURN ( true );
}
%}.
self primitiveFailedOrClosedConnection
!
resizeWindow:aWindowId width:w height:h
"resize a window"
<context: #return>
%{
int newWidth, newHeight;
if (ISCONNECTED
&& __isExternalAddress(aWindowId) && __bothSmallInteger(w, h)) {
newWidth = __intVal(w);
newHeight = __intVal(h);
if (newWidth < 1) newWidth = 1;
if (newHeight < 1) newHeight = 1;
ENTER_XLIB();
XResizeWindow(myDpy, __WindowVal(aWindowId), newWidth, newHeight);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setBackingStore:how in:aWindowId
"turn on/off backing-store for a window"
<context: #return>
%{
XSetWindowAttributes wa;
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
if (__INST(ignoreBackingStore) != true) {
if (how == @symbol(always)) wa.backing_store = Always;
else if (how == @symbol(whenMapped)) wa.backing_store = WhenMapped;
else if (how == true) wa.backing_store = Always;
else wa.backing_store = 0;
ENTER_XLIB();
XChangeWindowAttributes(myDpy, __WindowVal(aWindowId), CWBackingStore, &wa);
LEAVE_XLIB();
}
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setBitGravity:how in:aWindowId
"set bit gravity for a window"
<context: #return>
%{
XSetWindowAttributes wa;
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
if (how == @symbol(NorthWest)) {
wa.bit_gravity = NorthWestGravity;
} else if (how == @symbol(NorthEast)) {
wa.bit_gravity = NorthEastGravity;
} else if (how == @symbol(SouthWest)) {
wa.bit_gravity = SouthWestGravity;
} else if (how == @symbol(SouthEast)) {
wa.bit_gravity = SouthEastGravity;
} else if (how == @symbol(Center)) {
wa.bit_gravity = CenterGravity;
} else if (how == @symbol(North)) {
wa.bit_gravity = NorthGravity;
} else if (how == @symbol(South)) {
wa.bit_gravity = SouthGravity;
} else if (how == @symbol(West)) {
wa.bit_gravity = WestGravity;
} else if (how == @symbol(East)) {
wa.bit_gravity = EastGravity;
} else {
wa.bit_gravity = NorthWestGravity;
}
ENTER_XLIB();
XChangeWindowAttributes(myDpy, __WindowVal(aWindowId), CWBitGravity, &wa);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setCursor:aCursorId in:aWindowId
"define a windows cursor"
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)
&& __isExternalAddress(aCursorId)) {
Display *dpy = myDpy;
Window w = __WindowVal(aWindowId);
Cursor c = __CursorVal(aCursorId);
if (w && c) {
ENTER_XLIB();
XDefineCursor(dpy, w, c);
LEAVE_XLIB();
}
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setIconName:aString in:aWindowId
"define a windows iconname"
<context: #return>
%{
if (ISCONNECTED
&& __isNonNilObject(aString)
&& (__qIsString(aString) || __qIsSymbol(aString))
&& __isExternalAddress(aWindowId)) {
ENTER_XLIB();
XSetIconName(myDpy, __WindowVal(aWindowId), (char *) __stringVal(aString));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setSaveUnder:yesOrNo in:aWindowId
"turn on/off save-under for a window"
<context: #return>
%{
XSetWindowAttributes wa;
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
if (__INST(hasSaveUnder) == true) {
wa.save_under = (yesOrNo == true) ? 1 : 0;
ENTER_XLIB();
XChangeWindowAttributes(myDpy, __WindowVal(aWindowId), CWSaveUnder, &wa);
LEAVE_XLIB();
}
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setTransient:aWindowId for:aMainWindowId
"set aWindowId to be a transient of aMainWindow"
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
Window w;
if ((aMainWindowId == nil) || (aMainWindowId == __MKSMALLINT(0))) {
w = (Window) 0;
} else {
if (__isExternalAddress(aMainWindowId)) {
w = __WindowVal(aMainWindowId);
} else {
goto getOutOfHere;
}
}
ENTER_XLIB();
XSetTransientForHint(myDpy, __WindowVal(aWindowId), w);
LEAVE_XLIB();
RETURN ( self );
}
getOutOfHere: ;
%}.
self primitiveFailedOrClosedConnection
!
setWindowBackground:aColorIndex in:aWindowId
"set the windows background color. This is the color with which
the view is filled whenever exposed. Do not confuse this with
the background drawing color, which is used with opaque drawing."
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)
&& __isSmallInteger(aColorIndex)) {
ENTER_XLIB();
XSetWindowBackground(myDpy, __WindowVal(aWindowId), __intVal(aColorIndex));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setWindowBackgroundPixmap:aPixmapId in:aWindowId
"set the windows background pattern to be a form.
This is the pattern with which the view is filled whenever exposed.
Do not confuse this with the background drawing color, which is used
with opaque drawing."
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)
&& __isExternalAddress(aPixmapId)) {
ENTER_XLIB();
XSetWindowBackgroundPixmap(myDpy, __WindowVal(aWindowId), __PixmapVal(aPixmapId));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setWindowBorderColor:aColorIndex in:aWindowId
"set the windows border color"
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)
&& __isSmallInteger(aColorIndex)) {
ENTER_XLIB();
XSetWindowBorder(myDpy, __WindowVal(aWindowId), __intVal(aColorIndex));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setWindowBorderPixmap:aPixmapId in:aWindowId
"set the windows border pattern"
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)
&& __isExternalAddress(aPixmapId)) {
ENTER_XLIB();
XSetWindowBorderPixmap(myDpy, __WindowVal(aWindowId), __PixmapVal(aPixmapId));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setWindowBorderShape:aPixmapId in:aWindowId
"set the windows border shape"
<context: #return>
hasShapeExtension ifFalse:[^ self].
%{
#ifdef SHAPE
Pixmap shapeBitmap;
if (__isExternalAddress(aPixmapId))
shapeBitmap = __PixmapVal(aPixmapId);
else
shapeBitmap = (Pixmap)0;
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
ENTER_XLIB();
XShapeCombineMask(myDpy, __WindowVal(aWindowId), ShapeBounding,
0, 0, shapeBitmap, ShapeSet);
LEAVE_XLIB();
RETURN ( self );
}
#endif
%}.
self primitiveFailedOrClosedConnection
!
setWindowBorderWidth:aNumber in:aWindowId
"set the windows border width"
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)
&& __isSmallInteger(aNumber)) {
ENTER_XLIB();
XSetWindowBorderWidth(myDpy, __WindowVal(aWindowId), __intVal(aNumber));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setWindowClass:wClass name:wName in:aWindowId
"define class and name of a window.
This may be used by the window manager to
select client specific resources."
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
XClassHint classhint;
classhint.res_class = classhint.res_name = 0;
if (__isString(wClass) || __isSymbol(wClass)) {
classhint.res_class = (char *) __stringVal(wClass);
} else if (wClass != nil)
goto error;
if (__isString(wName) || __isSymbol(wName)) {
classhint.res_name = (char *) __stringVal(wName);
} else if (wName != nil)
goto error;
ENTER_XLIB();
XSetClassHint(myDpy, __WindowVal(aWindowId), &classhint);
LEAVE_XLIB();
RETURN ( self );
error:;
}
%}.
self primitiveFailedOrClosedConnection
!
setWindowGravity:how in:aWindowId
"set window gravity for a window"
<context: #return>
%{
XSetWindowAttributes wa;
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
if (how == @symbol(NorthWest)) {
wa.win_gravity = NorthWestGravity;
} else if (how == @symbol(NorthEast)) {
wa.win_gravity = NorthEastGravity;
} else if (how == @symbol(SouthWest)) {
wa.win_gravity = SouthWestGravity;
} else if (how == @symbol(SouthEast)) {
wa.win_gravity = SouthEastGravity;
} else if (how == @symbol(Center)) {
wa.win_gravity = CenterGravity;
} else if (how == @symbol(North)) {
wa.win_gravity = NorthGravity;
} else if (how == @symbol(South)) {
wa.win_gravity = SouthGravity;
} else if (how == @symbol(West)) {
wa.win_gravity = WestGravity;
} else if (how == @symbol(East)) {
wa.win_gravity = EastGravity;
} else {
wa.win_gravity = NorthWestGravity;
}
ENTER_XLIB();
XChangeWindowAttributes(myDpy, __WindowVal(aWindowId), CWWinGravity, &wa);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setWindowIcon:aForm in:aWindowId
"define a bitmap to be used as icon"
<context: #return>
|iconId|
aForm notNil ifTrue:[
iconId := aForm id
].
%{
if (ISCONNECTED
&& __isExternalAddress(iconId)
&& __isExternalAddress(aWindowId)) {
XWMHints hints;
hints.icon_pixmap = __PixmapVal(iconId);
hints.flags = IconPixmapHint;
ENTER_XLIB();
XSetWMHints(myDpy, __WindowVal(aWindowId), &hints);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setWindowIcon:aForm mask:aMaskForm in:aWindowId
"define a windows icon and (optional) iconMask."
<context: #return>
|iconId maskId|
aForm notNil ifTrue:[
iconId := aForm id
].
aMaskForm notNil ifTrue:[
maskId := aMaskForm id.
].
%{
if (ISCONNECTED
&& __isExternalAddress(iconId)
&& __isExternalAddress(aWindowId)) {
XWMHints hints;
hints.icon_pixmap = __PixmapVal(iconId);
hints.flags = IconPixmapHint;
if ((maskId != nil)
&& __isExternalAddress(maskId)) {
hints.icon_mask = __PixmapVal(maskId);
hints.flags |= IconMaskHint;
}
ENTER_XLIB();
XSetWMHints(myDpy, __WindowVal(aWindowId), &hints);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setWindowIconWindow:aView in:aWindowId
"define a window to be used as icon"
<context: #return>
|iconWindowId|
aView notNil ifTrue:[
iconWindowId := aView id
].
%{
if (ISCONNECTED
&& __isExternalAddress(iconWindowId)
&& __isExternalAddress(aWindowId)) {
XWMHints wmhints;
wmhints.icon_window = __WindowVal(iconWindowId);
wmhints.flags = IconWindowHint;
ENTER_XLIB();
XSetWMHints(myDpy, __WindowVal(aWindowId), &wmhints);
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setWindowMinExtentX:minW y:minH maxExtentX:maxW y:maxH in:aWindowId
"set a windows minimum & max extents.
nil arguments are ignored."
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
Display *dpy = myDpy;
XSizeHints szhints;
Window win;
win = __WindowVal(aWindowId);
szhints.flags = 0;
if (__bothSmallInteger(minW, minH)) {
szhints.flags |= PMinSize;
szhints.min_width = __intVal(minW);
szhints.min_height = __intVal(minH);
}
if (__bothSmallInteger(maxW, maxH)) {
szhints.flags |= PMaxSize;
szhints.max_width = __intVal(maxW);
szhints.max_height = __intVal(maxH);
}
if (szhints.flags) {
ENTER_XLIB();
XSetNormalHints(dpy, win, &szhints);
LEAVE_XLIB();
}
}
%}.
!
setWindowName:aString in:aWindowId
"define a windows name"
<context: #return>
%{
if (ISCONNECTED
&& __isNonNilObject(aString)
&& (__qIsString(aString) || __qIsSymbol(aString))
&& __isExternalAddress(aWindowId)) {
ENTER_XLIB();
XStoreName(myDpy, __WindowVal(aWindowId), (char *) __stringVal(aString));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
setWindowShape:aPixmapId in:aWindowId
"set the windows shape.
Returns false, if the display does not support the
X shape extension."
<context: #return>
hasShapeExtension ifFalse:[^ self].
%{
#ifdef SHAPE
Pixmap shapeBitmap;
if (__isExternalAddress(aPixmapId))
shapeBitmap = __PixmapVal(aPixmapId);
else
shapeBitmap = (Pixmap)0;
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
ENTER_XLIB();
XShapeCombineMask(myDpy, __WindowVal(aWindowId), ShapeClip,
0, 0,
shapeBitmap, ShapeSet);
LEAVE_XLIB();
RETURN ( self );
}
#endif
%}.
self primitiveFailedOrClosedConnection
!
unmapWindow:aWindowId
"make a window invisible"
<context: #return>
%{
if (!ISCONNECTED) {
RETURN ( self );
}
if (__isExternalAddress(aWindowId)) {
ENTER_XLIB();
XUnmapWindow(myDpy, __WindowVal(aWindowId));
LEAVE_XLIB();
RETURN ( self );
}
%}.
self primitiveFailedOrClosedConnection
!
windowIsIconified:aWindowId
"return true, if some window is iconified.
The passed windowID may be an alien windows id."
<context: #return>
%{
if (ISCONNECTED
&& __isExternalAddress(aWindowId)) {
Atom JunkAtom;
int JunkInt;
unsigned long WinState,JunkLong;
unsigned char *Property;
Atom WM_STATE_Atom;
if (__INST(wmStateAtom) != nil) {
WM_STATE_Atom = __AtomVal(__INST(wmStateAtom));
ENTER_XLIB();
XGetWindowProperty(myDpy, __WindowVal(aWindowId),
WM_STATE_Atom,
0L, 2L, False, AnyPropertyType,
&JunkAtom,&JunkInt,&WinState,&JunkLong,
&Property);
LEAVE_XLIB();
WinState=(unsigned long)(*((long*)Property));
if (WinState==3) {
RETURN (true);
}
}
RETURN (false);
}
%}.
self primitiveFailedOrClosedConnection.
^ false "/ or true or what ?
! !
!XWorkstation class methodsFor:'documentation'!
version
^ '$Header: /cvs/stx/stx/libview/XWorkstation.st,v 1.389 2001-07-18 12:47:54 stefan Exp $'
! !
XWorkstation initialize!