changes for modifierMappings from stefan
authorClaus Gittinger <cg@exept.de>
Thu, 07 Dec 1995 21:00:08 +0100
changeset 288 5d49b00f2bad
parent 287 a2bb1a26212f
child 289 bcdc7ae29443
changes for modifierMappings from stefan
XWorkstat.st
XWorkstation.st
--- a/XWorkstat.st	Thu Dec 07 16:21:05 1995 +0100
+++ b/XWorkstat.st	Thu Dec 07 21:00:08 1995 +0100
@@ -50,7 +50,7 @@
 !
 
 version
-    ^ '$Header: /cvs/stx/stx/libview/Attic/XWorkstat.st,v 1.84 1995-12-06 14:12:16 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libview/Attic/XWorkstat.st,v 1.85 1995-12-07 20:00:08 cg Exp $'
 !
 
 documentation
@@ -509,13 +509,42 @@
     buttonTranslation := ButtonTranslation.
     multiClickTimeDelta := MultiClickTimeDelta.
 
-    "/ these should be queried from the server
-    "/ (this will soon be done) - for now, take standard values
-
-    altModifiers := #(Alt_L Alt_R).
-    metaModifiers := #(Meta_L Meta_R).
-    ctrlModifiers := #(Control_L Control_R).
-    shiftModifiers := #(Shift_L Shift_R).
+    self initializeModifierMappings
+!
+
+initializeModifierMappings
+    |map mod|
+
+"/    altModifiers := #(Alt_L Alt_R).
+"/    metaModifiers := #(Meta_L Meta_R).
+"/    ctrlModifiers := #(Control_L Control_R).
+"/    shiftModifiers := #(Shift_L Shift_R).
+
+    shiftModifiers := ctrlModifiers := altModifiers := metaModifiers := nil.
+    altModifierMask := metaModifierMask := nil.
+
+    map := self modifierMapping.
+
+    mod := map at:1.
+    mod notNil ifTrue:[
+	shiftModifiers := mod collect:[ :key | self stringFromKeycode:key ].
+    ].
+    mod := map at:3.
+    mod notNil ifTrue:[
+	ctrlModifiers  := mod collect:[ :key | self stringFromKeycode:key ].
+    ].
+    mod := map at:4.
+    mod notNil ifTrue:[
+	metaModifiers  := mod collect:[ :key | self stringFromKeycode:key ].    
+	metaModifierMask := 1 bitShift:(4-1).
+    ].
+    mod := map at:5.
+    mod notNil ifTrue:[
+	altModifiers   := mod collect:[ :key | self stringFromKeycode:key ].    
+	altModifierMask := 1 bitShift:(5-1).
+    ].
+
+    "Modified: 1.12.1995 / 23:44:40 / stefan"
 !
 
 initializeEventBuffer
@@ -808,6 +837,17 @@
 
 !XWorkstation methodsFor:'misc'!
 
+refreshKeyboardMapping:eB
+%{
+    XMappingEvent *ev;
+
+    if (__isByteArray(eB)) {
+	ev = (XMappingEvent *)(_ByteArrayInstPtr(eB)->ba_element);
+	XRefreshKeyboardMapping(ev);
+    }
+%}
+!
+
 setInputFocusTo:aWindowId
 "/    self setInputFocusTo:aWindowId revertTo:#parent
     self setInputFocusTo:aWindowId revertTo:#root
