// Lower a popup to the bottom of the mapped list. public void LowerPopup(PopupWindow popup) { int index; lock (this) { for (index = list.Length - 1; index >= 0; --index) { if (list[index] == popup) { while (index > 0) { list[index] = list[index - 1]; --index; } list[0] = popup; return; } } } }
// Change the "lastEntered" and "lastChildEntered" window. // The popup is entered before the child and left after. private void ChangeEntered(PopupWindow popup, InputOutputWidget child) { PopupWindow before = null; PopupWindow after = null; InputOutputWidget childBefore = null; InputOutputWidget childAfter = null; lock (this) { if (lastEntered != popup) { before = lastEntered; after = popup; lastEntered = popup; } if (lastChildEntered != child) { childBefore = lastChildEntered; childAfter = child; lastChildEntered = child; } } if (before != null) { if (childBefore != null) { FakeLeave(childBefore); } FakeLeave(before); } if (after != null) { FakeEnter(after); if (childAfter != null) { FakeEnter(childAfter); } } }
// Dispatch an event to this widget. internal override void DispatchEvent(ref XEvent xevent) { XKeySym keysym; PopupWindow popup; InputOutputWidget child = null; switch ((EventType)(xevent.xany.type__)) { case EventType.ButtonPress: { // A mouse button was pressed during the grab. lock (this) { if (lastButton != null) { // We currently have a button window, so // all mouse events should go to it. popup = lastButton; } else { // Determine which popup contains the mouse. // If nothing contains, then use the top. popup = Find(xevent.xbutton.x_root, xevent.xbutton.y_root, true); } lastButton = popup; } // Find the child window. child = FindChild(popup, xevent.xbutton.x_root, xevent.xbutton.y_root); ChangeEntered(popup, child); if (popup != null) { // Adjust the co-ordinates and re-dispatch. xevent.xbutton.x__ = (Xlib.Xint)(xevent.xbutton.x_root - popup.x); xevent.xbutton.y__ = (Xlib.Xint)(xevent.xbutton.y_root - popup.y); popup.DispatchEvent(ref xevent); // Re-dispatch to the child window if necessary. if (child != null) { xevent.xbutton.x__ -= child.x; xevent.xbutton.y__ -= child.y; child.DispatchEvent(ref xevent); } } } break; case EventType.ButtonRelease: { // A mouse button was released during the grab. lock (this) { popup = lastButton; if (popup != null) { // Reset "lastButton" if this is the last // button to be released. ModifierMask mask = ModifierMask.AllButtons; mask &= (ModifierMask) ~((int)ModifierMask.Button1Mask << ((int)(xevent.xbutton.button__) - 1)); if ((xevent.xbutton.state & mask) == 0) { lastButton = null; } } } // Find the child window. child = FindChild(popup, xevent.xbutton.x_root, xevent.xbutton.y_root); ChangeEntered(popup, child); if (popup != null) { // Adjust the co-ordinates and re-dispatch. xevent.xbutton.x__ = (Xlib.Xint)(xevent.xbutton.x_root - popup.x); xevent.xbutton.y__ = (Xlib.Xint)(xevent.xbutton.y_root - popup.y); popup.DispatchEvent(ref xevent); // Re-dispatch to the child window if necessary. if (child != null) { xevent.xbutton.x__ -= child.x; xevent.xbutton.y__ -= child.y; child.DispatchEvent(ref xevent); } } } break; case EventType.MotionNotify: { // The mouse pointer was moved during the grab. lock (this) { // If there is a last button window, then use // that, otherwise find the one under the mouse. popup = lastButton; if (popup == null) { popup = Find(xevent.xmotion.x_root, xevent.xmotion.y_root, false); } } // Find the child window. child = FindChild(popup, xevent.xbutton.x_root, xevent.xbutton.y_root); ChangeEntered(popup, child); if (popup != null) { // Adjust the co-ordinates and re-dispatch. xevent.xmotion.x__ = (Xlib.Xint)(xevent.xmotion.x_root - popup.x); xevent.xmotion.y__ = (Xlib.Xint)(xevent.xmotion.y_root - popup.y); popup.DispatchEvent(ref xevent); // Re-dispatch to the child window if necessary. if (child != null) { xevent.xbutton.x__ -= child.x; xevent.xbutton.y__ -= child.y; child.DispatchEvent(ref xevent); } } } break; case EventType.KeyPress: { // Convert the event into a symbol and a string. if (keyBuffer == IntPtr.Zero) { keyBuffer = Marshal.AllocHGlobal(32); } keysym = 0; int len = Xlib.XLookupString (ref xevent.xkey, keyBuffer, 32, ref keysym, IntPtr.Zero); String str; if (len > 0) { str = Marshal.PtrToStringAnsi(keyBuffer, len); } else { str = null; } // Dispatch the event to the top-most popup. lock (this) { if (list.Length > 0) { popup = list[list.Length - 1]; } else { popup = null; } } if (popup != null) { // Find the child window. child = FindFocusedChild(popup); if (child == null) { popup.DispatchKeyEvent ((KeyName)keysym, xevent.xkey.state, str); } else { child.DispatchKeyEvent ((KeyName)keysym, xevent.xkey.state, str); } } } break; case EventType.KeyRelease: { // Convert the event into a symbol and a string. if (keyBuffer == IntPtr.Zero) { keyBuffer = Marshal.AllocHGlobal(32); } keysym = 0; int len = Xlib.XLookupString (ref xevent.xkey, keyBuffer, 32, ref keysym, IntPtr.Zero); // Dispatch the event to the top-most popup. lock (this) { if (list.Length > 0) { popup = list[list.Length - 1]; } else { popup = null; } } if (popup != null) { // Find the child window. child = FindFocusedChild(popup); if (child == null) { popup.DispatchKeyReleaseEvent ((KeyName)keysym, xevent.xkey.state); } else { child.DispatchKeyReleaseEvent ((KeyName)keysym, xevent.xkey.state); } } } break; default: { // Everything else is handled normally. base.DispatchEvent(ref xevent); } break; } }
// Dispatch an event to this widget. internal override void DispatchEvent(ref XEvent xevent) { XKeySym keysym; PopupWindow popup; InputOutputWidget child = null; switch((EventType)(xevent.xany.type__)) { case EventType.ButtonPress: { // A mouse button was pressed during the grab. lock(this) { if(lastButton != null) { // We currently have a button window, so // all mouse events should go to it. popup = lastButton; } else { // Determine which popup contains the mouse. // If nothing contains, then use the top. popup = Find(xevent.xbutton.x_root, xevent.xbutton.y_root, true); } lastButton = popup; } // Find the child window. child = FindChild(popup, xevent.xbutton.x_root, xevent.xbutton.y_root); ChangeEntered(popup, child); if(popup != null) { // Adjust the co-ordinates and re-dispatch. xevent.xbutton.x__ = (Xlib.Xint)(xevent.xbutton.x_root - popup.x); xevent.xbutton.y__ = (Xlib.Xint)(xevent.xbutton.y_root - popup.y); popup.DispatchEvent(ref xevent); // Re-dispatch to the child window if necessary. if (child != null) { xevent.xbutton.x__ -= child.x; xevent.xbutton.y__ -= child.y; child.DispatchEvent(ref xevent); } } } break; case EventType.ButtonRelease: { // A mouse button was released during the grab. lock(this) { popup = lastButton; if(popup != null) { // Reset "lastButton" if this is the last // button to be released. ModifierMask mask = ModifierMask.AllButtons; mask &= (ModifierMask)~((int)ModifierMask.Button1Mask << ((int)(xevent.xbutton.button__) - 1)); if((xevent.xbutton.state & mask) == 0) { lastButton = null; } } } // Find the child window. child = FindChild(popup, xevent.xbutton.x_root, xevent.xbutton.y_root); ChangeEntered(popup, child); if(popup != null) { // Adjust the co-ordinates and re-dispatch. xevent.xbutton.x__ = (Xlib.Xint)(xevent.xbutton.x_root - popup.x); xevent.xbutton.y__ = (Xlib.Xint)(xevent.xbutton.y_root - popup.y); popup.DispatchEvent(ref xevent); // Re-dispatch to the child window if necessary. if (child != null) { xevent.xbutton.x__ -= child.x; xevent.xbutton.y__ -= child.y; child.DispatchEvent(ref xevent); } } } break; case EventType.MotionNotify: { // The mouse pointer was moved during the grab. lock(this) { // If there is a last button window, then use // that, otherwise find the one under the mouse. popup = lastButton; if(popup == null) { popup = Find(xevent.xmotion.x_root, xevent.xmotion.y_root, false); } } // Find the child window. child = FindChild(popup, xevent.xbutton.x_root, xevent.xbutton.y_root); ChangeEntered(popup, child); if(popup != null) { // Adjust the co-ordinates and re-dispatch. xevent.xmotion.x__ = (Xlib.Xint)(xevent.xmotion.x_root - popup.x); xevent.xmotion.y__ = (Xlib.Xint)(xevent.xmotion.y_root - popup.y); popup.DispatchEvent(ref xevent); // Re-dispatch to the child window if necessary. if (child != null) { xevent.xbutton.x__ -= child.x; xevent.xbutton.y__ -= child.y; child.DispatchEvent(ref xevent); } } } break; case EventType.KeyPress: { // Convert the event into a symbol and a string. if(keyBuffer == IntPtr.Zero) { keyBuffer = Marshal.AllocHGlobal(32); } keysym = 0; int len = Xlib.XLookupString (ref xevent.xkey, keyBuffer, 32, ref keysym, IntPtr.Zero); String str; if(len > 0) { str = Marshal.PtrToStringAnsi(keyBuffer, len); } else { str = null; } // Dispatch the event to the top-most popup. lock(this) { if(list.Length > 0) { popup = list[list.Length - 1]; } else { popup = null; } } if(popup != null) { // Find the child window. child = FindFocusedChild(popup); if (child == null) popup.DispatchKeyEvent ((KeyName)keysym, xevent.xkey.state, str); else child.DispatchKeyEvent ((KeyName)keysym, xevent.xkey.state, str); } } break; case EventType.KeyRelease: { // Convert the event into a symbol and a string. if(keyBuffer == IntPtr.Zero) { keyBuffer = Marshal.AllocHGlobal(32); } keysym = 0; int len = Xlib.XLookupString (ref xevent.xkey, keyBuffer, 32, ref keysym, IntPtr.Zero); // Dispatch the event to the top-most popup. lock(this) { if(list.Length > 0) { popup = list[list.Length - 1]; } else { popup = null; } } if(popup != null) { // Find the child window. child = FindFocusedChild(popup); if (child == null) popup.DispatchKeyReleaseEvent ((KeyName)keysym, xevent.xkey.state); else child.DispatchKeyReleaseEvent ((KeyName)keysym, xevent.xkey.state); } } break; default: { // Everything else is handled normally. base.DispatchEvent(ref xevent); } break; } }
// Change the "lastEntered" and "lastChildEntered" window. // The popup is entered before the child and left after. private void ChangeEntered(PopupWindow popup, InputOutputWidget child) { PopupWindow before = null; PopupWindow after = null; InputOutputWidget childBefore = null; InputOutputWidget childAfter = null; lock(this) { if(lastEntered != popup) { before = lastEntered; after = popup; lastEntered = popup; } if(lastChildEntered != child) { childBefore = lastChildEntered; childAfter = child; lastChildEntered = child; } } if(before != null) { if (childBefore != null) FakeLeave(childBefore); FakeLeave(before); } if(after != null) { FakeEnter(after); if (childAfter != null) FakeEnter(childAfter); } }
// Lower a popup to the bottom of the mapped list. public void LowerPopup(PopupWindow popup) { int index; lock(this) { for(index = list.Length - 1; index >= 0; --index) { if(list[index] == popup) { while(index > 0) { list[index] = list[index - 1]; --index; } list[0] = popup; return; } } } }
// Remove a popup from the mapped list. public void RemovePopup(PopupWindow popup) { int index; lock(this) { for(index = list.Length - 1; index >= 0; --index) { if(list[index] == popup) { // Remove the item from the list. PopupWindow[] newList; newList = new PopupWindow [list.Length - 1]; Array.Copy(list, 0, newList, 0, index); Array.Copy(list, index + 1, newList, index, list.Length - index - 1); list = newList; // If this was the entered window, then // send it a fake "LeaveNotify" event. if(lastChildEntered != null && lastChildEntered.Parent == popup) { FakeLeave(lastChildEntered); lastChildEntered = null; } if(lastEntered == popup) { lastEntered = null; FakeLeave(popup); } // If this was the button window, then clear it. if(lastButton == popup) { lastButton = null; } // If the list is now empty, then ungrab. if(list.Length == 0) { Ungrab(); } return; } } } }
// Add a popup to the top of the mapped list. public void AddPopup(PopupWindow popup) { int index; lock(this) { // See if the popup is already in the list. for(index = 0; index < list.Length; ++index) { if(list[index] == popup) { while(index < (list.Length - 1)) { list[index] = list[index + 1]; ++index; } list[index] = popup; return; } } // Re-allocate the list and add the new item. PopupWindow[] newList = new PopupWindow [list.Length + 1]; Array.Copy(list, 0, newList, 0, list.Length); newList[list.Length] = popup; list = newList; // If the list now contains one item, then grab. if(list.Length == 1) { Grab(); } } }