"
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.
"
DeviceWorkstation subclass:#XWorkstation
instanceVariableNames:'screen
hasShapeExtension hasFaxExtension hasShmExtension
hasDPSExtension hasSaveUnder ignoreBackingStore
blackpixel whitepixel redMask greenMask blueMask
protocolsAtom deleteWindowAtom saveYourselfAtom
quitAppAtom
listOfXFonts eventRootX eventRootY buttonsPressed
displayName eventTrace
dispatchingExpose
rgbVisual virtualRootId'
classVariableNames: ''
poolDictionaries:''
category:'Interface-Graphics'
!
XWorkstation comment:'
COPYRIGHT (c) 1989 by Claus Gittinger
All Rights Reserved
$Header: /cvs/stx/stx/libview/XWorkstation.st,v 1.36 1995-03-18 05:13:21 claus Exp $
'!
!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.
"
!
version
"
$Header: /cvs/stx/stx/libview/XWorkstation.st,v 1.36 1995-03-18 05:13:21 claus Exp $
"
!
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 ...
"
! !
!XWorkstation primitiveDefinitions!
%{
/*
* x does a typedef Time - I need Object Time ...
*/
#define Time XTime
#ifdef memset
# undef memset
#endif
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
/*
* this define adds support for two-byte-strings.
* leaving it undefined does not really save you much
* (the define will vanish)
*/
#define TWOBYTESTRINGS
/*
* shape support works; enabled by -DSHAPE in makefile
* see RoundClock and RoundGlobe examples
*/
#ifdef SHAPE
# include <X11/extensions/shape.h>
#endif
/*
* shared memory extension currently not supported
* (only query is implemented)
*/
#ifdef SHM
# include <X11/extensions/XShm.h>
#endif
/*
* this is a non-standard fax-image decompression extension
* (only found in megascan servers ported by myself)
*/
#ifdef FAX
# include <X11/extensions/XFAXImage.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(IRIX5) || (XlibSpecificationRelease == 6)
/*
* accessing private data in Display ... sorry
*/
# define DISPLAYACCESS(d) ((_XPrivDisplay)d)
#else
# define DISPLAYACCESS(d) d
#endif
#if defined(hpux) && defined(POSITIVE_ADDRESSES)
# undef MKOBJ
# define MKOBJ(p) (OBJ)((int)p | TAG_INT)
# define MKCP(o) (char *)((int)(o) & ~TAG_INT)
#else
# define MKCP(o) (char *)(_intVal(o))
#endif
/*
* some defines - tired of typing ...
*/
#define _DisplayVal(o) (Display *)(MKCP(o))
#define _WindowVal(o) (Window)(MKCP(o))
#define _PixmapVal(o) (Pixmap)(MKCP(o))
#define _GCVal(o) (GC)(MKCP(o))
#define _CursorVal(o) (Cursor)(MKCP(o))
#define _FontVal(o) (XFontStruct *)(MKCP(o))
#define _AtomVal(o) (Atom)(MKCP(o))
#define _DPSContextVal(o) (DPSContext)(MKCP(o))
#define myDpy _DisplayVal(_INST(displayId))
#ifndef THISCONTEXT_IN_REGISTER
# define BLOCKINTERRUPTS() /* */
# define UNBLOCKINTERRUPTS() /* */
# define BEGIN_INTERRUPTSBLOCKED /* */
# define END_INTERRUPTSBLOCKED /* */
#else
extern int __interruptsBlocked;
# define BEGIN_INTERRUPTSBLOCKED \
{ \
int needUnblock = 0; \
extern OBJ __thisContext__; \
\
__thisContext__ = __thisContext;\
if (!__interruptsBlocked) { \
BLOCKINTERRUPTS(); \
needUnblock = 1; \
}
# define END_INTERRUPTSBLOCKED \
if (needUnblock) { \
UNBLOCKINTERRUPTS(); \
} \
__thisContext__ = 0; \
}
#endif
%}
! !
!XWorkstation primitiveVariables!
%{
static XEvent __ev__;
/*
* a private error handler
*/
static char lastErrorMsg[80] = "";
static unsigned lastRequestCode = 0;
static unsigned lastMinorCode = 0;
static unsigned lastResource = 0;
%}
! !
!XWorkstation primitiveFunctions!
%{
/*
* catch X-errors and forward as errorInterrupt,
* (which itself 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.
*/
__XErrorHandler__(dpy, event)
Display *dpy;
XErrorEvent *event;
{
XGetErrorText(dpy, event->error_code, lastErrorMsg, 80);
if (lastErrorMsg[0] == '\0') {
sprintf(lastErrorMsg, "code: %d", event->error_code);
}
lastRequestCode = event->request_code;
lastMinorCode = event->minor_code;
lastResource = event->resourceid;
fprintf(stderr, "XWORKSTAT: x-error cought 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, "XWORKSTAT: x-error message is '%s'\n", lastErrorMsg);
errorInterrupt();
return 0;
}
#ifdef VIRTUAL_ROOT
/*
* added since RootWindow-macro is not suficient
* 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;
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 (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;
break;
}
}
}
if (children) XFree( children );
}
}
# endif
return root;
}
#endif
%}
! !
!XWorkstation class methodsFor:'initialization'!
initialize
self initializeConstants.
! !
!XWorkstation class methodsFor:'error handling'!
requestCodeOfLastError
%{ /* NOCONTEXT */
RETURN ( _MKSMALLINT(lastRequestCode) );
%}
!
minorCodeOfLastError
%{ /* NOCONTEXT */
RETURN ( _MKSMALLINT(lastMinorCode) );
%}
!
resourceIdOfLastError
%{ /* NOCONTEXT */
RETURN ( _MKSMALLINT(lastResource) );
%}
!
errorStringOfLastError
%{
RETURN ( _MKSTRING(lastErrorMsg, __context) );
%}
!
lastError
"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
! !
!XWorkstation methodsFor:'initialize / release'!
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|
dpyName := aDisplayName.
dpyName isNil ifTrue:[
"look for a '-display xxx' argument"
index := Arguments indexOf:'-display'.
(index between:1 and:(Arguments size - 1)) ifTrue:[
dpyName := Arguments at:index+1
]
].
%{
int scr;
Display *dpy;
Visual *visual;
XVisualInfo viproto;
XVisualInfo *vip; /* retured info */
int maxRGBDepth;
int rgbRedMask, rgbGreenMask, rgbBlueMask;
int rgbVisualID;
int nvi, i;
int shapeEventBase, shapeErrorBase;
int shmEventBase, shmErrorBase;
int faxEventBase, faxErrorBase;
char *type, *nm;
int dummy;
if (_INST(displayId) != nil) {
RETURN ( self );
}
BEGIN_INTERRUPTSBLOCKED
if (__isString(dpyName))
nm = (char *)_stringVal(dpyName);
else
nm = NULL;
dpy = XOpenDisplay(nm);
if (dpy) {
#ifdef SUPERDEBUG
XSynchronize(dpy, 1);
#endif
_INST(screen) = _MKSMALLINT(scr = DefaultScreen(dpy));
_INST(displayId) = MKOBJ((int)dpy);
_INST(depth) = _MKSMALLINT(DisplayPlanes(dpy, scr));
_INST(ncells) = _MKSMALLINT(DisplayCells(dpy, scr));
_INST(width) = _MKSMALLINT(DisplayWidth(dpy, scr));
_INST(height) = _MKSMALLINT(DisplayHeight(dpy, scr));
_INST(widthMM) = _MKSMALLINT(DisplayWidthMM(dpy, scr));
_INST(heightMM) = _MKSMALLINT(DisplayHeightMM(dpy, scr));
_INST(blackpixel) = _MKSMALLINT(BlackPixel(dpy, scr));
_INST(whitepixel) = _MKSMALLINT(WhitePixel(dpy, scr));
#ifdef SHAPE
if (XShapeQueryExtension(dpy, &shapeEventBase, &shapeErrorBase))
_INST(hasShapeExtension) = true;
else
#else
_INST(hasShapeExtension) = false;
#endif
#ifdef SHM
if (XShmQueryExtension(dpy, &shmEventBase, &shmErrorBase))
_INST(hasShmExtension) = true;
else
#else
_INST(hasShmExtension) = false;
#endif
#ifdef FAX
if (XFAXImageQueryExtension(dpy, &faxEventBase, &faxErrorBase))
_INST(hasFaxExtension) = true;
else
#else
_INST(hasFaxExtension) = false;
#endif
#ifdef DPS
if (XQueryExtension(dpy, "DPSExtension", &dummy, &dummy, &dummy))
_INST(hasDPSExtension) = true;
else
#else
_INST(hasDPSExtension) = false;
#endif
/*
* this is a kludge around a bug in the X11/NeWS server,
* which does not correctly handle saveUnder
*/
if (strncmp(XServerVendor(dpy), "X11/NeWS", 8) == 0) {
_INST(hasSaveUnder) = false;
} else
_INST(hasSaveUnder) = true;
/*
* 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) = _MKSMALLINT(rgbVisualID);
}
visual = DefaultVisualOfScreen(DefaultScreenOfDisplay(dpy));
switch (visual->class) {
case StaticGray:
_INST(visualType) = @symbol(StaticGray);
_INST(hasColors) = false;
_INST(hasGreyscales) = true;
_INST(monitorType) = @symbol(monochrome);
break;
case GrayScale:
_INST(visualType) = @symbol(GrayScale);
_INST(hasColors) = false;
_INST(hasGreyscales) = true;
_INST(monitorType) = @symbol(monochrome);
break;
case StaticColor:
_INST(visualType) = @symbol(StaticColor);
_INST(hasColors) = true;
_INST(hasGreyscales) = true;
_INST(monitorType) = @symbol(unknown);
break;
case PseudoColor:
_INST(visualType) = @symbol(PseudoColor);
_INST(hasColors) = true;
_INST(hasGreyscales) = true;
_INST(monitorType) = @symbol(unknown);
break;
case TrueColor:
_INST(visualType) = @symbol(TrueColor);
_INST(hasColors) = true;
_INST(hasGreyscales) = true;
_INST(monitorType) = @symbol(unknown);
break;
case DirectColor:
_INST(visualType) = @symbol(DirectColor);
_INST(hasColors) = true;
_INST(hasGreyscales) = true;
_INST(monitorType) = @symbol(unknown);
break;
}
if (DisplayCells(dpy, scr) == 2) {
_INST(hasColors) = false;
_INST(hasGreyscales) = false;
_INST(monitorType) = @symbol(monochrome);
}
_INST(bitsPerRGB) = _MKSMALLINT(visual->bits_per_rgb);
_INST(redMask) = _MKSMALLINT(visual->red_mask);
_INST(greenMask) = _MKSMALLINT(visual->green_mask);
_INST(blueMask) = _MKSMALLINT(visual->blue_mask);
XSetErrorHandler(__XErrorHandler__);
}
END_INTERRUPTSBLOCKED
%}
.
displayId isNil ifTrue:[
'cannot connect to Display.' errorPrintNewline.
^ nil
].
dispatching := false.
dispatchingExpose := false.
isSlow := false.
shiftDown := false.
controlDown := false.
metaDown := false.
altDown := false.
motionEventCompression := true.
buttonsPressed := 0.
displayName := dpyName.
buttonTranslation := ButtonTranslation.
multiClickTimeDelta := MultiClickTimeDelta.
protocolsAtom := nil.
deleteWindowAtom := nil.
saveYourselfAtom := nil.
quitAppAtom := nil.
self initializeKeyboardMap.
ObjectMemory errorInterruptHandler:self class.
!
close
"close down the connection to the X-server"
%{ /* NOCONTEXT */
if (_INST(displayId) != nil) {
BEGIN_INTERRUPTSBLOCKED
XCloseDisplay(myDpy);
_INST(displayId) = nil;
END_INTERRUPTSBLOCKED
}
%}
!
reinitialize
virtualRootId := nil.
super reinitialize.
dispatchingExpose := nil
! !
!XWorkstation methodsFor:'misc'!
setInputFocusTo:aWindowId
"/ self setInputFocusTo:aWindowId revertTo:#parent
self setInputFocusTo:aWindowId revertTo:#root
!
setInputFocusTo:aWindowId revertTo:revertSymbol
%{ /* NOCONTEXT */
int arg;
if (__isSmallInteger(aWindowId)) {
if (revertSymbol == @symbol(parent))
arg = RevertToParent;
else if (revertSymbol == @symbol(root))
arg = RevertToPointerRoot;
else
arg = None;
BEGIN_INTERRUPTSBLOCKED
XSetInputFocus(myDpy, _WindowVal(aWindowId), arg, CurrentTime);
END_INTERRUPTSBLOCKED
RETURN ( self );
}
%}.
self primitiveFailed
!
unBuffered
"make all drawing be sent immediately to the display"
%{ /* NOCONTEXT */
BEGIN_INTERRUPTSBLOCKED
XSynchronize(myDpy, 1);
END_INTERRUPTSBLOCKED
%}
"Display unbuffered"
!
buffered
"buffer drawing - do not send it immediately to the display"
%{ /* NOCONTEXT */
BEGIN_INTERRUPTSBLOCKED
XSynchronize(myDpy, 0);
END_INTERRUPTSBLOCKED
%}
"Display buffered"
!
synchronizeOutput
"send all buffered drawing to the display"
%{ /* NOCONTEXT */
BEGIN_INTERRUPTSBLOCKED
XSync(myDpy, 0);
END_INTERRUPTSBLOCKED
%}
!
flushDpsContext:aDPSContext
%{ /* NOCONTEXT */
#ifdef DPS
if (__isSmallInteger(aDPSContext)) {
BEGIN_INTERRUPTSBLOCKED
DPSFlushContext(MKDPSCONTEXT(aDPSContext));
END_INTERRUPTSBLOCKED
RETURN ( self );
}
#endif
%}
.
self primitiveFailed
!
beep:volumeInPercent
"output an audible beep"
%{
int volume;
if (__isSmallInteger(volumeInPercent)) {
/* 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;
BEGIN_INTERRUPTSBLOCKED
XBell(myDpy, volume);
END_INTERRUPTSBLOCKED
}
%}
!
beep
"output an audible beep or bell"
self beep:50
!
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
! !
!XWorkstation class methodsFor:'queries'!
platformName
^ 'X'
! !
!XWorkstation methodsFor:'accessing & queries'!
displayFileDescriptor
"return the displays fileNumber - for select"
%{ /* NOCONTEXT */
RETURN ( MKOBJ(ConnectionNumber(myDpy)) );
%}
!
serverVendor
"return the X-server vendor string - this should normally not be of
any interrest, but can be for special cases
(to avoid bugs in certain implementations)"
%{
RETURN ( _MKSTRING(XServerVendor(myDpy), __context) );
%}
"
Display serverVendor
"
!
vendorRelease
"return the X-servers vendor release - should normally not be of
any interrest, but can be for special cases.
(to avoid bugs in certain implementations)"
%{ /* NOCONTEXT */
RETURN ( _MKSMALLINT(XVendorRelease(myDpy)) );
%}
"
Display vendorRelease
"
!
protocolVersion
"return the X-servers protocol version - should normally not be of
any interrest"
%{ /* NOCONTEXT */
RETURN ( _MKSMALLINT(XProtocolVersion(myDpy)) );
%}
"
Display protocolVersion
"
!
hasShape
"return true, if this workstation supports non-rectangular windows"
^ hasShapeExtension
"
Display hasShape
"
!
hasShm
"return true, if this workstation supports shared pixmaps"
^ hasShmExtension
!
hasFax
"return true, if this workstation supports decompression of fax images"
^ hasFaxExtension
!
hasDPS
"return true, if this workstation supports display postscript"
^ hasDPSExtension
!
supportedImageFormats
"return an array with supported image formats; each array entry
is another array, consisting of depth and bitsPerPixel values."
|nFormats formatArray|
%{
Display *dpy = myDpy;
nFormats = _MKSMALLINT(DISPLAYACCESS(dpy)->nformats);
%}.
formatArray := Array new:nFormats.
1 to:nFormats do:[:i |
|bitsPerPixelInfo depthInfo|
%{
ScreenFormat *format;
Display *dpy = myDpy;
format = DISPLAYACCESS(dpy)->pixmap_format;
format += (_intVal(i)-1);
bitsPerPixelInfo = _MKSMALLINT(format->bits_per_pixel);
depthInfo = _MKSMALLINT(format->depth);
%}.
formatArray at:i put:(Array with:depthInfo with:bitsPerPixelInfo).
].
^ formatArray
"
Display supportedImageFormats
"
!
supportsDeepIcons
"return true, if this device supports non b&w (i.e. greyScale
or colored icons). Many Xservers (and/or windowManagers) crash,
if you pass them a deep form as icon; therefore, we return false."
^ false
!
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
!
blackpixel
"return the colornumber of black"
^ blackpixel
!
whitepixel
"return the colornumber of white"
^ whitepixel
!
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
!
button1MotionMask
"return the state-mask for button1 in motion events state-field.
For backward compatibility."
%{ /* NOCONTEXT */
RETURN (_MKSMALLINT(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));
%}
!
defaultEventMask
"return a mask to enable some events by default."
%{ /* NOCONTEXT */
RETURN (_MKSMALLINT( ExposureMask | StructureNotifyMask |
KeyPressMask |
ButtonPressMask | ButtonMotionMask | ButtonReleaseMask ));
%}
!
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."
%{ /* NOCONTEXT */
Display *dpy = myDpy;
int screen = _intVal(_INST(screen));
OBJ xp, yp;
int xpos, ypos;
Window child_return;
if (__isSmallInteger(windowId)
&& __isPoint(aPoint)) {
xp = _point_X(aPoint);
yp = _point_Y(aPoint);
if (__bothSmallInteger(xp, yp)) {
BEGIN_INTERRUPTSBLOCKED
XTranslateCoordinates(dpy,
RootWindow(dpy, screen),
_WindowVal(windowId),
_intVal(xp), _intVal(yp),
&xpos, &ypos, &child_return);
END_INTERRUPTSBLOCKED
if (child_return) {
RETURN ( MKOBJ(child_return) );
}
RETURN ( nil );
}
}
%}.
(windowId isMemberOf:SmallInteger) ifTrue:[
^ self viewIdFromPoint:aPoint asPoint truncated in:windowId
].
^ nil
!
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"
|x1 y1 x2 y2|
x1 := x2 := aPoint x truncated.
y1 := y2 := aPoint y truncated.
%{
int xpos, ypos;
Window w1, w2, child_return;
int screen = _intVal(_INST(screen));
Display *dpy = myDpy;
if (__bothSmallInteger(windowId1, windowId2)
&& __bothSmallInteger(x1, y1)) {
w1 = _WindowVal(windowId1);
w2 = _WindowVal(windowId2);
#ifdef VIRTUAL_ROOT
if ((w1 == RootWindow(dpy, screen))
|| (w2 == RootWindow(dpy, screen))) {
if (w1 == RootWindow(dpy, screen)) {
w1 = getRootWindow(dpy, screen);
}
if (w2 == RootWindow(dpy, screen)) {
w2 = getRootWindow(dpy, screen);
}
}
#endif
BEGIN_INTERRUPTSBLOCKED
XTranslateCoordinates(dpy, w1, w2,
_intVal(x1), _intVal(y1),
&xpos, &ypos, &child_return);
END_INTERRUPTSBLOCKED
x2 = _MKSMALLINT(xpos);
y2 = _MKSMALLINT(ypos);
}
%}.
^ (x2 @ y2)
! !
!XWorkstation methodsFor:'bitmap/window creation'!
createFaxImageFromArray:data width:w height:h type:type k:k msbFirst:msbFirst
"create a new faxImage in the workstation
type: 0 -> uncompressed
1 -> group3 1D (k is void)
2 -> group3 2D
3 -> group4 2D (k is void)"
|nBytes|
hasFaxExtension ifFalse:[^ nil].
nBytes := data size.
%{
#ifdef FAX
Display *dpy = myDpy;
int screen = _intVal(_INST(screen));
FAXImage newImage;
int _type, _msb, _k = 0;
unsigned char *bits;
extern OBJ ByteArray;
if (__bothSmallInteger(w, h)
&& __bothSmallInteger(type, k)
&& __isSmallInteger(nBytes)
&& __isByteArray(data)) {
if (msbFirst == true)
_msb = 1;
else
_msb = 0;
_type = _intVal(type);
if ((_type < 0) || (_type > 3)) {
RETURN ( nil );
}
if (_type == 2) {
if (! __isSmallInteger(k)) {
RETURN ( nil );
}
_k = _intVal(k);
}
bits = _ByteArrayInstPtr(data)->ba_element;
BEGIN_INTERRUPTSBLOCKED
newImage = XFAXImageCreateImage(dpy, _intVal(w), _intVal(h),
_type, _k, _msb,
_intVal(nBytes), bits);
END_INTERRUPTSBLOCKED
RETURN ( (newImage != (FAXImage)0) ? MKOBJ(newImage) : nil );
}
#else
RETURN ( nil );
#endif
%}
.
self primitiveFailed.
^ nil
!
createBitmapWidth:w height:h
"allocate a bitmap on the Xserver, the contents is undefined
(i.e. random). Return a bitmap id or nil"
%{ /* NOCONTEXT */
Display *dpy = myDpy;
int screen = _intVal(_INST(screen));
Pixmap newBitmap;
if (__bothSmallInteger(w, h)) {
BEGIN_INTERRUPTSBLOCKED
newBitmap = XCreatePixmap(dpy, RootWindow(dpy, screen),
_intVal(w), _intVal(h), 1);
END_INTERRUPTSBLOCKED
RETURN ( (newBitmap != (Pixmap)0) ? MKOBJ(newBitmap) : nil );
}
%}
.
self primitiveFailed.
^ 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"
%{ /* NOCONTEXT */
Display *dpy = myDpy;
int screen = _intVal(_INST(screen));
Pixmap newBitmap;
if (__bothSmallInteger(w, h)) {
BEGIN_INTERRUPTSBLOCKED
newBitmap = XCreatePixmap(dpy, RootWindow(dpy, screen),
_intVal(w), _intVal(h), _intVal(d));
END_INTERRUPTSBLOCKED
RETURN ( (newBitmap != (Pixmap)0) ? MKOBJ(newBitmap) : nil );
}
%}
.
self primitiveFailed.
^ nil
!
createBitmapFromFile:aString for:aForm
|id w h|
%{
Display *dpy = myDpy;
int screen = _intVal(_INST(screen));
Pixmap newBitmap;
char *filename;
unsigned b_width, b_height;
int b_x_hot, b_y_hot;
int status;
if (__isString(aString) || __isSymbol(aString)) {
filename = (char *)_stringVal(aString);
BEGIN_INTERRUPTSBLOCKED
status = XReadBitmapFile(dpy, RootWindow(dpy, screen),
filename, &b_width, &b_height, &newBitmap,
&b_x_hot, &b_y_hot);
END_INTERRUPTSBLOCKED
if (status == BitmapSuccess) {
w = _MKSMALLINT(b_width);
h = _MKSMALLINT(b_height);
id = MKOBJ(newBitmap);
}
}
%}
.
id notNil ifTrue:[
aForm setWidth:w height:h
].
^ id
!
primCreateBitmapFromArray:anArray width:w height:h
%{ /* UNLIMITEDSTACK */
Display *dpy = myDpy;
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;
extern OBJ Array, ByteArray;
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)) {
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) == 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)) goto fail;
bits = _intVal(num);
*cp++ = reverseBitTable[bits];
}
}
} else {
if (_qClass(anArray) == ByteArray) {
pBits = _ByteArrayInstPtr(anArray)->ba_element;
for (col = b_height*bytesPerRow; col; col--) {
*cp++ = reverseBitTable[*pBits++];
}
} else {
goto fail;
}
}
BEGIN_INTERRUPTSBLOCKED
newBitmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
(char *)b_bits,
b_width, b_height);
END_INTERRUPTSBLOCKED
fail: ;
if (allocatedBits)
free(allocatedBits);
RETURN ( newBitmap ? MKOBJ(newBitmap) : nil );
}
%}
!
createBitmapFromArray:anArray width:w height:h
|bitmapId|
bitmapId := self primCreateBitmapFromArray:anArray width:w height:h.
bitmapId isNil ifTrue:[
self primitiveFailed
].
^ bitmapId
!
destroyPixmap:aDrawableId
%{ /* NOCONTEXT */
if (__isSmallInteger(aDrawableId)) {
BEGIN_INTERRUPTSBLOCKED
XFreePixmap(myDpy, _PixmapVal(aDrawableId));
END_INTERRUPTSBLOCKED
RETURN ( self );
}
%}
.
self primitiveFailed
!
destroyFaxImage:aFaxImageId
%{ /* NOCONTEXT */
#ifdef FAX
if (__isSmallInteger(aFaxImageId)) {
BEGIN_INTERRUPTSBLOCKED
XFAXImageFreeImage(myDpy, (FAXImage)_WindowVal(aFaxImageId));
END_INTERRUPTSBLOCKED
RETURN ( self );
}
#endif
%}
.
self primitiveFailed
!
realRootWindowFor:aView
%{
int screen = _intVal(_INST(screen));
Window root;
root = RootWindow(myDpy, screen);
if (! root) {
RETURN ( nil );
}
RETURN( MKOBJ(root) );
%}
!
rootWindowFor:aView
|id|
%{
int screen = _intVal(_INST(screen));
Window root;
OBJ vRoot;
vRoot = _INST(virtualRootId);
if (__isSmallInteger(vRoot)) {
root = _WindowVal(vRoot);
} else {
BEGIN_INTERRUPTSBLOCKED
root = RootWindow(myDpy, 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 = None;
int i;
Window rootReturn, parentReturn;
Window* children;
unsigned int numChildren;
if (XQueryTree(myDpy, root,
&rootReturn, &parentReturn,
&children, &numChildren)) {
vRootAtom = XInternAtom(myDpy, "__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(myDpy, children[i], vRootAtom,
0L, 1L, False, XA_WINDOW,
&actual_type, &actual_format,
&nitems, &bytesafter,
(unsigned char**) &newRoot
) == Success && newRoot) {
root = *newRoot;
break;
}
}
}
if (children) XFree( children );
}
}
}
#endif
END_INTERRUPTSBLOCKED
}
if (! root) {
RETURN ( nil );
}
id = _INST(virtualRootId) = MKOBJ(root);
%}
.
self addKnownView:aView withId:id.
^ id
!
createWindowFor:aView left:xpos top:ypos width:wwidth height:wheight
"will vanish - for compatibility with previous versions"
^ self
createWindowFor:aView
origin:(xpos @ ypos)
extent:(wwidth @ wheight)
minExtent:(aView minExtent)
maxExtent:(aView maxExtent)
borderWidth:(aView borderWidth)
"/ borderColor:(aView borderColor)
subViewOf:(aView superView)
onTop:(aView createOnTop)
inputOnly:(aView inputOnly)
label:(aView label)
cursor:(aView cursor)
icon:(aView icon)
iconView:(aView iconView)
!
createWindowFor:aView
origin:origin
extent:extent
minExtent:minExt
maxExtent:maxExt
borderWidth:bWidth
"/ borderColor:bColor
subViewOf:wsuperView
onTop:wcreateOnTop
inputOnly:winputOnly
label:wlabel
cursor:wcursor
icon:wicon
iconView:wiconView
|xpos ypos wwidth wheight minWidth minHeight maxWidth maxHeight
bColorId wsuperViewId wcursorId wiconId windowId
weventMask wiconViewId bitGravity viewGravity vBgColor
vBgForm deepForm preferedVisual preferedDepth|
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
].
"
bColor notNil ifTrue:[
bColorId := bColor colorId
].
"
"
viewBg := aView viewBackground.
viewBg notNil ifTrue:[
viewBg isColor ifTrue:[
viewBg := viewBg colorId.
] ifFalse:[
viewBg := nil.
]
].
"
wsuperView notNil ifTrue:[
wsuperViewId := wsuperView id
].
wcursor isNil ifTrue:[
'cursor nil - defaulted' errorPrintNewline
] ifFalse:[
wcursorId := wcursor id
].
wicon notNil ifTrue:[
wiconId := wicon id
].
wiconView notNil ifTrue:[
wiconViewId := wiconView id
].
weventMask := aView eventMask.
"/ bitGravity := aView bitGravity.
"/ viewGravity := aView viewGravity.
preferedVisual := aView preferedVisual.
preferedDepth := aView preferedDepth.
%{ /* STACK:16000 */
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;
int flags = 0, depth, ioClass;
extern OBJ Rectangle, Form;
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(viewBg)) {
bg = _intVal(viewBg);
} else if (__isSmallInteger(viewBgId)) {
backPixmap = _PixmapVal(viewBgId);
}
*/
if (__isSmallInteger(bWidth)) {
bw = _intVal(bWidth);
} else {
bw = 0;
}
#ifdef OLD
if (__isSmallInteger(bColor)) {
bd = _intVal(bColor);
} else {
bd = BlackPixel(dpy, screen);
}
#else
bd = BlackPixel(dpy, screen);
#endif
if (__isSmallInteger(wsuperViewId)) {
parentWindow = _WindowVal(wsuperViewId);
} else {
parentWindow = RootWindow(dpy, screen);
isTopWindow = 1;
}
#ifdef OLD
if (bitGravity == @symbol(NorthWest)) {
xswa.bit_gravity = NorthWestGravity;
flags |= CWBitGravity;
}
if (viewGravity != nil) {
if (viewGravity == @symbol(NorthWest)) {
xswa.win_gravity = NorthWestGravity;
flags |= CWWinGravity;
}
if (viewGravity == @symbol(NorthEast)) {
xswa.win_gravity = NorthEastGravity;
flags |= CWWinGravity;
}
if (viewGravity == @symbol(SouthWest)) {
xswa.win_gravity = SouthWestGravity;
flags |= CWWinGravity;
}
if (viewGravity == @symbol(SouthEast)) {
xswa.win_gravity = SouthEastGravity;
flags |= CWWinGravity;
}
if (viewGravity == @symbol(Center)) {
xswa.win_gravity = CenterGravity;
flags |= CWWinGravity;
}
if (viewGravity == @symbol(North)) {
xswa.win_gravity = NorthGravity;
flags |= CWWinGravity;
}
if (viewGravity == @symbol(South)) {
xswa.win_gravity = SouthGravity;
flags |= CWWinGravity;
}
if (viewGravity == @symbol(West)) {
xswa.win_gravity = WestGravity;
flags |= CWWinGravity;
}
if (viewGravity == @symbol(East)) {
xswa.win_gravity = EastGravity;
flags |= CWWinGravity;
}
}
#endif
if (wcreateOnTop == true)
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;
}
#ifdef OLD
/* these may not be disabled */
xswa.event_mask |= ExposureMask | StructureNotifyMask |
KeyPressMask |
ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
#endif
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(preferedDepth)) {
depth = _intVal(preferedDepth);
}
BEGIN_INTERRUPTSBLOCKED
if (preferedVisual != nil) {
XVisualInfo vi;
int cls;
if (preferedVisual == @symbol(StaticGray))
cls = StaticGray;
else if (preferedVisual == @symbol(GrayScale))
cls = StaticGray;
else if (preferedVisual == @symbol(StaticColor))
cls = StaticColor;
else if (preferedVisual == @symbol(PseudoColor))
cls = PseudoColor;
else if (preferedVisual == @symbol(TrueColor))
cls = TrueColor;
else if (preferedVisual == @symbol(DirectColor))
cls = DirectColor;
else
cls = PseudoColor;
if (XMatchVisualInfo(dpy, screen, depth, cls, &vi)) {
visual.visualid = vi.visualid;
printf("visualId=%x\n", vi.visualid);
}
}
newWindow = XCreateWindow(dpy, parentWindow,
sizehints.x, sizehints.y,
sizehints.width, sizehints.height,
bw, depth, ioClass, &visual,
flags, &xswa);
END_INTERRUPTSBLOCKED
if (! newWindow) {
RETURN ( nil );
}
BEGIN_INTERRUPTSBLOCKED
/*
* define its cursor
*/
if (__isSmallInteger(wcursorId)) {
XDefineCursor(dpy, newWindow, _CursorVal(wcursorId));
}
/*
* define its icon and name
* (only makes sense for topWindows)
*/
if (isTopWindow) {
if (__isSmallInteger(wiconId))
iconBitmap = _PixmapVal(wiconId);
else
iconBitmap = (Pixmap)0;
if (__isSmallInteger(wiconViewId))
iconWindow = _WindowVal(wiconViewId);
else
iconWindow = (Window)0;
if (__isString(wlabel) || __isSymbol(wlabel))
windowName = (char *)_stringVal(wlabel);
else
windowName = "";
if (iconBitmap || windowName) {
XSetStandardProperties(dpy, newWindow,
windowName, windowName,
iconBitmap,
0, 0, &sizehints);
}
wmhints.flags = 0;
if (iconBitmap) {
wmhints.flags |= IconPixmapHint;
wmhints.icon_pixmap = iconBitmap;
}
if (iconWindow) {
wmhints.flags |= IconWindowHint;
wmhints.icon_window = iconWindow;
}
/*
wmhints.flags |= InputHint;
wmhints.input = True;
*/
XSetWMHints(dpy, newWindow, &wmhints);
/*
* tell window manager to not kill us but send an event instead
*/
/*
* get atoms first (if not already known)
*/
if (_INST(protocolsAtom) == nil) {
WmProtocolsAtom = XInternAtom(dpy, "WM_PROTOCOLS", False);
_INST(protocolsAtom) = _MKSMALLINT(WmProtocolsAtom);
#ifdef USE_SAVEYOURSELF_ATOM
WmSaveYourselfAtom = XInternAtom(dpy, "WM_SAVE_YOURSELF", False);
_INST(saveYourselfAtom) = _MKSMALLINT(WmSaveYourselfAtom);
#endif
#ifdef USE_QUIT_APP_ATOM
WmQuitAppAtom = XInternAtom(dpy, "_WM_QUIT_APP", False);
_INST(quitAppAtom) = _MKSMALLINT(WmQuitAppAtom);
#endif
WmDeleteWindowAtom = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
_INST(deleteWindowAtom) = _MKSMALLINT(WmDeleteWindowAtom);
} else {
#ifdef USE_QUIT_APP_ATOM
WmQuitAppAtom = _intVal(_INST(quitAppAtom));
#else
WmQuitAppAtom = 0;
#endif
WmProtocolsAtom = _intVal(_INST(protocolsAtom));
WmDeleteWindowAtom = _intVal(_INST(deleteWindowAtom));
#ifdef USE_SAVEYOURSELF_ATOM
WmSaveYourselfAtom = _intVal(_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
XChangeProperty(dpy, newWindow, WmProtocolsAtom, XA_ATOM,
32, PropModeReplace, (unsigned char *)atoms, atomCount);
}
END_INTERRUPTSBLOCKED
windowId = MKOBJ(newWindow);
%}
.
self addKnownView:aView withId:windowId.
^ windowId
!
destroyView:aView withId:aWindowId
%{
if (__isSmallInteger(aWindowId)) {
BEGIN_INTERRUPTSBLOCKED
XDestroyWindow(myDpy, _WindowVal(aWindowId));
END_INTERRUPTSBLOCKED
}
%}
.
self removeKnownView:aView
!
destroyGC:aGCId
%{ /* NOCONTEXT */
if (__isSmallInteger(aGCId)) {
BEGIN_INTERRUPTSBLOCKED
XFreeGC(myDpy, _GCVal(aGCId));
END_INTERRUPTSBLOCKED
RETURN ( self );
}
%}.
self primitiveFailed
!
gcFor:aDrawableId
%{ /* NOCONTEXT */
int screen = _intVal(_INST(screen));
GC gc;
if (__isSmallInteger(aDrawableId)) {
BEGIN_INTERRUPTSBLOCKED
gc = XCreateGC(myDpy, (Drawable)_WindowVal(aDrawableId),
0L, (XGCValues *)0);
END_INTERRUPTSBLOCKED
RETURN ( gc ? MKOBJ(gc) : nil );
}
%}.
self primitiveFailed.
^ nil
!
dpsContextFor:aDrawableId and:aGCId
%{ /* NOCONTEXT */
#ifdef XXDPS
int screen = _intVal(_INST(screen));
DPSContext dps;
int height;
if (__bothSmallInteger(aDrawableId, aGCId)) {
BEGIN_INTERRUPTSBLOCKED
dps = XDPSCreateContext(myDpy, (Drawable)_WindowVal(aDrawableId),
_GCVal(aGCId),
0, height, 0, colormap, NULL, 0,
XDPSDefaultTextBackstop,
XDPSDefaultErrorProc,
NULL);
END_INTERRUPTSBLOCKED
RETURN ( dps ? MKOBJ(dps) : nil );
}
#endif
%}
.
self primitiveFailed.
^ nil
! !
!XWorkstation methodsFor:'resources'!
getResource:name class:cls
%{
char *rslt;
if ((__isString(name) || __isSymbol(name))
&& (__isString(cls) || __isSymbol(cls))) {
BEGIN_INTERRUPTSBLOCKED
rslt = XGetDefault(myDpy, (char *)_stringVal(cls),
(char *)_stringVal(name));
END_INTERRUPTSBLOCKED
RETURN (rslt ? _MKSTRING(rslt, __context) : nil );
}
%}
.
self primitiveFailed.
^ nil
! !
!XWorkstation methodsFor:'selections'!
setTextProperty:propertyID value:aString for:aWindowID
^ self setProperty:propertyID type:(self atomIDOf:'STRING') value:aString for:aWindowID
!
setObjectProperty:propertyID value:anObject for:aWindowID
|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' create:true) value:(s contents) for:aWindowID
!
setProperty:propertyID type:typeID value:anObject for:aWindowID
%{
Display *dpy = myDpy;
Atom prop, type;
Window window;
if (__bothSmallInteger(propertyID, typeID)
&& (__isString(anObject)
|| __isSymbol(anObject)
|| __isByteArray(anObject))) {
prop = _AtomVal(propertyID);
type = _AtomVal(typeID);
if (__isSmallInteger(aWindowID)) {
window = _WindowVal(aWindowID);
} else {
window = DefaultRootWindow(dpy);
}
if (__isByteArray(anObject)) {
XChangeProperty(dpy, window, prop, type, 8,
PropModeReplace,
_ByteArrayInstPtr(anObject)->ba_element,
_byteArraySize(anObject));
} else {
XChangeProperty(dpy, window, prop, XA_STRING, 8,
PropModeReplace,
_stringVal(anObject),
strlen(_stringVal(anObject)));
}
RETURN (true);
}
%}.
self primitiveFailed.
^ false
!
getTextProperty:propertyID from:aWindowID
self getProperty:propertyID from:aWindowID into:[:type :value |
type == (self atomIDOf:'STRING') ifTrue:[
^ value
]
].
^ nil
!
getObjectProperty:propertyID from:aWindowID
self getProperty:propertyID from:aWindowID into:[:type :value |
type == (self atomIDOf:'STRING') ifTrue:[
^ value
].
(value isMemberOf:ByteArray) ifTrue:[
^ (Object readBinaryFrom:(ReadStream on:value) onError:[nil])
]
].
^ nil
!
getProperty:propertyID from:aWindowID into:aTwoArgBlock
|val typeID cls|
cls := ByteArray.
%{
Display *dpy = myDpy;
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;
extern OBJ new();
# define PROP_SIZE 2048
if (__isSmallInteger(propertyID)) {
property = (int)(_AtomVal(propertyID));
if (__isSmallInteger(aWindowID)) {
window = _WindowVal(aWindowID);
} else {
window = DefaultRootWindow(dpy);
}
nread = 0;
cp = 0;
/*
fprintf(stderr, "getProperty: ");
*/
do {
if (XGetWindowProperty(dpy,window,property,nread/4,PROP_SIZE,False,
AnyPropertyType,&actual_type,&actual_format,
&nitems,&bytes_after,(unsigned char **)&data)
!= Success) {
ok = 0;
break;
}
typeID = MKOBJ(actual_type);
if (! cp) {
cp = cp2 = (char *)malloc(nitems+1);
} else {
cp = (char *)realloc(cp, nread + nitems + 1);
cp2 = cp + nread;
}
if (! cp) 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(cp, __context);
} else {
val = new(nread + OHDR_SIZE, __context);
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
!
getSelectionOwnerOf:selectionID
%{
Display *dpy = myDpy;
Atom selection;
Window window;
if (__isSmallInteger(selectionID)) {
window = XGetSelectionOwner(dpy, _AtomVal(selectionID));
if (window == None) {
RETURN (nil);
}
RETURN (MKOBJ(window));
}
%}.
self primitiveFailed.
^ nil
!
setSelectionOwner:aWindowId of:selectionID
%{
Display *dpy = myDpy;
if (__bothSmallInteger(aWindowId, selectionID)) {
XSetSelectionOwner(dpy, _AtomVal(selectionID), _WindowVal(aWindowId), CurrentTime);
if (XGetSelectionOwner(dpy, _AtomVal(selectionID)) != _WindowVal(aWindowId)) {
RETURN (false);
}
RETURN (true);
}
%}
.
self primitiveFailed.
^ nil
!
requestObjectSelection:selectionID property:propertyID for:aWindowId
"ask the server to send us the selection - the view with ID aWindowID
will later receive a SelectionNotify event for it."
^ self requestSelection:selectionID
property:propertyID
type:(self atomIDOf:'ST_OBJECT')
for:aWindowId
!
requestTextSelection:selectionID property:propertyID for:aWindowId
"ask the server to send us the selection - the view with ID aWindowID
will later receive a SelectionNotify event for it."
^ self requestSelection:selectionID
property:propertyID
type:(self atomIDOf:'STRING')
for:aWindowId
!
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."
%{
Display *dpy = myDpy;
Atom sel_prop;
char *cp;
if (_isSmallInteger(aWindowId)
&& __bothSmallInteger(typeID, selectionID)) {
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 primitiveFailed.
^ false
"
Display requestSelection:(Display atomIDOf:'PRIMARY')
property:(Display atomIDOf:'VT_SELECTION')
for:0
"
!
atomIDOf:aStringOrSymbol
^ self atomIDOf:aStringOrSymbol create:false
!
atomIDOf:aStringOrSymbol create:create
%{ /* NOCONTEXT */
Atom prop;
if (__isString(aStringOrSymbol)
|| __isSymbol(aStringOrSymbol)) {
prop = XInternAtom(myDpy, _stringVal(aStringOrSymbol), (create == true) ? False : True);
if (prop == None) {
RETURN (nil);
}
RETURN ( MKOBJ(prop) );
}
%}.
self primitiveFailed.
^ nil
"
Display atomIDOf:'VT_SELECTION' create:false
Display atomIDOf:'CUT_BUFFER0' create:false
Display atomIDOf:'STRING' create:false
Display atomIDOf:'PRIMARY' create:false
"
!
sendSelection:something property:propertyID target:targetID to:requestorID
"send aString back from a SelectionRequest"
%{
Display *dpy = myDpy;
if (__bothSmallInteger(propertyID, requestorID)
&& __isSmallInteger(targetID)
&& (__isString(something) || __isByteArray(something))) {
XEvent ev;
int requestor = (int)(_AtomVal(requestorID));
int property = (int)(_AtomVal(propertyID));
int target = (int)(_AtomVal(targetID));
unsigned char *p;
int sz;
ev.xselection.type = SelectionNotify;
ev.xselection.selection = XA_PRIMARY;
ev.xselection.target = target /* XA_STRING */;
ev.xselection.requestor = requestor;
ev.xselection.time = CurrentTime;
if (__isString(something)) {
p = (unsigned char *) _stringVal(something);
sz = strlen(p);
} else {
p = _ByteArrayInstPtr(something)->ba_element;
sz = _byteArraySize(something);
}
XChangeProperty(dpy, requestor, property, target, 8, PropModeReplace,
p, sz);
ev.xselection.property = property;
/*
printf("sending SelectionNotify prop=%x target=%x requestor=%x\n",
ev.xselection.property,
ev.xselection.target,
ev.xselection.requestor);
*/
XSendEvent(dpy, requestor, False, 0 , &ev);
RETURN (self )
}
%}
.
self primitiveFailed
!
getTextSelectionFor:drawableId
"get the text selection - either immediate, or asynchronous.
Returns nil, if async request is on its way"
|primary cutBuffer selProp sel|
primary := self atomIDOf:'PRIMARY'.
(self getSelectionOwnerOf:primary) isNil ifTrue:[
"no primary selection - use cut buffer"
cutBuffer := self atomIDOf:'CUT_BUFFER0'.
sel := self getTextProperty:cutBuffer from:nil.
^ sel
].
selProp := self atomIDOf:'VT_SELECTION'.
self requestTextSelection:primary property:selProp for:drawableId.
^ nil
!
getSelectionFor:drawableId
"get the object selection - either immediate, or asynchronous.
Returns nil, if async request is on its way"
|primary cutBuffer selProp sel|
primary := self atomIDOf:'PRIMARY'.
(self getSelectionOwnerOf:primary) isNil ifTrue:[
"no primary selection - use cut buffer"
cutBuffer := self atomIDOf:'ST_CUT_BUFFER0' create:true.
sel := self getObjectProperty:cutBuffer from:nil.
^ sel
].
selProp := self atomIDOf:'ST_SELECTION' create:true.
self requestObjectSelection:primary property:selProp for:drawableId.
^ nil
!
setTextSelection:aString owner:aWindowId
"set the text selection, and make aWindowId be the owner.
This can be used by any other X application."
|primary cutBuffer|
primary := self atomIDOf:'PRIMARY'.
(self setSelectionOwner:aWindowId of:primary) ifFalse:[
'ownerchange failed' errorPrintNL.
].
cutBuffer := self atomIDOf:'CUT_BUFFER0'.
^ self setTextProperty:cutBuffer value:aString for:nil
!
setSelection:anObject owner:aWindowId
"set the object selection, and make aWindowId be the owner.
This can be used by other Smalltalk(X) applications only."
|primary cutBuffer|
primary := self atomIDOf:'PRIMARY'.
(self setSelectionOwner:aWindowId of:primary) ifFalse:[
^ false
].
"/ cutBuffer := self atomIDOf:'ST_CUT_BUFFER0' create:true.
"/ ^ self setObjectProperty:cutBuffer value:anObject for:nil
^ true
! !
!XWorkstation methodsFor:'font stuff'!
decomposeXFontName:aString into:aBlock
"extract family, face, style and size from an
X-font name
(-brand-family-face-style-moreStyle--height-size-res-res-?-??-coding);
evaluate aBlock with these"
|origin family face style moreStyle skip fheight size
resX resY x1 x2 coding start end |
aString isNil ifTrue:[^ false].
(aString startsWith:'-') ifFalse:[
"
take care for ill-named fonts (i.e. pre Rel4 fonts)
"
('*-*-[0-9]*' match:aString) ifTrue:[
end := aString indexOf:$- startingAt:1.
family := aString copyFrom:1 to:(end - 1).
start := end + 1.
end := aString indexOf:$- startingAt:start.
style := aString copyFrom:start to:(end - 1).
start := end + 1.
size := aString copyFrom:start.
size := (Number readFromString:size).
aBlock value:family value:nil value:style value:size value:nil.
^ true.
].
('*-[0-9]*' match:aString) ifTrue:[
"
something like lucidasans-24
"
end := aString indexOf:$- startingAt:1.
family := aString copyFrom:1 to:(end - 1).
start := end + 1.
size := aString copyFrom:start.
size := (Number readFromString:size).
aBlock value:family value:nil value:nil value:size value:nil.
^ true.
].
aBlock value:aString value:nil value:nil value:nil value:nil.
^ true.
].
end := aString indexOf:$- startingAt:2.
(end == 0) ifTrue:[^ false].
origin := aString copyFrom:2 to:(end - 1).
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
family := aString copyFrom:start to:(end - 1).
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
face := aString copyFrom:start to:(end - 1).
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
style := aString copyFrom:start to:(end - 1).
(style = 'o') ifTrue:[
style := 'oblique'
] ifFalse:[
(style = 'i') ifTrue:[
style := 'italic'
] ifFalse:[
(style = 'r') ifTrue:[
style := 'roman'
]
]
].
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
moreStyle := aString copyFrom:start to:(end - 1).
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
skip := aString copyFrom:start to:(end - 1).
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
fheight := aString copyFrom:start to:(end - 1).
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
size := aString copyFrom:start to:(end - 1).
size := (Number readFromString:size) / 10.
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
resX := aString copyFrom:start to:(end - 1).
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
resY := aString copyFrom:start to:(end - 1).
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
x1 := aString copyFrom:start to:(end - 1).
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
x2 := aString copyFrom:start to:(end - 1).
start := end + 1.
end := aString indexOf:$- startingAt:start.
(end == 0) ifTrue:[^ false].
coding := aString copyFrom:start to:(end - 1).
aBlock value:family value:face value:style value:size value:coding.
^ true
!
listOfAvailableFonts
"return a list with all available fonts on this display.
Since this takes a long time, keep the result of the query for the
next time. The elements of the returned collection are instances of
FontDescription."
|stream aName fntDescr|
listOfXFonts isNil ifTrue:[
stream := PipeStream readingFrom:'xlsfonts ''*'''.
stream isNil ifTrue:[^ nil].
listOfXFonts := OrderedCollection new.
[stream atEnd] whileFalse:[
aName := stream nextLine.
aName notNil ifTrue:[
self decomposeXFontName:aName into:
[:family :face :style :size :coding |
fntDescr := FontDescription
family:family
face:face
style:style
size:size
encoding:coding.
listOfXFonts add:fntDescr
]
]
].
stream close.
"if xlsfont is broken ... (hey sco)"
(listOfXFonts size == 0) ifTrue:[
listOfXFonts := nil
] ifFalse:[
listOfXFonts sort:[:a :b | a family < b family].
]
].
^ listOfXFonts
"Display listOfAvailableFonts"
!
getFontWithFamily:familyString face:faceString
style:styleString size:sizeArg encoding:encodingSym
"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."
|theSize theName theId xlatedStyle enc|
"special: if face is nil, allow access to X-fonts"
faceString isNil ifTrue:[
sizeArg notNil ifTrue:[
theName := familyString , '-' , sizeArg printString
] ifFalse:[
theName := familyString
].
theId := self createFontFor:theName.
theId isNil ifTrue:[
theId := self getDefaultFont
].
^ theId
].
xlatedStyle := styleString.
"oblique is named italic in times font"
((familyString = 'Times') or:[familyString = 'times']) ifTrue:[
((styleString = 'Oblique') or:[styleString = 'oblique']) ifTrue:[
xlatedStyle := 'italic'
]
].
(xlatedStyle = 'italic') ifTrue:[
xlatedStyle := 'i'
] ifFalse:[
(xlatedStyle = 'roman') ifTrue:[
xlatedStyle := 'r'
] ifFalse:[
(xlatedStyle = 'oblique') ifTrue:[
xlatedStyle := 'o'
]
]
].
theId := nil.
theSize := sizeArg.
[theId isNil] whileTrue:[
"this works only on Release >= 3 - X-servers"
enc := encodingSym.
enc isNil ifTrue:[
enc := '*'
].
theName := ('-*-' , familyString ,
'-' , faceString ,
'-' , xlatedStyle , '-*-*-*-'
, theSize printString , '0-*-*-*-*-'
, enc , '-*').
"
Transcript showCr:theName; endEntry.
"
theId := self createFontFor:theName.
theId isNil ifTrue:[
"could not get the font - try next smaller one"
theSize := theSize - 1.
(theSize < (sizeArg // 2)) ifTrue:[
"thats too much - give up"
^ self getDefaultFont
"^ nil"
]
]
].
(theSize ~~ sizeArg) ifTrue:[
Transcript show:'next smaller font: '.
Transcript showCr:theName
].
^ theId
!
getFontWithFoundry:foundry family:family weight:weight
slant:slant 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 wntry."
|theName|
"this works only on 'Release >= 3' - X-servers"
theName := ('-' , foundry ,
'-' , family ,
'-' , weight ,
'-' , slant ,
'-*-*-*' ,
'-' , size printString , '0' ,
'-*-*-*-*' ,
'-' , registry ,
'-' , encoding).
Transcript showCr:theName; endEntry.
^ self createFontFor:theName.
"
Display getFontWithFoundry:'*'
family:'courier'
weight:'medium'
slant:'r'
size:13
registry:'iso8859'
encoding:'*'
"
!
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)"
%{ /* NOCONTEXT */
XFontStruct *newFont;
if (__isString(aFontName) || __isSymbol(aFontName)) {
BEGIN_INTERRUPTSBLOCKED
newFont = XLoadQueryFont(myDpy, (char *)_stringVal(aFontName));
END_INTERRUPTSBLOCKED
RETURN ( newFont ? MKOBJ(newFont) : nil );
}
%}
.
self primitiveFailed.
^ nil
!
getDefaultFont
"return a default font id - used when class Font cannot
find anything usable"
^ self createFontFor:'fixed'
!
releaseFont:aFontId
%{ /* NOCONTEXT */
XFontStruct *f;
if (__isSmallInteger(aFontId)) {
f = _FontVal(aFontId);
BEGIN_INTERRUPTSBLOCKED
XFreeFont(myDpy, f);
END_INTERRUPTSBLOCKED
RETURN ( self );
}
%}
.
self primitiveFailed
!
ascentOf:aFontId
%{ /* NOCONTEXT */
XFontStruct *f;
if (__isSmallInteger(aFontId)) {
f = _FontVal(aFontId);
RETURN ( _MKSMALLINT(f->ascent) );
}
%}
.
self primitiveFailed.
^ nil
!
descentOf:aFontId
%{ /* NOCONTEXT */
XFontStruct *f;
if (__isSmallInteger(aFontId)) {
f = _FontVal(aFontId);
RETURN ( _MKSMALLINT(f->descent) );
}
%}
.
self primitiveFailed.
^ nil
!
minWidthOfFont:aFontId
%{ /* NOCONTEXT */
XFontStruct *f;
if (__isSmallInteger(aFontId)) {
f = _FontVal(aFontId);
RETURN ( _MKSMALLINT(f->min_bounds.width) );
}
%}
.
self primitiveFailed.
^ nil
!
maxWidthOfFont:aFontId
%{ /* NOCONTEXT */
XFontStruct *f;
if (__isSmallInteger(aFontId)) {
f = _FontVal(aFontId);
RETURN ( _MKSMALLINT(f->max_bounds.width) );
}
%}
.
self primitiveFailed.
^ nil
!
widthOf:aString inFont:aFontId
%{ /* NOCONTEXT */
XFontStruct *f;
char *cp;
int len, n;
#ifdef TWOBYTESTRINGS
extern OBJ TwoByteString;
#endif
if (__isSmallInteger(aFontId)) {
f = _FontVal(aFontId);
if (__isString(aString) || __isSymbol(aString)) {
n = _stringSize(aString);
cp = (char *)_stringVal(aString);
BEGIN_INTERRUPTSBLOCKED
len = XTextWidth(f, cp, n);
END_INTERRUPTSBLOCKED
RETURN ( _MKSMALLINT(len) );
}
#ifdef TWOBYTESTRINGS
if (_Class(aString) == TwoByteString) {
n = _byteArraySize(aString) / 2;
cp = (char *) _stringVal(aString);
BEGIN_INTERRUPTSBLOCKED
len = XTextWidth16(f, (XChar2b *)cp, n);
END_INTERRUPTSBLOCKED
RETURN ( _MKSMALLINT(len) );
}
#endif
}
%}
.
self primitiveFailed.
^ nil
!
widthOf:aString from:index1 to:index2 inFont:aFontId
%{ /* NOCONTEXT */
XFontStruct *f;
char *cp;
int len, n, i1, i2;
#ifdef TWOBYTESTRINGS
extern OBJ TwoByteString;
#endif
if (__bothSmallInteger(index1, index2)
&& __isSmallInteger(aFontId)) {
f = _FontVal(aFontId);
i1 = _intVal(index1) - 1;
i2 = _intVal(index2) - 1;
if (__isString(aString) || __isSymbol(aString)) {
cp = (char *) _stringVal(aString);
n = _stringSize(aString);
if ((i1 >= 0) && (i2 >= i1) && (i2 < n)) {
cp += i1;
BEGIN_INTERRUPTSBLOCKED
len = XTextWidth(f, cp, i2 - i1 + 1);
END_INTERRUPTSBLOCKED
RETURN ( _MKSMALLINT(len) );
}
}
#ifdef TWOBYTESTRINGS
if (_Class(aString) == TwoByteString) {
cp = (char *) _stringVal(aString);
n = _byteArraySize(aString) / 2;
if ((i1 >= 0) && (i2 >= i1) && (i2 < n)) {
cp += (i1 * 2);
BEGIN_INTERRUPTSBLOCKED
len = XTextWidth16(f, (XChar2b *)cp, i2 - i1 + 1);
END_INTERRUPTSBLOCKED
RETURN ( _MKSMALLINT(len) );
}
}
#endif
}
%}
.
self primitiveFailed.
^ nil
!
sizesInFamily:aFamilyName face:aFaceName style:aStyleName
"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.
(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)
].
^ sizes
"
Display sizesInFamily:'courier' face:'bold' style:'roman'
"
! !
!XWorkstation methodsFor:'cursor stuff'!
destroyCursor:aCursorId
%{ /* NOCONTEXT */
if (__isSmallInteger(aCursorId)) {
BEGIN_INTERRUPTSBLOCKED
XFreeCursor(myDpy, _CursorVal(aCursorId));
END_INTERRUPTSBLOCKED
RETURN ( self );
}
%}
.
self primitiveFailed
!
createCursorSourceForm:sourceForm maskForm:maskForm hotX:hx hotY:hy
"create a cursor given 2 bitmaps (source, mask) and a hotspot"
|id sourceId maskId|
sourceId := sourceForm id.
maskId := maskForm id.
%{
Cursor newCursor;
XColor fgColor, bgColor;
if (__bothSmallInteger(sourceId, 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;
BEGIN_INTERRUPTSBLOCKED
newCursor = XCreatePixmapCursor(myDpy,
_PixmapVal(sourceId),
_PixmapVal(maskId),
&fgColor, &bgColor, _intVal(hx), _intVal(hy));
END_INTERRUPTSBLOCKED
if (newCursor != (Cursor)0)
id = MKOBJ(newCursor);
}
%}
.
^ id
!
shapeNumberFromSymbol:shape
"given a shape-symbol, return the corresponding cursor-number"
"this is pure X-knowlegde - but you may easily add more"
(shape == #upLeftArrow) ifTrue:[ ^ 132 ].
(shape == #upRightHand) ifTrue:[ ^ 58 ].
(shape == #upDownArrow) ifTrue:[ ^ 116 ].
(shape == #leftRightArrow) ifTrue:[ ^ 108 ].
(shape == #upLimitArrow) ifTrue:[ ^ 138 ].
(shape == #downLimitArrow) ifTrue:[ ^ 16 ].
(shape == #leftLimitArrow) ifTrue:[ ^ 70 ].
(shape == #rightLimitArrow) ifTrue:[ ^ 96 ].
(shape == #text) ifTrue:[ ^ 152 ].
(shape == #upRightArrow) ifTrue:[ ^ 44 ].
(shape == #leftHand) ifTrue:[ ^ 60 ].
(shape == #questionMark) ifTrue:[ ^ 92 ].
(shape == #cross) ifTrue:[ ^ 0 ].
(shape == #wait) ifTrue:[ ^ 150 ].
(shape == #crossHair) ifTrue:[ ^ 130 ].
((shape == #origin)
or:[shape == #topLeft]) ifTrue:[ ^ 144 ].
((shape == #corner)
or:[shape == #bottomRight]) ifTrue:[ ^ 78 ].
(shape == #topRight) ifTrue:[ ^ 148 ].
(shape == #bottomLeft) ifTrue:[ ^ 76 ].
(shape == #square) ifTrue:[ ^ 40 ].
(shape == #fourWay) ifTrue:[ ^ 52 ].
(shape == #crossCursor) ifTrue:[ ^ 0 ].
('invalid cursorShape:' , shape printString) errorPrintNewline.
^ 0
!
createCursorShape:aShape
"create a cursor given a shape-symbol"
|number id|
number := self shapeNumberFromSymbol:aShape.
%{
Cursor newCursor;
if (__isSmallInteger(number)) {
BEGIN_INTERRUPTSBLOCKED
newCursor = XCreateFontCursor(myDpy, _intVal(number));
END_INTERRUPTSBLOCKED
if (newCursor != (Cursor)0)
id = MKOBJ(newCursor);
}
%}
.
^ id
!
colorCursor:aCursorId foreground:fgColor background:bgColor
"change a cursors colors"
|fgR fgG fgB bgR bgG bgB|
fgR := fgColor red.
fgG := fgColor green.
fgB := fgColor blue.
bgR := bgColor red.
bgG := bgColor green.
bgB := bgColor blue.
fgR := self percentToXColorValue:fgR.
fgG := self percentToXColorValue:fgG.
fgB := self percentToXColorValue:fgB.
bgR := self percentToXColorValue:bgR.
bgG := self percentToXColorValue:bgG.
bgB := self percentToXColorValue:bgB.
%{
XColor fgcolor, bgcolor;
if (__bothSmallInteger(aCursorId, fgR)
&& __bothSmallInteger(fgG, fgB)
&& __bothSmallInteger(bgR, bgG)
&& __isSmallInteger(bgB)) {
fgcolor.red = _intVal(fgR);
fgcolor.green= _intVal(fgG);
fgcolor.blue = _intVal(fgB);
bgcolor.red = _intVal(bgR);
bgcolor.green= _intVal(bgG);
bgcolor.blue = _intVal(bgB);
BEGIN_INTERRUPTSBLOCKED
XRecolorCursor(myDpy, _CursorVal(aCursorId), &fgcolor, &bgcolor);
END_INTERRUPTSBLOCKED
RETURN ( self );
}
%}
.
self primitiveFailed
! !
!XWorkstation methodsFor:'grabbing '!
grabKeyboardIn:aWindowId
"grab the keyboard"
%{ /* NOCONTEXT */
int result, ok;
if (__isSmallInteger(aWindowId)) {
BEGIN_INTERRUPTSBLOCKED
result = XGrabKeyboard(myDpy,
_WindowVal(aWindowId),
True /* False */,
GrabModeAsync,
GrabModeAsync,
CurrentTime);
END_INTERRUPTSBLOCKED
ok = 0;
switch(result) {
case AlreadyGrabbed:
printf("XWORKSTAT: grab keyboard: AlreadyGrabbed\n");
break;
case GrabNotViewable:
printf("XWORKSTAT: grab keyboard: GrabNotViewable\n");
break;
case GrabInvalidTime:
printf("XWORKSTAT: grab keyboard: InvalidTime\n");
break;
case GrabFrozen:
printf("XWORKSTAT: grab keyboard: Frozen\n");
break;
default:
ok = 1;
break;
}
if (! ok) {
XUngrabKeyboard(myDpy, CurrentTime);
RETURN (false);
}
RETURN ( true );
}
%}
.
self primitiveFailed
!
ungrabKeyboard
"release the keyboard"
%{ /* NOCONTEXT */
BEGIN_INTERRUPTSBLOCKED
XUngrabKeyboard(myDpy, CurrentTime);
XSync(myDpy, 0);
END_INTERRUPTSBLOCKED
%}.
activeKeyboardGrab := nil
!
grabPointerIn:aWindowId withCursor:aCursorId pointerMode:pMode keyboardMode:kMode confineTo:confineId
"grap the pointer - return true if ok"
%{ /* NOCONTEXT */
int result, ok;
Window confineWin;
Cursor curs;
int pointer_mode, keyboard_mode;
if (__isSmallInteger(aWindowId)) {
if (__isSmallInteger(confineId))
confineWin = _WindowVal(confineId);
else
confineWin = (Window) None;
if (__isSmallInteger(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;
BEGIN_INTERRUPTSBLOCKED
result = XGrabPointer(myDpy,
_WindowVal(aWindowId),
False,
ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
pointer_mode, keyboard_mode,
confineWin,
curs,
CurrentTime);
END_INTERRUPTSBLOCKED
ok = 0;
switch (result) {
case AlreadyGrabbed:
printf("XWORKSTAT: grab pointer: AlreadyGrabbed\n");
break;
case GrabNotViewable:
printf("XWORKSTAT: grab pointer: GrabNotViewable\n");
break;
case GrabInvalidTime:
printf("XWORKSTAT: grab pointer: InvalidTime\n");
break;
case GrabFrozen:
printf("XWORKSTAT: grab pointer: Frozen\n");
break;
default:
ok = 1;
break;
}
if (! ok) {
XUngrabPointer(myDpy, CurrentTime);
RETURN (false);
}
RETURN ( true );
}
%}
.
self primitiveFailed
!
ungrabPointer
"release the pointer"
%{ /* NOCONTEXT */
BEGIN_INTERRUPTSBLOCKED
XUngrabPointer(myDpy, CurrentTime);
XSync(myDpy, 0);
END_INTERRUPTSBLOCKED
%}.
activePointerGrab := nil
!
allowEvents:mode
%{ /* NOCONTEXT */
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) {
BEGIN_INTERRUPTSBLOCKED
XAllowEvents(myDpy, _mode, CurrentTime);
END_INTERRUPTSBLOCKED
RETURN (self);
}
%}
.
self primitiveFailed
! !
!XWorkstation methodsFor:'pointer queries '!
rootPositionOfLastEvent
"return the position in root-window coordinates
of the last button, key or pointer event"
^ eventRootX @ eventRootY
!
pointerPosition
"return the current pointer position in root-window coordinates"
|xpos ypos|
%{
Display *dpy = myDpy;
Window w;
int screen = _intVal(_INST(screen));
Window rootRet, childRet;
int rootX, rootY, winX, winY;
unsigned int mask;
BEGIN_INTERRUPTSBLOCKED
#ifdef VIRTUAL_ROOT
w = getRootWindow(myDpy, screen);
#else
w = RootWindow(dpy, screen);
#endif
XQueryPointer(dpy, w, &rootRet, &childRet,
&rootX, &rootY,
&winX, &winY,
&mask);
xpos = _MKSMALLINT(rootX);
ypos = _MKSMALLINT(rootY);
END_INTERRUPTSBLOCKED
%}
.
^ xpos @ ypos
!
buttonStates
"return an integer representing the state of the pointer buttons;
a one-bit in positions 0.. represent a pressed button"
%{ /* NOCONTEXT*/
Display *dpy = myDpy;
Window w;
int screen = _intVal(_INST(screen));
Window rootRet, childRet;
int rootX, rootY, winX, winY;
unsigned int mask;
BEGIN_INTERRUPTSBLOCKED
#ifdef VIRTUAL_ROOT
w = getRootWindow(myDpy, screen);
#else
w = RootWindow(dpy, screen);
#endif
XQueryPointer(dpy, w, &rootRet, &childRet,
&rootX, &rootY,
&winX, &winY,
&mask);
END_INTERRUPTSBLOCKED
RETURN (_MKSMALLINT(mask));
%}
!
leftButtonPressed
"return true, if the left button is currently pressed"
^ (self buttonStates bitAnd:256) ~~ 0
!
middleButtonPressed
"return true, if the middle button is currently pressed.
Notice, that there are systems with only a single button."
^ (self buttonStates bitAnd:512) ~~ 0
!
rightButtonPressed
"return true, if the left button is currently pressed.
Notice, that there are systems with only one or two buttons."
^ (self buttonStates bitAnd:1024) ~~ 0
! !
!XWorkstation methodsFor:'color stuff'!
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) 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
!
freeColor:colorIndex
"free a display color when its no longer needed"
%{ /* NOCONTEXT */
Display *dpy = myDpy;
unsigned long color;
int screen = _intVal(_INST(screen));
if (__isSmallInteger(colorIndex)) {
color = (long) _intVal(colorIndex);
BEGIN_INTERRUPTSBLOCKED
XFreeColors(dpy, DefaultColormap(dpy, screen), &color, 1, 0L);
END_INTERRUPTSBLOCKED
RETURN ( self );
}
%}
.
self primitiveFailed
!
percentToXColorValue: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
!
colorRed:redVal green:greenVal blue:blueVal
"allocate a color with rgb values (0..100) - return index"
|r g b|
r := self percentToXColorValue:redVal.
g := self percentToXColorValue:greenVal.
b := self percentToXColorValue:blueVal.
%{
Display *dpy = myDpy;
XColor ecolor;
int screen = _intVal(_INST(screen));
Status ok;
if (__bothSmallInteger(r, g) && __isSmallInteger(b)) {
ecolor.red = _intVal(r);
ecolor.green= _intVal(g);
ecolor.blue = _intVal(b);
BEGIN_INTERRUPTSBLOCKED
ok = XAllocColor(dpy, DefaultColormap(dpy, screen), &ecolor);
END_INTERRUPTSBLOCKED
if (! ok) {
RETURN ( nil );
}
RETURN ( _MKSMALLINT(ecolor.pixel) );
}
%}
.
self primitiveFailed.
^ nil
!
colorNamed:aString
"allocate a color with color name - return index.
Dont use this method, colornames are mostly X specific"
%{ /* NOCONTEXT */
char *colorname;
Display *dpy = myDpy;
XColor scolor, ecolor;
int screen =_intVal(_INST(screen));
Status ok;
if (__isString(aString) || __isSymbol(aString)) {
colorname = (char *)_stringVal(aString);
BEGIN_INTERRUPTSBLOCKED
ok = XParseColor(dpy, DefaultColormap(dpy, screen), colorname, &ecolor);
if (ok) {
ok = XAllocColor(dpy, DefaultColormap(dpy, screen), &ecolor);
}
END_INTERRUPTSBLOCKED
if (! ok) {
RETURN ( nil );
}
RETURN ( _MKSMALLINT(ecolor.pixel) );
}
%}
.
self primitiveFailed.
^ nil
!
colorCell
"allocate a color cell - return index.
This method will return nil for StaticGrey and StaticGrey displays."
%{ /* NOCONTEXT */
Display *dpy = myDpy;
int screen = _intVal(_INST(screen));
XColor color;
unsigned long dummy;
Status ok;
BEGIN_INTERRUPTSBLOCKED
ok = XAllocColorCells(dpy, DefaultColormap(dpy, screen), (Bool)0,
&dummy, 0, &color.pixel, 1);
END_INTERRUPTSBLOCKED
if (ok) {
RETURN ( _MKSMALLINT(color.pixel) );
}
%}
.
^ nil
!
setColor:index red:redVal green:greenVal blue:blueVal
"change color in map at:index to rgb (0..100).
This method is a noop for StaticGrey and StaticGrey displays."
%{ /* NOCONTEXT */
char *colorname;
Display *dpy = myDpy;
XColor color;
int screen = _intVal(_INST(screen));
int r, g, b;
int ok = 1;
if (__isSmallInteger(redVal))
r = 0xFFFF * _intVal(redVal) / 100;
else if (__isFloat(redVal))
r = 0xFFFF * (int)(_floatVal(redVal)) / 100;
else ok = 0;
if (__isSmallInteger(greenVal))
g = 0xFFFF * _intVal(greenVal) / 100;
else if (__isFloat(greenVal))
g = 0xFFFF * (int)(_floatVal(greenVal)) / 100;
else ok = 0;
if (__isSmallInteger(blueVal))
b = 0xFFFF * _intVal(blueVal) / 100;
else if (__isFloat(blueVal))
b = 0xFFFF * (int)(_floatVal(blueVal)) / 100;
else ok = 0;
if (__isSmallInteger(index) && ok) {
color.pixel = _intVal(index);
color.red = r;
color.green = g;
color.blue = b;
color.flags = DoRed | DoGreen | DoBlue;
BEGIN_INTERRUPTSBLOCKED
XStoreColor(dpy, DefaultColormap(dpy, screen), &color);
END_INTERRUPTSBLOCKED
RETURN ( self );
}
%}
.
self primitiveFailed
!
getRGBFromName:colorName into:aBlock
"get rgb components (0..100) of color named colorName,
and evaluate the 3-arg block, aBlock with them"
|r g b|
%{
Display *dpy = myDpy;
int screen = _intVal(_INST(screen));
XColor color;
double fr, fg, fb;
double floor();
if (__isString(colorName) || __isSymbol(colorName)) {
BEGIN_INTERRUPTSBLOCKED
if (XParseColor(dpy, DefaultColormap(dpy, screen),
(char *)_stringVal(colorName), &color)) {
/*
* scale to 0..100 and round to the first decimal
*/
fr = floor( ((((double)color.red) * 1000.0) / 0xFFFF) + 0.5) / 10.0;
fg = floor( ((((double)color.green) * 1000.0) / 0xFFFF) + 0.5) / 10.0;
fb = floor( ((((double)color.blue) * 1000.0) / 0xFFFF) + 0.5) / 10.0;
r = _MKFLOAT(fr, __context);
g = _MKFLOAT(fg, __context);
b = _MKFLOAT(fb, __context);
}
END_INTERRUPTSBLOCKED
}
%}
.
aBlock value:r value:g value:b
!
getRGBFrom:index into:aBlock
"get rgb components (0..100) of color in map at:index,
and evaluate the 3-arg block, aBlock with them"
|r g b|
%{
Display *dpy = myDpy;
int screen = _intVal(_INST(screen));
XColor color;
double fr, fg, fb;
double floor();
int bits, scale, shift;
if (__isSmallInteger(index)) {
color.pixel = _intVal(index);
BEGIN_INTERRUPTSBLOCKED
XQueryColor(dpy, DefaultColormap(dpy, screen), &color);
END_INTERRUPTSBLOCKED
/* scale to 0..100 and round to the first decimal */
/*
* 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;
fr = floor( ( ((double)(color.red>>shift) * 1000.0) / scale) + 0.5) / 10.0;
fg = floor( ( ((double)(color.green>>shift) * 1000.0) / scale) + 0.5) / 10.0;
fb = floor( ( ((double)(color.blue>>shift) * 1000.0) / scale) + 0.5) / 10.0;
r = _MKFLOAT(fr, __context);
g = _MKFLOAT(fg, __context);
b = _MKFLOAT(fb, __context);
}
%}
.
aBlock value:r value:g value:b
! !
!XWorkstation methodsFor:'window stuff'!
setBackingStore:how in:aWindowId
"turn on/off backing-store for a window"
%{ /* NOCONTEXT */
XSetWindowAttributes wa;
if (__isSmallInteger(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;
BEGIN_INTERRUPTSBLOCKED
XChangeWindowAttributes(myDpy, _WindowVal(aWindowId), CWBackingStore, &wa);
END_INTERRUPTSBLOCKED
}
RETURN ( self );
}
%}
.
self primitiveFailed
!
setBitGravity:how in:aWindowId
"set bit gravity for a window"
%{ /* NOCONTEXT */
XSetWindowAttributes wa;
if (__isSmallInteger(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;
}
BEGIN_INTERRUPTSBLOCKED
XChangeWindowAttributes(myDpy, _WindowVal(aWindowId), CWBitGravity, &wa);
END_INTERRUPTSBLOCKED
RETURN ( self );
}
%}
.
self primitiveFailed
!
setWindowGravity:how in:aWindowId
"set window gravity for a window"
%{ /* NOCONTEXT */
XSetWindowAttributes wa;
if (__isSmallInteger(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;
}
BEGIN_INTERRUPTSBLOCKED
XChangeWindowAttributes(myDpy, _WindowVal(aWindowId), CWWinGravity, &wa);
END_INTERRUPTSBLOCKED
RETURN ( self );
}
%}
.
self primitiveFailed
!
setSaveUnder:yesOrNo in:aWindowId
"turn on/off save-under for a window"
%{ /* NOCONTEXT */
XSetWindowAttributes wa;
if (__isSmallInteger(aWindowId)) {
if (_INST(hasSaveUnder) == true) {
wa.save_under = (yesOrNo == true) ? 1 : 0;
XChangeWindowAttributes(myDpy, _WindowVal(aWindowId), CWSaveUnder, &wa);
}
RETURN ( self );
}
%}
.
self primitiveFailed
!
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."
%{ /* NOCONTEXT */
if (__bothSmallInteger(aWindowId, aColorIndex)) {
XSetWindowBackground(myDpy, _WindowVal(aWindowId), _intVal(aColorIndex));
RETURN ( self );
}
%}
.
self primitiveFailed
!
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."
%{ /* NOCONTEXT */
if (__bothSmallInteger(aWindowId, aPixmapId)) {
XSetWindowBackgroundPixmap(myDpy, _WindowVal(aWindowId), _PixmapVal(aPixmapId));
RETURN ( self );
}
%}
.
self primitiveFailed
!
setWindowBorderColor:aColorIndex in:aWindowId
"set the windows border color"
%{ /* NOCONTEXT */
if (__bothSmallInteger(aWindowId, aColorIndex)) {
XSetWindowBorder(myDpy, _WindowVal(aWindowId), _intVal(aColorIndex));
RETURN ( self );
}
%}
.
self primitiveFailed
!
setWindowBorderPixmap:aPixmapId in:aWindowId
"set the windows border pattern"
%{ /* NOCONTEXT */
if (__bothSmallInteger(aWindowId, aPixmapId)) {
XSetWindowBorderPixmap(myDpy, _WindowVal(aWindowId), _PixmapVal(aPixmapId));
RETURN ( self );
}
%}
.
self primitiveFailed
!
setWindowBorderWidth:aNumber in:aWindowId
"set the windows border width"
%{ /* NOCONTEXT */
if (__bothSmallInteger(aWindowId, aNumber)) {
XSetWindowBorderWidth(myDpy, _WindowVal(aWindowId), _intVal(aNumber));
RETURN ( self );
}
%}
.
self primitiveFailed
!
setWindowBorderShape:aPixmapId in:aWindowId
"set the windows border shape"
hasShapeExtension ifFalse:[^ self].
%{ /* NOCONTEXT */
#ifdef SHAPE
if (__bothSmallInteger(aWindowId, aPixmapId)) {
XShapeCombineMask(myDpy, _WindowVal(aWindowId), ShapeBounding,
0, 0, _PixmapVal(aPixmapId), ShapeSet);
RETURN ( self );
}
#endif
%}
.
self primitiveFailed
!
setWindowShape:aPixmapId in:aWindowId
"set the windows shape"
hasShapeExtension ifFalse:[^ self].
%{ /* NOCONTEXT */
#ifdef SHAPE
if (__bothSmallInteger(aWindowId, aPixmapId)) {
XShapeCombineMask(myDpy, _WindowVal(aWindowId), ShapeClip,
0, 0,
_PixmapVal(aPixmapId), ShapeSet);
RETURN ( self );
}
#endif
%}
.
self primitiveFailed
!
setCursor:aCursorId in:aWindowId
"define a windows cursor"
%{ /* NOCONTEXT */
Display *dpy = myDpy;
if (__bothSmallInteger(aWindowId, aCursorId)) {
XDefineCursor(dpy, _WindowVal(aWindowId), _CursorVal(aCursorId));
RETURN ( self );
}
%}
.
self primitiveFailed
!
setWindowName:aString in:aWindowId
"define a windows name"
%{ /* NOCONTEXT */
if (__isSmallInteger(aWindowId)
&& (__isString(aString) || __isSymbol(aString))) {
XStoreName(myDpy, _WindowVal(aWindowId), (char *)_stringVal(aString));
RETURN ( self );
}
%}
.
self primitiveFailed
!
setIconName:aString in:aWindowId
"define a windows iconname"
%{ /* NOCONTEXT */
if (__isSmallInteger(aWindowId)
&& (__isString(aString) || __isSymbol(aString))) {
XSetIconName(myDpy, _WindowVal(aWindowId), (char *)_stringVal(aString));
RETURN ( self );
}
%}
.
self primitiveFailed
!
setWindowIcon:aForm in:aWindowId
"define a bitmap to be used as icon"
|iconId|
aForm notNil ifTrue:[
iconId := aForm id
].
%{
if (__bothSmallInteger(iconId, aWindowId)) {
XWMHints hints;
hints.icon_pixmap = _PixmapVal(iconId);
hints.flags = IconPixmapHint;
XSetWMHints(myDpy, _WindowVal(aWindowId), &hints);
RETURN ( self );
}
%}
.
self primitiveFailed
!
setWindowIconWindow:aView in:aWindowId
"define a window to be used as icon"
|iconWindowId|
aView notNil ifTrue:[
iconWindowId := aView id
].
%{
if (__bothSmallInteger(iconWindowId, aWindowId)) {
XWMHints hints;
hints.icon_window = _WindowVal(iconWindowId);
hints.flags = IconWindowHint;
XSetWMHints(myDpy, _WindowVal(aWindowId), &hints);
RETURN ( self );
}
%}
.
self primitiveFailed
!
setTransient:aWindowId for:aMainWindowId
"set aWindowId to be a transient of aMainWindow"
%{ /* NOCONTEXT */
if (__bothSmallInteger(aWindowId, aMainWindowId)) {
XSetTransientForHint(myDpy, _WindowVal(aWindowId),
_WindowVal(aMainWindowId));
RETURN ( self );
}
%}
.
self primitiveFailed
!
clearWindow:aWindowId
"clear a window to viewbackground"
%{ /* NOCONTEXT */
if (__isSmallInteger(aWindowId)) {
XClearWindow(myDpy, _WindowVal(aWindowId));
RETURN ( self );
}
%}
.
self primitiveFailed
!
clearRectangleX:x y:y width:width height:height in:aWindowId
"clear a rectangular area to viewbackground"
%{ /* NOCONTEXT */
int w, h;
if (__isSmallInteger(aWindowId)
&& __bothSmallInteger(x, y)
&& __bothSmallInteger(width, height)) {
w = _intVal(width);
h = _intVal(height);
if (w < 0) w = 0;
if (h < 0) h = 0;
XClearArea(myDpy, _WindowVal(aWindowId), _intVal(x), _intVal(y), w, h, 0);
RETURN ( self );
}
%}
.
self primitiveFailed
!
mapView:aView id:aWindowId iconified:aBoolean atX:xPos y:yPos width:w height:h
"make a window visible - either as icon or as a real view - needed for restart"
|wicon wiconId wiconView wiconViewId wlabel|
aBoolean ifTrue:[
wicon := aView icon.
wicon notNil ifTrue:[
wiconId := wicon id
].
wiconView := aView iconView.
wiconView notNil ifTrue:[
wiconViewId := wiconView id
].
wlabel := aView label.
].
%{
XWMHints wmhints;
XSizeHints szhints;
Display *dpy = myDpy;
Window win;
if (__isSmallInteger(aWindowId)) {
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 (aBoolean == true) {
char *windowName;
Pixmap iconBitmap = (Pixmap)0;
Window iconWindow;
if (__isSmallInteger(wiconId))
iconBitmap = _PixmapVal(wiconId);
else
iconBitmap = (Pixmap)0;
if (__isSmallInteger(wiconViewId))
iconWindow = _WindowVal(wiconViewId);
else
iconWindow = (Window)0;
if (__isString(wlabel) || __isSymbol(wlabel))
windowName = (char *)_stringVal(wlabel);
else
windowName = "";
if (iconBitmap || windowName) {
XSetStandardProperties(dpy, win,
windowName, windowName,
iconBitmap,
0, 0, &szhints);
}
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;
XSetWMHints(dpy, win, &wmhints);
}
if (szhints.flags) {
XSetNormalHints(dpy, win, &szhints);
}
XMapWindow(dpy, win);
RETURN ( self );
}
%}
.
self primitiveFailed
!
mapWindow:aWindowId
"make a window visible"
%{ /* NOCONTEXT */
if (__isSmallInteger(aWindowId)) {
XMapWindow(myDpy, _WindowVal(aWindowId));
RETURN ( self );
}
%}
.
self primitiveFailed
!
unmapWindow:aWindowId
"make a window invisible"
%{ /* NOCONTEXT */
if (__isSmallInteger(aWindowId)) {
XUnmapWindow(myDpy, _WindowVal(aWindowId));
RETURN ( self );
}
%}
.
self primitiveFailed
!
raiseWindow:aWindowId
"bring a window to front"
%{ /* NOCONTEXT */
if (__isSmallInteger(aWindowId)) {
XRaiseWindow(myDpy, _WindowVal(aWindowId));
RETURN ( self );
}
%}
.
self primitiveFailed
!
lowerWindow:aWindowId
"bring a window to back"
%{ /* NOCONTEXT */
if (__isSmallInteger(aWindowId)) {
XLowerWindow(myDpy, _WindowVal(aWindowId));
RETURN ( self );
}
%}
.
self primitiveFailed
!
moveWindow:aWindowId x:x y:y
"move a window"
%{ /* NOCONTEXT */
if (__isSmallInteger(aWindowId) && __bothSmallInteger(x, y)) {
XMoveWindow(myDpy, _WindowVal(aWindowId), _intVal(x), _intVal(y));
RETURN ( self );
}
%}
.
self primitiveFailed
!
resizeWindow:aWindowId width:w height:h
"resize a window"
%{ /* NOCONTEXT */
int newWidth, newHeight;
if (__isSmallInteger(aWindowId) && __bothSmallInteger(w, h)) {
newWidth = _intVal(w);
newHeight = _intVal(h);
if (newWidth < 1) newWidth = 1;
if (newHeight < 1) newHeight = 1;
XResizeWindow(myDpy, _WindowVal(aWindowId), newWidth, newHeight);
RETURN ( self );
}
%}
.
self primitiveFailed
!
moveResizeWindow:aWindowId x:x y:y width:w height:h
"move and resize a window"
%{ /* NOCONTEXT */
int newWidth, newHeight;
if (__isSmallInteger(aWindowId)
&& __bothSmallInteger(w, h)
&& __bothSmallInteger(x, y)) {
newWidth = _intVal(w);
newHeight = _intVal(h);
if (newWidth < 1) newWidth = 1;
if (newHeight < 1) newHeight = 1;
XMoveResizeWindow(myDpy, _WindowVal(aWindowId),
_intVal(x), _intVal(y),
newWidth, newHeight);
RETURN ( self );
}
%}
.
self primitiveFailed
!
configureWindow:aWindowId sibling:siblingId stackMode:modeSymbol
"configure stacking operation of aWindowId w.r.t siblingId"
%{ /* NOCONTEXT */
XWindowChanges chg;
int mask = CWSibling | CWStackMode;
if (__bothSmallInteger(aWindowId, 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);
XConfigureWindow(myDpy, _WindowVal(aWindowId),
mask, &chg);
RETURN ( self );
}
bad: ;
%}
.
self primitiveFailed
! !
!XWorkstation methodsFor:'graphic context stuff'!
setForeground:fgColorIndex in:aGCId
"set foreground color to be drawn with"
%{ /* NOCONTEXT */
if (__bothSmallInteger(fgColorIndex, aGCId)) {
XSetForeground(myDpy, _GCVal(aGCId), _intVal(fgColorIndex));
RETURN ( self );
}
%}
.
self primitiveFailed
!
setBackground:bgColorIndex in:aGCId
"set background color to be drawn with"
%{ /* NOCONTEXT */
if (__bothSmallInteger(bgColorIndex, aGCId)) {
XSetBackground(myDpy, _GCVal(aGCId), _intVal(bgColorIndex));
RETURN ( self );
}
%}
.
self primitiveFailed
!
setForeground:fgColorIndex background:bgColorIndex in:aGCId
"set foreground and background colors to be drawn with"
%{ /* NOCONTEXT */
Display *dpy = myDpy;
GC gc = _GCVal(aGCId);
if (__bothSmallInteger(fgColorIndex, bgColorIndex)
&& __isSmallInteger(aGCId)) {
XSetForeground(dpy, gc, _intVal(fgColorIndex));
XSetBackground(dpy, gc, _intVal(bgColorIndex));
RETURN ( self );
}
%}
.
self primitiveFailed
!
setForeground:fgColor background:bgColor mask:aBitmapId in:aGCId
"set foreground and background colors to be drawn with using mask or
solid (if aBitmapId is nil)"
%{ /* NOCONTEXT */
Display *dpy = myDpy;
GC gc = _GCVal(aGCId);
if (__isSmallInteger(aGCId)) {
if (__isSmallInteger(fgColor))
XSetForeground(dpy, gc, _intVal(fgColor));
if (__isSmallInteger(bgColor))
XSetBackground(dpy, gc, _intVal(bgColor));
if (__isSmallInteger(aBitmapId)) {
XSetStipple(dpy, gc, _PixmapVal(aBitmapId));
XSetFillStyle(dpy, gc, FillOpaqueStippled);
RETURN ( self );
}
if (aBitmapId == nil) {
XSetFillStyle(dpy, gc, FillSolid);
RETURN ( self );
}
}
%}
.
self primitiveFailed
!
setLineWidth:aNumber style:lineStyle cap:capStyle join:joinStyle in:aGCId
"set line attributes"
%{ /* NOCONTEXT */
int x_style, x_cap, x_join;
if (__bothSmallInteger(aGCId, aNumber)) {
if (lineStyle == @symbol(solid)) x_style = LineSolid;
else if (lineStyle == @symbol(dashed)) x_style = LineOnOffDash;
else if (lineStyle == @symbol(doubleDashed)) x_style = LineDoubleDash;
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;
XSetLineAttributes(myDpy,
_GCVal(aGCId), _intVal(aNumber),
x_style, x_cap, x_join);
RETURN ( self );
}
bad: ;
%}
.
"
either aGCId is invalid,
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 primitiveFailed
!
setForeground:fgColor background:bgColor mask:aBitmapId lineWidth:lw in:aGCId
"set foreground and background colors to be drawn with using mask or
solid (if aBitmapId is nil); also set lineWidth"
%{ /* NOCONTEXT */
Display *dpy = myDpy;
GC gc = _GCVal(aGCId);
if (__isSmallInteger(aGCId)) {
if (__isSmallInteger(lw)) {
XSetLineAttributes(dpy, gc, _intVal(lw),
LineSolid, CapNotLast, JoinMiter);
}
if (__isSmallInteger(fgColor))
XSetForeground(dpy, gc, _intVal(fgColor));
if (__isSmallInteger(bgColor))
XSetBackground(dpy, gc, _intVal(bgColor));
if (__isSmallInteger(aBitmapId)) {
XSetStipple(dpy, gc, _PixmapVal(aBitmapId));
XSetFillStyle(dpy, gc, FillOpaqueStippled);
RETURN ( self );
}
if (aBitmapId == nil) {
XSetFillStyle(dpy, gc, FillSolid);
RETURN ( self );
}
}
%}
.
self primitiveFailed
!
setFunction:aFunctionSymbol in:aGCId
"set alu function to be drawn with"
%{ /* NOCONTEXT */
GC gc = _GCVal(aGCId);
int fun = -1;
if (__isSmallInteger(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;
if (fun != -1) {
XSetFunction(myDpy, gc, fun);
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 primitiveFailed
!
setFont:aFontId in:aGCId
"set font to be drawn in"
%{ /* NOCONTEXT */
XFontStruct *f;
if (__bothSmallInteger(aFontId, aGCId)) {
f = (XFontStruct *) _FontVal(aFontId);
XSetFont(myDpy, _GCVal(aGCId), f->fid);
RETURN ( self );
}
%}
.
"
aGCId and/or aFontId are invalid
"
self primitiveFailed
!
setPixmapMask:aPixmapId in:aGCId
"set or clear the drawing mask - a pixmap mask providing full color"
%{ /* NOCONTEXT */
Display *dpy = myDpy;
GC gc = _GCVal(aGCId);
Pixmap pixmap;
if (__isSmallInteger(aGCId)) {
if (__isSmallInteger(aPixmapId)) {
pixmap = _PixmapVal(aPixmapId);
XSetTile(dpy, gc, pixmap);
XSetFillStyle(dpy, gc, FillTiled);
RETURN ( self );
}
if (aPixmapId == nil) {
XSetFillStyle(dpy, gc, FillSolid);
RETURN ( self );
}
}
%}
.
self primitiveFailed
!
setBitmapMask:aBitmapId in:aGCId
"set or clear the drawing mask - a bitmap mask using current fg/bg"
%{ /* NOCONTEXT */
Display *dpy = myDpy;
GC gc = _GCVal(aGCId);
Pixmap bitmap;
if (__isSmallInteger(aGCId)) {
if (__isSmallInteger(aBitmapId)) {
bitmap = _PixmapVal(aBitmapId);
XSetStipple(dpy, gc, bitmap);
XSetFillStyle(dpy, gc, FillOpaqueStippled);
RETURN ( self );
}
if (aBitmapId == nil) {
XSetFillStyle(dpy, gc, FillSolid);
RETURN ( self );
}
}
%}
.
self primitiveFailed
!
setMaskOriginX:orgX y:orgY in:aGCid
"set the mask origin"
%{ /* NOCONTEXT */
if (__bothSmallInteger(orgX, orgY) && __isSmallInteger(aGCid)) {
XSetTSOrigin(myDpy, _GCVal(aGCid), _intVal(orgX), _intVal(orgY));
RETURN ( self );
}
%}
.
self primitiveFailed
!
setClipByChildren:aBool in:aGCId
"enable/disable drawing into child views"
%{ /* NOCONTEXT */
XGCValues gcv;
GC gc = _GCVal(aGCId);
if (__isSmallInteger(aGCId)) {
if (aBool == true)
gcv.subwindow_mode = ClipByChildren;
else
gcv.subwindow_mode = IncludeInferiors;
XChangeGC(myDpy, gc, GCSubwindowMode, &gcv);
RETURN ( self );
}
%}
.
self primitiveFailed
!
noClipIn:aGCId
"disable clipping rectangle"
%{ /* NOCONTEXT */
XGCValues gcv;
GC gc = _GCVal(aGCId);
if (__isSmallInteger(aGCId)) {
gcv.clip_mask = None;
XChangeGC(myDpy, gc, GCClipMask, &gcv);
RETURN ( self );
}
%}
.
self primitiveFailed
!
setClipX:clipX y:clipY width:clipWidth height:clipHeight in:aGCId
"clip to a rectangle"
%{ /* NOCONTEXT */
XRectangle r;
if (__isSmallInteger(aGCId)
&& __bothSmallInteger(clipX, clipY)
&& __bothSmallInteger(clipWidth, clipHeight)) {
r.x = _intVal(clipX);
r.y = _intVal(clipY);
r.width = _intVal(clipWidth);
r.height = _intVal(clipHeight);
XSetClipRectangles(myDpy, _GCVal(aGCId), 0, 0, &r, 1, Unsorted);
RETURN ( self );
}
%}
.
self primitiveFailed
!
setGraphicsExposures:aBoolean in:aGCId
"set or clear the graphics exposures flag"
%{ /* NOCONTEXT */
if (__isSmallInteger(aGCId)) {
XSetGraphicsExposures(myDpy, _GCVal(aGCId), (aBoolean==true)?1:0);
RETURN ( self );
}
%}
.
self primitiveFailed
! !
!XWorkstation methodsFor:'retrieving pixels'!
getPixelX:x y:y from:aDrawableId
"return the pixel value at x/y"
%{
Window win = _WindowVal(aDrawableId);
XImage *img;
int ret;
int xpos, ypos;
if (__isSmallInteger(aDrawableId) && __bothSmallInteger(x, y)) {
xpos = _intVal(x);
ypos = _intVal(y);
if ((xpos < 0) || (ypos < 0)) {
RETURN ( _MKSMALLINT(0) );
}
img = XGetImage(myDpy, win, xpos, ypos, 1, 1, (unsigned)~0, ZPixmap);
ret = XGetPixel(img, 0, 0);
XDestroyImage(img);
RETURN ( _MKSMALLINT(ret) );
}
%}
.
self primitiveFailed.
^ nil
!
getBitsFrom: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."
|info|
((w <= 0) or:[h <= 0]) ifTrue:[
self primitiveFailed.
^ nil
].
info := Array with:nil "depth"
with:nil "bit order"
with:nil "bytes_per_line"
with:nil "byte_order".
(self primGetBitsFrom:aDrawableId x:srcx y:srcy width:w height:h into:imageBits infoInfo:info) ifTrue:[
^ info
].
"
some error occured - either args are not smallintegers, imageBits is not a ByteArray
or is too small to hold the bits
"
^ self primitiveFailed
!
primGetBitsFrom:aDrawableId x:srcx y:srcy width:w height:h into:imageBits infoInfo:info
%{ /* UNLIMITEDSTACK */
Display *dpy = myDpy;
Window win = _WindowVal(aDrawableId);
extern OBJ ByteArray;
XImage *image = (XImage *)0;
int pad, bytes_per_line, numBytes;
if (__isSmallInteger(aDrawableId)
&& __bothSmallInteger(srcx, srcy)
&& __bothSmallInteger(w, h)
&& __isArray(info)
&& __isByteArray(imageBits)) {
image = XGetImage(dpy, win, _intVal(srcx), _intVal(srcy),
_intVal(w), _intVal(h),
(unsigned)AllPlanes, ZPixmap);
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:
numBytes = image->bytes_per_line * image->height;
break;
default:
/* unsupported depth */
goto fail;
}
#ifdef SUPERDEBUG
printf("bytes need:%d bytes given:%d\n", numBytes, _byteArraySize(imageBits));
#endif
if (numBytes > _byteArraySize(imageBits)) {
/* imageBits too small */
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);
bcopy(image->data, _ByteArrayInstPtr(imageBits)->ba_element, numBytes);
XDestroyImage(image);
RETURN ( true );
}
fail:
if (image) {
XDestroyImage(image);
}
%}.
^ false
! !
!XWorkstation methodsFor:'drawing'!
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."
%{ /* NOCONTEXT */
GC gc = _GCVal(aGCId);
Window win = _WindowVal(aDrawableId);
unsigned char *cp;
int n;
OBJ cls;
#ifdef TWOBYTESTRINGS
extern OBJ TwoByteString;
#endif
if (__bothSmallInteger(aGCId, aDrawableId)
&& __isNonNilObject(aString)
&& __bothSmallInteger(x, y)) {
cls = _qClass(aString);
if ((cls == String) || (cls == Symbol)) {
cp = _stringVal(aString);
n = _stringSize(aString);
if (n > 1000) n = 1000;
if (opaque == true)
XDrawImageString(myDpy, win, gc, _intVal(x), _intVal(y), (char *)cp, n);
else
XDrawString(myDpy, win, gc, _intVal(x), _intVal(y), (char *)cp, n);
RETURN ( self );
}
#ifdef TWOBYTESTRINGS
if (cls == TwoByteString) {
cp = _stringVal(aString);
n = _byteArraySize(aString) / 2;
if (n > 1000) n = 1000;
if (opaque == true)
XDrawImageString16(myDpy, win, gc, _intVal(x), _intVal(y), (XChar2b *)cp, n);
else
XDrawString16(myDpy, win, gc, _intVal(x), _intVal(y), (XChar2b *)cp, n);
RETURN ( self );
}
#endif
}
%}.
"x/y not integer, badGC or drawable, or not a string"
self primitiveFailed
!
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."
%{ /* NOCONTEXT */
GC gc = _GCVal(aGCId);
Window win = _WindowVal(aDrawableId);
unsigned char *cp;
OBJ cls;
int i1, i2, l, n;
#ifdef TWOBYTESTRINGS
extern OBJ TwoByteString;
#endif
if (__bothSmallInteger(aGCId, aDrawableId)
&& __isNonNilObject(aString)
&& __bothSmallInteger(index1, index2)
&& __bothSmallInteger(x, y)) {
cls = _qClass(aString);
if ((cls == String) || (cls == Symbol)) {
i1 = _intVal(index1) - 1;
i2 = _intVal(index2) - 1;
n = _stringSize(aString);
cp = _stringVal(aString);
if ((i1 >= 0) && (i2 < n)) {
if (i2 >= i1) {
cp += i1;
l = i2 - i1 + 1;
if (l > 1000) l = 1000;
if (opaque == true)
XDrawImageString(myDpy, win, gc, _intVal(x), _intVal(y), (char *)cp, l);
else
XDrawString(myDpy, win, gc, _intVal(x), _intVal(y), (char *)cp, l);
}
RETURN ( self );
}
}
#ifdef TWOBYTESTRINGS
if (cls == TwoByteString) {
i1 = _intVal(index1) - 1;
i2 = _intVal(index2) - 1;
n = _byteArraySize(aString) / 2;
cp = _stringVal(aString);
if ((i1 >= 0) && (i2 < n)) {
if (i2 >= i1) {
cp += (i1 * 2);
l = i2 - i1 + 1;
if (l > 1000) l = 1000;
if (opaque == true)
XDrawImageString16(myDpy, win, gc, _intVal(x), _intVal(y), (XChar2b *)cp, l);
else
XDrawString16(myDpy, win, gc, _intVal(x), _intVal(y), (XChar2b *)cp, l);
RETURN ( self );
}
}
}
#endif
}
%}.
"x/y not integer, badGC or drawable, or not a string"
self primitiveFailed
!
displayPointX:x y:y in:aDrawableId with:aGCId
"draw a point. If x/y are not integers, an error is triggered."
%{ /* NOCONTEXT */
GC gc = _GCVal(aGCId);
Window win = _WindowVal(aDrawableId);
if (__bothSmallInteger(aGCId, aDrawableId)
&& __bothSmallInteger(x, y)) {
XDrawPoint(myDpy, win, gc, _intVal(x), _intVal(y));
RETURN ( self );
}
%}.
"badGC, badDrawable or x/y not integer"
self primitiveFailed
!
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."
%{ /* NOCONTEXT */
GC gc = _GCVal(aGCId);
Window win = _WindowVal(aDrawableId);
if (__bothSmallInteger(aGCId, aDrawableId)
&& __bothSmallInteger(x0, y0)
&& __bothSmallInteger(x1, y1)) {
XDrawLine(myDpy, win, gc, _intVal(x0), _intVal(y0),
_intVal(x1), _intVal(y1));
RETURN ( self );
}
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailed
!
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."
%{ /* NOCONTEXT */
GC gc = _GCVal(aGCId);
Window win = _WindowVal(aDrawableId);
int w, h;
if (__bothSmallInteger(aGCId, 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)) {
XDrawRectangle(myDpy, win, gc, _intVal(x), _intVal(y), w, h);
}
RETURN ( self );
}
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailed
!
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."
|numberOfPoints newPoints|
numberOfPoints := aPolygon size.
%{
GC gc = _GCVal(aGCId);
Window win = _WindowVal(aDrawableId);
extern OBJ Point;
OBJ point, x, y;
int i, num;
XPoint *points;
XPoint qPoints[100];
if (__bothSmallInteger(aGCId, aDrawableId)
&& __isSmallInteger(numberOfPoints)) {
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;
} else
points = qPoints;
for (i=0; i<num; i++) {
point = _AT_(aPolygon COMMA_CON, _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);
}
XDrawLines(myDpy, win, gc, points, num, CoordModeOrigin);
if (num > 100)
free(points);
RETURN ( self );
}
fail: ;
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailed
!
copyFromFaxImage:sourceId x:srcX y:srcY to:destId x:dstX y:dstY
width:w height:h with:aGCId scaleX:scaleX scaleY:scaleY
"do a bit-blt of a compressed FAX image
- this needs my private FAX extension"
%{
#ifdef FAX
GC gc = _GCVal(aGCId);
FAXImage source;
Drawable dest;
if (__isSmallInteger(aGCId)
&& __bothSmallInteger(sourceId, destId)
&& __bothSmallInteger(scaleX, scaleY)
&& __bothSmallInteger(w, h)
&& __bothSmallInteger(srcX, srcY)
&& __bothSmallInteger(dstX, dstY)) {
source = (FAXImage) _WindowVal(sourceId);
dest = (Drawable) _WindowVal(destId);
XFAXImageCopyImage(myDpy, source, dest, gc,
_intVal(srcX), _intVal(srcY),
_intVal(w), _intVal(h),
_intVal(dstX), _intVal(dstY),
_intVal(scaleX), _intVal(scaleY));
RETURN ( self );
}
#endif
%}.
self primitiveFailed
!
copyFromId:sourceId x:srcX y:srcY to:destId x:dstX y:dstY
width:w height:h with:aGCId
"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."
%{ /* NOCONTEXT */
GC gc = _GCVal(aGCId);
Drawable source, dest;
if (__isSmallInteger(aGCId)
&& __bothSmallInteger(sourceId, destId)
&& __bothSmallInteger(w, h)
&& __bothSmallInteger(srcX, srcY)
&& __bothSmallInteger(dstX, dstY)) {
source = (Drawable) _WindowVal(sourceId);
dest = (Drawable) _WindowVal(destId);
XCopyArea(myDpy, source, dest, gc,
_intVal(srcX), _intVal(srcY),
_intVal(w), _intVal(h),
_intVal(dstX), _intVal(dstY));
RETURN ( self );
}
%}.
"badGC, bad sourceDrawableId or destDrawableID
or any non integer coordinate"
self primitiveFailed
!
copyPlaneFromId:sourceId x:srcX y:srcY to:destId x:dstX y:dstY
width:w height:h with:aGCId
"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."
%{ /* NOCONTEXT */
GC gc = _GCVal(aGCId);
Drawable source, dest;
if (__isSmallInteger(aGCId)
&& __bothSmallInteger(sourceId, destId)
&& __bothSmallInteger(w, h)
&& __bothSmallInteger(srcX, srcY)
&& __bothSmallInteger(dstX, dstY)) {
source = (Drawable) _WindowVal(sourceId);
dest = (Drawable) _WindowVal(destId);
XCopyPlane(myDpy, source, dest, gc,
_intVal(srcX), _intVal(srcY),
_intVal(w), _intVal(h),
_intVal(dstX), _intVal(dstY), 1);
RETURN ( self );
}
%}.
"badGC, bad sourceDrawableId or destDrawableID
or any non integer coordinate"
self primitiveFailed
!
displayArcX:x y:y w:width h: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."
%{ /* NOCONTEXT */
GC gc = _GCVal(aGCId);
Window win = _WindowVal(aDrawableId);
int w, h, angle1, angle2;
double f;
if (__isSmallInteger(startAngle))
angle1 = _intVal(startAngle) * 64;
else if (__isFloat(startAngle)) {
f = _floatVal(startAngle);
angle1 = f * 64;
}
if (__isSmallInteger(angle))
angle2 = _intVal(angle) * 64;
else if (__isFloat(angle)) {
f = _floatVal(angle);
angle2 = f * 64;
}
if (__bothSmallInteger(aGCId, 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) && (angle1 >= 0) && (angle2 >= 0)) {
XDrawArc(myDpy, win, gc, _intVal(x), _intVal(y),
w, h, angle1, angle2);
}
RETURN ( self );
}
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailed
!
fillArcX:x y:y w:width h: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."
%{ /* NOCONTEXT */
GC gc = _GCVal(aGCId);
Window win = _WindowVal(aDrawableId);
int w, h, angle1, angle2;
double f;
if (__isSmallInteger(startAngle))
angle1 = _intVal(startAngle) * 64;
else if (__isFloat(startAngle)) {
f = _floatVal(startAngle);
angle1 = f * 64;
}
if (__isSmallInteger(angle))
angle2 = _intVal(angle) * 64;
else if (__isFloat(angle)) {
f = _floatVal(angle);
angle2 = f * 64;
}
if (__bothSmallInteger(aGCId, 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) && (angle1 >= 0) && (angle2 >= 0)) {
XFillArc(myDpy, win, gc, _intVal(x), _intVal(y),
w, h, angle1, angle2);
}
RETURN ( self );
}
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailed
!
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."
%{ /* NOCONTEXT */
int w, h;
if (__bothSmallInteger(aGCId, 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)) {
XFillRectangle(myDpy,
(Drawable)_WindowVal(aDrawableId), _GCVal(aGCId),
_intVal(x), _intVal(y), w, h);
}
RETURN ( self );
}
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailed
!
fillPolygon:aPolygon in:aDrawableId with:aGCId
"fill a polygon given by its points.
If any coordinate is not integer, an error is triggered."
|numberOfPoints|
numberOfPoints := aPolygon size.
%{
GC gc = _GCVal(aGCId);
Window win = _WindowVal(aDrawableId);
OBJ point, x, y;
extern OBJ Point;
int i, num;
XPoint *points;
XPoint qPoints[100];
if (__bothSmallInteger(aGCId, aDrawableId)
&& __isSmallInteger(numberOfPoints)) {
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;
} else
points = qPoints;
for (i=0; i<num; i++) {
point = _AT_(aPolygon COMMA_CON, _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);
}
XFillPolygon(myDpy, win, gc, points, num, Complex, CoordModeOrigin);
if (num > 100)
free(points);
RETURN ( self );
fail: ;
}
%}.
"badGC, badDrawable or coordinates not integer"
self primitiveFailed
!
drawBits:imageBits depth:imageDepth
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 must have imageDepth bits.
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."
^ self drawBits:imageBits bitsPerPixel:imageDepth depth:imageDepth
width:imageWidth height:imageHeight
x:srcx y:srcy
into:aDrawableId
x:dstx y:dsty
width:w height:h
with:aGCId
!
drawBits:imageBits bitsPerPixel:bitsPerPixel depth:imageDepth
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."
"
sorry; I had to separate it into 2 methods, since XPutImage needs
an unlimited stack, and thus cannot send primitiveFailed
"
(self primDrawBits:imageBits bitsPerPixel:bitsPerPixel depth:imageDepth
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 primitiveFailed
].
!
primDrawBits:imageBits bitsPerPixel:bitsPerPixel depth:imageDepth
width:imageWidth height:imageHeight
x:srcx y:srcy
into:aDrawableId
x:dstx y:dsty
width:w height:h
with:aGCId
%{ /* UNLIMITEDSTACK */
/*
* need unlimited stack, since some Xlibs do a huge alloca in
* XPutImage
*/
Display *dpy = myDpy;
GC gc = _GCVal(aGCId);
Window win = _WindowVal(aDrawableId);
extern OBJ ByteArray;
XImage image;
if (__bothSmallInteger(aGCId, aDrawableId)
&& __bothSmallInteger(srcx, srcy)
&& __bothSmallInteger(dstx, dsty)
&& __bothSmallInteger(w, h)
&& __bothSmallInteger(imageWidth, imageHeight)
&& __bothSmallInteger(imageDepth, bitsPerPixel)
&& __isByteArray(imageBits)) {
#ifdef ARGDEBUG
printf("args ok\n");
#endif
image.data = (char *)_ByteArrayInstPtr(imageBits)->ba_element;
image.width = _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 = 8;
image.depth = _intVal(imageDepth);
image.bits_per_pixel = _intVal(bitsPerPixel);
switch (image.bits_per_pixel) {
case 1:
image.bytes_per_line = (_intVal(imageWidth) + 7) / 8;
break;
case 2:
image.bytes_per_line = (_intVal(imageWidth)*2 + 7) / 8;
break;
case 4:
image.bytes_per_line = (_intVal(imageWidth)*4 + 7) / 8;
break;
case 8:
image.bytes_per_line = _intVal(imageWidth);
break;
case 16:
image.bytes_per_line = _intVal(imageWidth)*2;
break;
case 24:
image.bytes_per_line = _intVal(imageWidth)*3;
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;
XPutImage(dpy, win, gc, &image, _intVal(srcx), _intVal(srcy),
_intVal(dstx), _intVal(dsty),
_intVal(w), _intVal(h));
RETURN ( true );
}
#ifdef ARGDEBUG
if (! __isSmallInteger(aGCId)) printf("GC\n");
if (! __isSmallInteger(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 handling'!
eventMaskFor:anEventSymbol
"return the eventMask bit-constant corresponding to an event symbol"
%{
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));
%}
!
setEventMask:aMask in:aWindowId
"tell X that we are only interrested in events from aMask, which
is the bitwise or of the eventMask bits (see 'eventMaskFor:')"
%{ /* NOCONTEXT */
int mask;
if (__bothSmallInteger(aWindowId, aMask)) {
mask = _intVal(aMask);
#ifdef OLD
/* these may not be disabled */
mask |= ExposureMask | StructureNotifyMask |
KeyPressMask |
ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
#endif
XSelectInput(myDpy, _WindowVal(aWindowId), mask);
RETURN ( self );
}
%}
.
self primitiveFailed
!
startDispatch
"redefined to clear dispatchingExpose, which is a special X feature"
dispatching ifTrue:[^ self].
dispatchingExpose := nil.
super startDispatch
!
checkForEndOfDispatch
"return true, if there are still any views of interrest - if not,
stop dispatch"
"/ idToViewMapping isEmpty ifTrue:[
"/ dispatching := false.
"/ ] ifFalse:[
"/ ((idToViewMapping size == 1) and:[idToViewMapping includesValue:RootView]) ifTrue:[
"/ dispatching := false.
"/ ]
"/ ]
knownViews isEmpty ifTrue:[
dispatching := false.
^ self
].
((knownViews size == 1) and:[(knownViews at:1) == RootView]) ifTrue:[
dispatching := false.
]
!
dispatchPendingEvents
"central event handling method:
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"
"interrested in exposes only ?"
dispatchingExpose notNil ifTrue:[
[self exposeEventPendingFor:dispatchingExpose] whileTrue:[
self dispatchExposeEventFor:dispatchingExpose
].
^ self
].
"no, general dispatch"
[self eventPendingWithoutSync] whileTrue:[
self dispatchEventFor:nil withMask:nil
]
!
handleExposeOnlyFor:aView
"from now on, handle expose events only"
dispatchingExpose := aView id
!
handleAllEvents
"from now on, handle any kind of event"
dispatchingExpose := nil
!
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."
self dispatchEventFor:aViewIdOrNil withMask:(self eventMaskFor:#expose)
!
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."
(self getEventFor:aViewIdOrNil withMask:eventMask) ifTrue:[
Object abortSignal catch:[
self dispatchLastEvent.
]
].
!
getEventFor:aViewIdOrNil withMask:eventMask
"read next event - put into local buffer. If aViewIdOrNil is
nil, events for any view are fetched; otherwise only events for that
view will be processed.
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.
BUG: uses a static buffer - has to be rewritten, to support multiple
display connections.
"
%{ /* UNLIMITEDSTACK */
Display *dpy = myDpy;
Window win, wWanted;
int evMask;
__ev__.type = 0;
if (__isSmallInteger(eventMask)) {
evMask = _intVal(eventMask);
} else {
evMask = ~0;
}
if (__isSmallInteger(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);
}
}
%}.
^ false
!
dispatchLastEvent
|theView symS arg butt sibling|
%{ /* STACK: 8000 */
# define ANYBUTTON (Button1MotionMask | Button2MotionMask | Button3MotionMask)
Display *dpy = myDpy;
XAnyEvent *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__)
KeySym keySym;
unsigned char buffer[10];
int i, nchars;
char *keySymString;
char keySymStringBuffer[32];
static unsigned multiClickTime = 0;
unsigned nextMultiClickTime;
struct inlineCache *ipS;
static struct inlineCache vid = _ILC1;
static struct inlineCache expS = _ILC5;
static struct inlineCache gexpS = _ILC5;
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 keymap = _ILC0;
static struct inlineCache created = _ILC0;
static struct inlineCache mapReq = _ILC0;
static struct inlineCache repar = _ILC0;
static struct inlineCache confReq = _ILC0;
static struct inlineCache resReq = _ILC0;
static struct inlineCache prop = _ILC0;
static struct inlineCache selClear = _ILC0;
static struct inlineCache selReq = _ILC4;
static struct inlineCache selNotify = _ILC4;
static struct inlineCache colormap = _ILC0;
static struct inlineCache vis = _ILC1;
static struct inlineCache skpS = _ILC4;
static struct inlineCache skrS = _ILC4;
theView = (*vid.ilc_func)(self, @symbol(viewFromId:) COMMA_CON, nil, &vid,
MKOBJ(ae->window));
if (theView == nil) {
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.
*/
switch (__ev__.type) {
case KeyRelease:
symS = @symbol(keyRelease:x:y:view:);
ipS = &skrS;
goto keyPressAndRelease;
break;
case KeyPress:
symS = @symbol(keyPress:x:y:view:);
ipS = &skpS;
keyPressAndRelease:
_INST(eventRootX) = _MKSMALLINT(ke->x_root);
_INST(eventRootY) = _MKSMALLINT(ke->y_root);
_INST(altDown) = (ke->state & Mod2Mask) ? true : false;
_INST(metaDown) = (ke->state & Mod1Mask) ? true : false;
_INST(shiftDown) = (ke->state & ShiftMask) ? true : false;
_INST(controlDown) = (ke->state & ControlMask) ? true : false;
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) {
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, __context);
}
}
if (arg == nil) {
/* happens sometimes (alt-graph on sun has no keysym) */
break;
}
(*(*ipS).ilc_func)(self, symS COMMA_CON, nil, ipS,
arg,
_MKSMALLINT(ke->x),
_MKSMALLINT(ke->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 (multiClickTime) {
if (be->time < multiClickTime) {
multiClickTime = nextMultiClickTime;
ipS = &bmpS;
symS = @symbol(buttonMultiPress:x:y:view:);
goto sendButtonEvent;
break;
}
}
multiClickTime = nextMultiClickTime;
if (be->state & ShiftMask) {
ipS = &bspS;
symS = @symbol(buttonShiftPress:x:y:view:);
goto sendButtonEvent;
}
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);
(*(*ipS).ilc_func)(self,
symS
COMMA_CON, 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);
(*motS.ilc_func)(self,
@symbol(buttonMotion:x:y:view:)
COMMA_CON, nil, &motS,
_MKSMALLINT(me->state),
_MKSMALLINT(me->x),
_MKSMALLINT(me->y),
theView);
break;
case FocusIn:
(*focInS.ilc_func)(self,
@symbol(focusInView:)
COMMA_CON, nil, &focInS,
theView);
break;
case FocusOut:
(*focOutS.ilc_func)(self,
@symbol(focusOutView:)
COMMA_CON, nil, &focOutS,
theView);
break;
case EnterNotify:
(*peS.ilc_func)(self,
@symbol(pointerEnter:x:y:view:)
COMMA_CON, nil, &peS,
_MKSMALLINT(ewe->state),
_MKSMALLINT(ewe->x),
_MKSMALLINT(ewe->y),
theView);
break;
case LeaveNotify:
(*plS.ilc_func)(self,
@symbol(pointerLeave:view:)
COMMA_CON, nil, &plS,
_MKSMALLINT(lwe->state),
theView);
break;
case GraphicsExpose:
(*gexpS.ilc_func)(self,
@symbol(graphicExposeX:y:width:height:view:)
COMMA_CON, nil, &gexpS,
_MKSMALLINT(ee->x),
_MKSMALLINT(ee->y),
_MKSMALLINT(ee->width),
_MKSMALLINT(ee->height),
theView);
if (ee->count != 0) {
break;
}
/* fall into */
case NoExpose:
(*nexpS.ilc_func)(self,
@symbol(noExposeView:)
COMMA_CON, nil, &nexpS,
theView);
break;
case Expose:
(*expS.ilc_func)(self,
@symbol(exposeX:y:width:height:view:)
COMMA_CON, nil, &expS,
_MKSMALLINT(ee->x),
_MKSMALLINT(ee->y),
_MKSMALLINT(ee->width),
_MKSMALLINT(ee->height),
theView);
break;
case ConfigureNotify:
if (ce->above != None) {
sibling = (*vid.ilc_func)(self, @symbol(viewFromId:)
COMMA_CON, nil, &vid,
MKOBJ(ce->above));
}
(*confS.ilc_func)(self,
@symbol(configureX:y:width:height:view:)
COMMA_CON, 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:)
COMMA_CON, 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:)
COMMA_CON, nil, &termS, theView);
break;
}
if (__ev__.xclient.data.l[0] == (int) _AtomVal(_INST(saveYourselfAtom))) {
(*savtermS.ilc_func)(self,
@symbol(saveAndTerminateView:)
COMMA_CON, nil, &savtermS, theView);
break;
}
}
break;
case DestroyNotify:
(*destrS.ilc_func)(self, @symbol(destroyedView:)
COMMA_CON, nil, &destrS, theView);
break;
case UnmapNotify:
(*unmapS.ilc_func)(self, @symbol(unmappedView:)
COMMA_CON, nil, &unmapS, theView);
break;
case MapNotify:
(*mapS.ilc_func)(self,
@symbol(mappedView:)
COMMA_CON, nil, &mapS, theView);
break;
case KeymapNotify:
(*keymap.ilc_func)(theView,
@symbol(keyMapChange)
COMMA_CON, 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:) COMMA_CON, nil, &vis, arg);
break;
case CreateNotify:
(*created.ilc_func)(theView, @symbol(created) COMMA_CON, nil, &created);
break;
case MapRequest:
(*mapReq.ilc_func)(theView, @symbol(mapRequest) COMMA_CON, nil, &mapReq);
break;
case ReparentNotify:
(*repar.ilc_func)(theView, @symbol(reparented) COMMA_CON, nil, &repar);
break;
case ConfigureRequest:
(*confReq.ilc_func)(theView, @symbol(configRequest) COMMA_CON, nil, &confReq);
break;
case GravityNotify:
case ResizeRequest:
(*resReq.ilc_func)(theView, @symbol(resizeRequest) COMMA_CON, nil, &resReq);
break;
case CirculateNotify:
case CirculateRequest:
break;
case PropertyNotify:
(*prop.ilc_func)(theView,
@symbol(propertyChange)
COMMA_CON, nil, &prop);
break;
case SelectionClear:
(*selClear.ilc_func)(theView,
@symbol(selectionClear)
COMMA_CON, nil, &selClear);
break;
case SelectionNotify:
/*
* returned selection value (answer from SelectionRequest)
*/
/*
printf("SelectionNotify prop=%x requestor=%x\n", __ev__.xselection.property,
__ev__.xselection.requestor);
*/
(*selNotify.ilc_func)(theView,
@symbol(selectionNotify:target:selection:from:)
COMMA_CON, nil, &selNotify,
MKOBJ(__ev__.xselection.property),
MKOBJ(__ev__.xselection.target),
MKOBJ(__ev__.xselection.selection),
MKOBJ(__ev__.xselection.requestor));
break;
case SelectionRequest:
/*
printf("SelectionRequest prop=%x requestor=%x target=%x selection=%x\n",
__ev__.xselectionrequest.property,
__ev__.xselectionrequest.requestor,
__ev__.xselectionrequest.target,
__ev__.xselectionrequest.selection);
*/
(*selReq.ilc_func)(theView,
@symbol(selectionRequest:target:selection:from:)
COMMA_CON, nil, &selReq,
MKOBJ(__ev__.xselectionrequest.property),
MKOBJ(__ev__.xselectionrequest.target),
MKOBJ(__ev__.xselectionrequest.selection),
MKOBJ(__ev__.xselectionrequest.requestor));
break;
case ColormapNotify:
(*colormap.ilc_func)(theView,
@symbol(colorMapChange)
COMMA_CON, nil, &colormap);
break;
case MappingNotify:
/*
printf("mapping\n");
*/
/*
(*mapping.ilc_func)(theView,
@symbol(mapping)
COMMA_CON, nil, &mapping);
*/
break;
}
#undef ee
#undef ke
#undef be
#undef ce
#undef me
#undef ewe
#undef lwe
#undef de
%}
.
^ true
!
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."
%{ /* NOCONTEXT */
Display *dpy = myDpy;
XEvent ev;
Window win;
if (__isSmallInteger(aMask)) {
if (__isSmallInteger(aWindowIdOrNil)) {
win = _WindowVal(aWindowIdOrNil);
while (XCheckWindowEvent(dpy, win, _intVal(aMask), &ev)) ;;
} else {
while (XCheckMaskEvent(dpy, _intVal(aMask), &ev)) ;;
}
RETURN ( self );
}
%}
.
self primitiveFailed
!
eventPending
"return true, if any event is pending"
dispatchingExpose notNil ifTrue:[
^ self exposeEventPendingFor:dispatchingExpose
].
"/ ^ self eventPendingWithSync
^ self eventPendingWithoutSync
!
eventPendingWithSync
"return true, if any event is pending.
Do a flush output buffer before."
%{ /* UNLIMITEDSTACK */
Display *dpy = myDpy;
XSync(dpy, 0); /* make certain everything is flushed */
RETURN ( (XPending(dpy)) ? true : false );
%}
!
eventPendingWithoutSync
"return true, if any event is pending."
%{ /* UNLIMITEDSTACK */
RETURN ( (XPending(myDpy)) ? true : false );
%}
!
exposeEventPendingFor:aWindowIdOrNil
"return true, if any expose event is pending"
%{ /* UNLIMITEDSTACK */
Display *dpy = myDpy;
XEvent ev;
Window win;
int thereIsOne;
XSync(dpy, 0); /* make certain everything is flushed */
if (__isSmallInteger(aWindowIdOrNil)) {
win = _WindowVal(aWindowIdOrNil);
thereIsOne = XCheckWindowEvent(dpy, win, ExposureMask, &ev);
} else {
thereIsOne = XCheckMaskEvent(dpy, ExposureMask, &ev);
}
if (thereIsOne) {
XPutBackEvent(dpy, &ev);
RETURN ( true );
}
RETURN ( false );
%}
!
eventsPending:anEventMask for:aWindowIdOrNil
"return true, if any of the masked events is pending"
%{ /* UNLIMITEDSTACK */
Display *dpy = myDpy;
XEvent ev;
Window win;
int thereIsOne;
if (__isSmallInteger(anEventMask)) {
XSync(dpy, 0); /* make certain everything is flushed */
if (__isSmallInteger(aWindowIdOrNil)) {
win = _WindowVal(aWindowIdOrNil);
thereIsOne = XCheckWindowEvent(dpy, win, _intVal(anEventMask), &ev);
} else {
thereIsOne = XCheckMaskEvent(dpy, _intVal(anEventMask), &ev);
}
if (thereIsOne) {
XPutBackEvent(dpy, &ev);
RETURN ( true );
}
}
RETURN ( false );
%}
!
eventPending:anEventSymbol for:aWindowIdOrNil
"return true, if a specific event is pending"
^ self eventsPending:(self eventMaskFor:anEventSymbol) for:aWindowIdOrNil
! !