@@ -826,7 +866,7 @@
     Window focusWindow;
 
     if (ISCONNECTED) {
-        if (__isExternalAddress(aWindowId)) {
+	if (__isExternalAddress(aWindowId)) {
 	    focusWindow = _WindowVal(aWindowId);
 	} else {
 	    focusWindow = None;
@@ -1228,6 +1268,103 @@
     ^ false
 !
 
+iconSizes
+    "Get the preferrer icon sizes. These are set by the window manager.
+     We return nil (if not set) or an OrderedCollection of Intervals."
+
+    |xIconSizes count ret|
+
+%{
+    Display *dpy = myDpy;
+    int screen = _intVal(_INST(screen));
+    XIconSize *sizeList;
+    int cnt;
+
+    if (ISCONNECTED) {
+	if (XGetIconSizes(myDpy, RootWindow(dpy, screen), &sizeList, &cnt) > 0) {
+	   xIconSizes = __MKEXTERNALBYTES(sizeList);
+	   count = __MKSMALLINT(cnt);
+	}
+    }
+%}.
+    xIconSizes isNil ifTrue:[^ nil].
+
+    ret := OrderedCollection new:count.
+    1 to:count do:[ :i |
+	| startX startY stopX stopY stepX stepY|
+
+%{
+	XIconSize *slp;
+
+	slp = &((XIconSize *)__externalBytesAddress(xIconSizes))[__intVal(i)-1];
+	startX = __MKSMALLINT(slp->min_width);
+	startY = __MKSMALLINT(slp->min_height);
+	stopX = __MKSMALLINT(slp->max_width);
+	stopY = __MKSMALLINT(slp->max_height);
+	stepX = __MKSMALLINT(slp->width_inc);
+	stepY = __MKSMALLINT(slp->height_inc);
+%}.
+	ret add:(Interval from:startX@startY to:stopX@stopY by:stepX@stepY)
+    ].
+
+    xIconSizes free.
+    ^ ret
+
+    "
+	Display iconSizes
+    "
+!
+
+modifierMapping
+    "Get the Modifier Mapping.
+     We return an array of arrays of keycodes"
+
+    |modifierKeyMap maxKeyPerMod ret nextKey|
+
+%{
+    Display *dpy = myDpy;
+    XModifierKeymap *modmap;
+
+    if (ISCONNECTED) {
+	if ((modmap = XGetModifierMapping(myDpy)) != 0) {
+	   maxKeyPerMod = __MKSMALLINT(modmap->max_keypermod);
+	   modifierKeyMap = __BYTEARRAY_UNINITIALIZED_NEW_INT(modmap->max_keypermod * 8);
+	   if (modifierKeyMap != nil) {
+		maxKeyPerMod = __MKSMALLINT(modmap->max_keypermod);
+		memcpy((char *)__ByteArrayInstPtr(modifierKeyMap)->ba_element, 
+		       (char *)modmap->modifiermap, modmap->max_keypermod * 8);
+	   }
+	   XFreeModifiermap(modmap);
+	}
+    }
+%}.
+
+    modifierKeyMap isNil ifTrue:[^ nil].
+
+    ret := Array new:8.
+    nextKey := 1.
+    1 to:8 do:[ :i |
+	(modifierKeyMap at:nextKey) ~= 0 ifTrue:[
+	    |mod|
+
+	    mod := OrderedCollection new:maxKeyPerMod.
+	    modifierKeyMap from:nextKey to:(nextKey+maxKeyPerMod-1) do:[ :key |
+		key ~= 0 ifTrue:[
+		    mod add:key
+		].
+	    ].
+	    ret at:i put:mod.
+	].
+	nextKey := nextKey+maxKeyPerMod.
+    ].
+
+    ^ ret
+
+    "
+	Display modifierMapping
+    "
+!
+
 supportsViewGravity
     "return true, if this device supports gravity attributes.
      We do not depend on it being implemented, but some resizing operations
@@ -1248,6 +1385,29 @@
     ^ whitepixel
 !
 
+stringFromKeycode:code
+    "Get a KeySymbol (a smalltalk symbol) from the keycode."
+
+    |str|
+
+%{
+    Display *dpy = myDpy;
+    KeySym keysym;
+    char *keystring;
+
+    if (ISCONNECTED && __isSmallInteger(code)) {
+	if ((keysym = XKeycodeToKeysym(myDpy, __intVal(code), 0)) != NoSymbol &&
+	    (keystring = XKeysymToString(keysym)) != 0) 
+	    str = __MKSTRING(keystring);
+    }
+%}.
+    ^ str
+
+    "
+	Display stringFromKeycode:28
+    "
+!
+
 buttonMotionMask:aButton
     "return the state-mask for button1 in motion events state-field.
      This is the devices mask."
@@ -4829,8 +4989,7 @@
 	XSetForeground(myDpy, _GCVal(aGCId), _intVal(fgColorIndex));
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -4844,8 +5003,7 @@
 	XSetBackground(myDpy, _GCVal(aGCId), _intVal(bgColorIndex));
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -4863,8 +5021,7 @@
 	XSetBackground(dpy, gc, _intVal(bgColorIndex));
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -4893,8 +5050,7 @@
 	    RETURN ( self );
 	}
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -4929,8 +5085,7 @@
 	RETURN ( self );
     }
 bad: ;
-%}
-.
+%}.
     "
      either aGCId is invalid,
      and/or lineStyle is none of #solid, #dashed, #doubleDashed
@@ -4969,8 +5124,7 @@
 	    RETURN ( self );
 	}
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -4997,8 +5151,7 @@
 	    RETURN ( self );
 	}
     }
-%}
-.
+%}.
     "
      either aGCId is not an integer, or an invalid symbol
      was passed ... valid functions are #copy, #copyInverted, #xor, #and, #andReverse,
@@ -5020,8 +5173,7 @@
 	XSetFont(myDpy, _GCVal(aGCId), f->fid);
 	RETURN ( self );
     }
-%}
-.
+%}.
     "
      aGCId and/or aFontId are invalid
     "
@@ -5049,8 +5201,7 @@
 	    RETURN ( self );
 	}
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -5075,8 +5226,7 @@
 	    RETURN ( self );
 	}
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -5089,8 +5239,7 @@
 	XSetTSOrigin(myDpy, _GCVal(aGCid), _intVal(orgX), _intVal(orgY));
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -5111,8 +5260,7 @@
 	XChangeGC(myDpy, gc, GCSubwindowMode, &gcv);
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -5129,8 +5277,7 @@
 	XChangeGC(myDpy, gc, GCClipMask, &gcv);
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -5151,8 +5298,7 @@
 	XSetClipRectangles(myDpy, _GCVal(aGCId), 0, 0, &r, 1, Unsorted);
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -6186,6 +6332,7 @@
 #   define lwe ((XLeaveWindowEvent *)ev)
 #   define de ((XDestroyWindowEvent *)ev)
 #   define ve ((XVisibilityEvent *)ev)
+#   define mape ((XMappingEvent *)ev)
 
     KeySym keySym;
     unsigned char buffer[10];
@@ -6231,6 +6378,7 @@
     static struct inlineCache selReq = _ILC4;
     static struct inlineCache selNotify = _ILC4;
     static struct inlineCache colormap = _ILC0;
+    static struct inlineCache mapping = _ILC2;
     static struct inlineCache vis = _ILC1;
 
     static struct inlineCache skpS = _ILC4;
@@ -6247,7 +6395,7 @@
     windowID = __MKOBJ(ae->window);
     theView = (*vid.ilc_func)(self, @symbol(viewFromId:) COMMA_CON, nil, &vid, windowID);
 
-    if (theView == nil) {
+    if ((theView == nil) && (ev->type != MappingNotify)) {
 	RETURN (nil);
     }
 
@@ -6694,14 +6842,23 @@
 	    break;
 
 	case MappingNotify:
-/*
-printf("mapping\n");
-*/
-/*
-	    (*mapping.ilc_func)(theView, 
-				@symbol(mapping) 
-				COMMA_CON, nil, &mapping);
-*/
+	    switch(mape->request) {
+		case MappingModifier:
+		    arg = @symbol(mappingModifier);
+		    break;
+		case MappingKeyboard:
+		    arg = @symbol(mappingKeyboard);
+		    break;
+		case MappingPointer:
+		    arg = @symbol(mappingPointer);
+		    break;
+		default:
+		    arg = nil;
+		    break;
+	    }
+	    (*mapping.ilc_func)(self, 
+				@symbol(mappingChanged:event:) 
+				COMMA_CON, nil, &mapping, arg, eB);
 	    break;
     }
 #undef ae
@@ -6713,6 +6870,7 @@
 #undef ewe
 #undef lwe
 #undef de
+#undef mape
 %}
 .
     ^ true
@@ -6844,4 +7002,17 @@
     "return true, if a specific event is pending"
 
     ^ self eventsPending:(self eventMaskFor:anEventSymbol) for:aWindowIdOrNil
+!
+
+mappingChanged:what event:eB
+    "One of Keyboard-, Modifier- or PointerMap has change, probably by xmodmap.
+     Tell xlib about the fact."
+
+    (what == #mappingKeyboard or:[what == #mappingModifier]) ifTrue:[
+	self refreshKeyboardMapping:eB.
+	"Maybe some of our modifiers have been changed"
+	self initializeModifierMappings.
+    ].
+
+    "Created: 1.12.1995 / 16:28:23 / stefan"
 ! !
--- a/XWorkstation.st	Thu Dec 07 16:21:05 1995 +0100
+++ b/XWorkstation.st	Thu Dec 07 21:00:08 1995 +0100
@@ -50,7 +50,7 @@
 !
 
 version
-    ^ '$Header: /cvs/stx/stx/libview/XWorkstation.st,v 1.84 1995-12-06 14:12:16 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libview/XWorkstation.st,v 1.85 1995-12-07 20:00:08 cg Exp $'
 !
 
 documentation
@@ -509,13 +509,42 @@
     buttonTranslation := ButtonTranslation.
     multiClickTimeDelta := MultiClickTimeDelta.
 
-    "/ these should be queried from the server
-    "/ (this will soon be done) - for now, take standard values
-
-    altModifiers := #(Alt_L Alt_R).
-    metaModifiers := #(Meta_L Meta_R).
-    ctrlModifiers := #(Control_L Control_R).
-    shiftModifiers := #(Shift_L Shift_R).
+    self initializeModifierMappings
+!
+
+initializeModifierMappings
+    |map mod|
+
+"/    altModifiers := #(Alt_L Alt_R).
+"/    metaModifiers := #(Meta_L Meta_R).
+"/    ctrlModifiers := #(Control_L Control_R).
+"/    shiftModifiers := #(Shift_L Shift_R).
+
+    shiftModifiers := ctrlModifiers := altModifiers := metaModifiers := nil.
+    altModifierMask := metaModifierMask := nil.
+
+    map := self modifierMapping.
+
+    mod := map at:1.
+    mod notNil ifTrue:[
+	shiftModifiers := mod collect:[ :key | self stringFromKeycode:key ].
+    ].
+    mod := map at:3.
+    mod notNil ifTrue:[
+	ctrlModifiers  := mod collect:[ :key | self stringFromKeycode:key ].
+    ].
+    mod := map at:4.
+    mod notNil ifTrue:[
+	metaModifiers  := mod collect:[ :key | self stringFromKeycode:key ].    
+	metaModifierMask := 1 bitShift:(4-1).
+    ].
+    mod := map at:5.
+    mod notNil ifTrue:[
+	altModifiers   := mod collect:[ :key | self stringFromKeycode:key ].    
+	altModifierMask := 1 bitShift:(5-1).
+    ].
+
+    "Modified: 1.12.1995 / 23:44:40 / stefan"
 !
 
 initializeEventBuffer
@@ -808,6 +837,17 @@
 
 !XWorkstation methodsFor:'misc'!
 
+refreshKeyboardMapping:eB
+%{
+    XMappingEvent *ev;
+
+    if (__isByteArray(eB)) {
+	ev = (XMappingEvent *)(_ByteArrayInstPtr(eB)->ba_element);
+	XRefreshKeyboardMapping(ev);
+    }
+%}
+!
+
 setInputFocusTo:aWindowId
 "/    self setInputFocusTo:aWindowId revertTo:#parent
     self setInputFocusTo:aWindowId revertTo:#root
@@ -826,7 +866,7 @@
     Window focusWindow;
 
     if (ISCONNECTED) {
-        if (__isExternalAddress(aWindowId)) {
+	if (__isExternalAddress(aWindowId)) {
 	    focusWindow = _WindowVal(aWindowId);
 	} else {
 	    focusWindow = None;
@@ -1228,6 +1268,103 @@
     ^ false
 !
 
+iconSizes
+    "Get the preferrer icon sizes. These are set by the window manager.
+     We return nil (if not set) or an OrderedCollection of Intervals."
+
+    |xIconSizes count ret|
+
+%{
+    Display *dpy = myDpy;
+    int screen = _intVal(_INST(screen));
+    XIconSize *sizeList;
+    int cnt;
+
+    if (ISCONNECTED) {
+	if (XGetIconSizes(myDpy, RootWindow(dpy, screen), &sizeList, &cnt) > 0) {
+	   xIconSizes = __MKEXTERNALBYTES(sizeList);
+	   count = __MKSMALLINT(cnt);
+	}
+    }
+%}.
+    xIconSizes isNil ifTrue:[^ nil].
+
+    ret := OrderedCollection new:count.
+    1 to:count do:[ :i |
+	| startX startY stopX stopY stepX stepY|
+
+%{
+	XIconSize *slp;
+
+	slp = &((XIconSize *)__externalBytesAddress(xIconSizes))[__intVal(i)-1];
+	startX = __MKSMALLINT(slp->min_width);
+	startY = __MKSMALLINT(slp->min_height);
+	stopX = __MKSMALLINT(slp->max_width);
+	stopY = __MKSMALLINT(slp->max_height);
+	stepX = __MKSMALLINT(slp->width_inc);
+	stepY = __MKSMALLINT(slp->height_inc);
+%}.
+	ret add:(Interval from:startX@startY to:stopX@stopY by:stepX@stepY)
+    ].
+
+    xIconSizes free.
+    ^ ret
+
+    "
+	Display iconSizes
+    "
+!
+
+modifierMapping
+    "Get the Modifier Mapping.
+     We return an array of arrays of keycodes"
+
+    |modifierKeyMap maxKeyPerMod ret nextKey|
+
+%{
+    Display *dpy = myDpy;
+    XModifierKeymap *modmap;
+
+    if (ISCONNECTED) {
+	if ((modmap = XGetModifierMapping(myDpy)) != 0) {
+	   maxKeyPerMod = __MKSMALLINT(modmap->max_keypermod);
+	   modifierKeyMap = __BYTEARRAY_UNINITIALIZED_NEW_INT(modmap->max_keypermod * 8);
+	   if (modifierKeyMap != nil) {
+		maxKeyPerMod = __MKSMALLINT(modmap->max_keypermod);
+		memcpy((char *)__ByteArrayInstPtr(modifierKeyMap)->ba_element, 
+		       (char *)modmap->modifiermap, modmap->max_keypermod * 8);
+	   }
+	   XFreeModifiermap(modmap);
+	}
+    }
+%}.
+
+    modifierKeyMap isNil ifTrue:[^ nil].
+
+    ret := Array new:8.
+    nextKey := 1.
+    1 to:8 do:[ :i |
+	(modifierKeyMap at:nextKey) ~= 0 ifTrue:[
+	    |mod|
+
+	    mod := OrderedCollection new:maxKeyPerMod.
+	    modifierKeyMap from:nextKey to:(nextKey+maxKeyPerMod-1) do:[ :key |
+		key ~= 0 ifTrue:[
+		    mod add:key
+		].
+	    ].
+	    ret at:i put:mod.
+	].
+	nextKey := nextKey+maxKeyPerMod.
+    ].
+
+    ^ ret
+
+    "
+	Display modifierMapping
+    "
+!
+
 supportsViewGravity
     "return true, if this device supports gravity attributes.
      We do not depend on it being implemented, but some resizing operations
@@ -1248,6 +1385,29 @@
     ^ whitepixel
 !
 
+stringFromKeycode:code
+    "Get a KeySymbol (a smalltalk symbol) from the keycode."
+
+    |str|
+
+%{
+    Display *dpy = myDpy;
+    KeySym keysym;
+    char *keystring;
+
+    if (ISCONNECTED && __isSmallInteger(code)) {
+	if ((keysym = XKeycodeToKeysym(myDpy, __intVal(code), 0)) != NoSymbol &&
+	    (keystring = XKeysymToString(keysym)) != 0) 
+	    str = __MKSTRING(keystring);
+    }
+%}.
+    ^ str
+
+    "
+	Display stringFromKeycode:28
+    "
+!
+
 buttonMotionMask:aButton
     "return the state-mask for button1 in motion events state-field.
      This is the devices mask."
@@ -4829,8 +4989,7 @@
 	XSetForeground(myDpy, _GCVal(aGCId), _intVal(fgColorIndex));
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -4844,8 +5003,7 @@
 	XSetBackground(myDpy, _GCVal(aGCId), _intVal(bgColorIndex));
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -4863,8 +5021,7 @@
 	XSetBackground(dpy, gc, _intVal(bgColorIndex));
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -4893,8 +5050,7 @@
 	    RETURN ( self );
 	}
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -4929,8 +5085,7 @@
 	RETURN ( self );
     }
 bad: ;
-%}
-.
+%}.
     "
      either aGCId is invalid,
      and/or lineStyle is none of #solid, #dashed, #doubleDashed
@@ -4969,8 +5124,7 @@
 	    RETURN ( self );
 	}
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -4997,8 +5151,7 @@
 	    RETURN ( self );
 	}
     }
-%}
-.
+%}.
     "
      either aGCId is not an integer, or an invalid symbol
      was passed ... valid functions are #copy, #copyInverted, #xor, #and, #andReverse,
@@ -5020,8 +5173,7 @@
 	XSetFont(myDpy, _GCVal(aGCId), f->fid);
 	RETURN ( self );
     }
-%}
-.
+%}.
     "
      aGCId and/or aFontId are invalid
     "
@@ -5049,8 +5201,7 @@
 	    RETURN ( self );
 	}
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -5075,8 +5226,7 @@
 	    RETURN ( self );
 	}
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -5089,8 +5239,7 @@
 	XSetTSOrigin(myDpy, _GCVal(aGCid), _intVal(orgX), _intVal(orgY));
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -5111,8 +5260,7 @@
 	XChangeGC(myDpy, gc, GCSubwindowMode, &gcv);
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -5129,8 +5277,7 @@
 	XChangeGC(myDpy, gc, GCClipMask, &gcv);
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -5151,8 +5298,7 @@
 	XSetClipRectangles(myDpy, _GCVal(aGCId), 0, 0, &r, 1, Unsorted);
 	RETURN ( self );
     }
-%}
-.
+%}.
     self primitiveFailed
 !
 
@@ -6186,6 +6332,7 @@
 #   define lwe ((XLeaveWindowEvent *)ev)
 #   define de ((XDestroyWindowEvent *)ev)
 #   define ve ((XVisibilityEvent *)ev)
+#   define mape ((XMappingEvent *)ev)
 
     KeySym keySym;
     unsigned char buffer[10];
@@ -6231,6 +6378,7 @@
     static struct inlineCache selReq = _ILC4;
     static struct inlineCache selNotify = _ILC4;
     static struct inlineCache colormap = _ILC0;
+    static struct inlineCache mapping = _ILC2;
     static struct inlineCache vis = _ILC1;
 
     static struct inlineCache skpS = _ILC4;
@@ -6247,7 +6395,7 @@
     windowID = __MKOBJ(ae->window);
     theView = (*vid.ilc_func)(self, @symbol(viewFromId:) COMMA_CON, nil, &vid, windowID);
 
-    if (theView == nil) {
+    if ((theView == nil) && (ev->type != MappingNotify)) {
 	RETURN (nil);
     }
 
@@ -6694,14 +6842,23 @@
 	    break;
 
 	case MappingNotify:
-/*
-printf("mapping\n");
-*/
-/*
-	    (*mapping.ilc_func)(theView, 
-				@symbol(mapping) 
-				COMMA_CON, nil, &mapping);
-*/
+	    switch(mape->request) {
+		case MappingModifier:
+		    arg = @symbol(mappingModifier);
+		    break;
+		case MappingKeyboard:
+		    arg = @symbol(mappingKeyboard);
+		    break;
+		case MappingPointer:
+		    arg = @symbol(mappingPointer);
+		    break;
+		default:
+		    arg = nil;
+		    break;
+	    }
+	    (*mapping.ilc_func)(self, 
+				@symbol(mappingChanged:event:) 
+				COMMA_CON, nil, &mapping, arg, eB);
 	    break;
     }
 #undef ae
@@ -6713,6 +6870,7 @@
 #undef ewe
 #undef lwe
 #undef de
+#undef mape
 %}
 .
     ^ true
@@ -6844,4 +7002,17 @@
     "return true, if a specific event is pending"
 
     ^ self eventsPending:(self eventMaskFor:anEventSymbol) for:aWindowIdOrNil
+!
+
+mappingChanged:what event:eB
+    "One of Keyboard-, Modifier- or PointerMap has change, probably by xmodmap.
+     Tell xlib about the fact."
+
+    (what == #mappingKeyboard or:[what == #mappingModifier]) ifTrue:[
+	self refreshKeyboardMapping:eB.
+	"Maybe some of our modifiers have been changed"
+	self initializeModifierMappings.
+    ].
+
+    "Created: 1.12.1995 / 16:28:23 / stefan"
 ! !