dotgnu-pnet-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Dotgnu-pnet-commits] CVS: pnetlib/Xsharp GrabWindow.cs,NONE,1.1 Overrid


From: Rhys Weatherley <address@hidden>
Subject: [Dotgnu-pnet-commits] CVS: pnetlib/Xsharp GrabWindow.cs,NONE,1.1 OverrideWindow.cs,NONE,1.1 PopupWindow.cs,NONE,1.1 ModifierMask.cs,1.1,1.2 Screen.cs,1.2,1.3 Xlib.cs.in,1.10,1.11
Date: Mon, 23 Jun 2003 22:18:58 -0400

Update of /cvsroot/dotgnu-pnet/pnetlib/Xsharp
In directory subversions:/tmp/cvs-serv12850/Xsharp

Modified Files:
        ModifierMask.cs Screen.cs Xlib.cs.in 
Added Files:
        GrabWindow.cs OverrideWindow.cs PopupWindow.cs 
Log Message:


Add popup window support to Xsharp, to support menu functionality.


--- NEW FILE ---
/*
 * GrabWindow.cs - Window that captures all events during an active grab.
 *
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

namespace Xsharp
{

using System;
using System.Runtime.InteropServices;
using Xsharp.Events;

// When a "PopupWindow" instance is displayed on-screen, all mouse
// and keyboard events are routed to the grab window.  From there,
// they are dispatched to the approriate popup window.  The grab
// ends when the last popup window is unmapped.

internal class GrabWindow : OverrideWindow
{
        // Internal state.
        private PopupWindow[] list;
        private PopupWindow lastEntered;
        private PopupWindow lastButton;
        private IntPtr keyBuffer;

        // Constructor.
        public GrabWindow(Widget parent)
                        : base(parent, -1, -1, 1, 1)
                        {
                                // Create the initial list of popup windows.
                                list = new PopupWindow [0];

                                // The grab window is always mapped, but just 
off-screen
                                // so that it isn't visible to the user.
                                Map();
                        }

        // Destructor.
        ~GrabWindow()
                        {
                                if(keyBuffer != IntPtr.Zero)
                                {
                                        Marshal.FreeHGlobal(keyBuffer);
                                        keyBuffer = IntPtr.Zero;
                                }
                        }

        // Grab control of the mouse and keyboard to manage popups.
        private void Grab()
                        {
                                try
                                {
                                        IntPtr display = dpy.Lock();
                                        Xlib.Window handle = GetWidgetHandle();
                                        Xlib.XGrabKeyboard
                                                (display, handle, 
Xlib.Bool.False,
                                                 1 /* GrabModeAsync */, 1 /* 
GrabModeAsync */,
                                                 dpy.knownEventTime);
                                        Xlib.XGrabPointer
                                                (display, handle, 
Xlib.Bool.False,
                                                 
(uint)(EventMask.ButtonPressMask |
                                                                
EventMask.ButtonReleaseMask |
                                                                
EventMask.PointerMotionMask),
                                                 1 /* GrabModeAsync */, 1 /* 
GrabModeAsync */,
                                                 Xlib.Window.Zero, 
Xlib.Cursor.Zero,
                                                 dpy.knownEventTime);
                                        Xlib.XFlush(display);
                                }
                                finally
                                {
                                        dpy.Unlock();
                                }
                        }

        // Ungrab the mouse and keyboard because there are no more popups.
        private void Ungrab()
                        {
                                try
                                {
                                        IntPtr display = dpy.Lock();
                                        Xlib.XUngrabPointer(display, 
dpy.knownEventTime);
                                        Xlib.XUngrabKeyboard(display, 
dpy.knownEventTime);
                                        Xlib.XFlush(display);
                                }
                                finally
                                {
                                        dpy.Unlock();
                                }
                        }

        // 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();
                                        }
                                }
                        }

        // 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(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;
                                                }
                                        }
                                }
                        }

        // 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;
                                                }
                                        }
                                }
                        }

        // Send a fake "EnterNotify" event to a popup window.
        private static void FakeEnter(PopupWindow popup)
                        {
                                if(popup != null)
                                {
                                        XEvent xevent = new XEvent();
                                        xevent.xany.type__ =
                                                
(Xlib.Xint)(int)(EventType.EnterNotify);
                                        popup.DispatchEvent(ref xevent);
                                }
                        }

        // Send a fake "LeaveNotify" event to a popup window.
        private static void FakeLeave(PopupWindow popup)
                        {
                                if(popup != null)
                                {
                                        XEvent xevent = new XEvent();
                                        xevent.xany.type__ =
                                                
(Xlib.Xint)(int)(EventType.LeaveNotify);
                                        popup.DispatchEvent(ref xevent);
                                }
                        }

        // Change the "lastEntered" window.
        private void ChangeEntered(PopupWindow popup)
                        {
                                PopupWindow before = null;
                                PopupWindow after = null;
                                lock(this)
                                {
                                        if(lastEntered != popup)
                                        {
                                                before = lastEntered;
                                                after = popup;
                                                lastEntered = popup;
                                        }
                                }
                                if(before != null)
                                {
                                        FakeLeave(before);
                                }
                                if(after != null)
                                {
                                        FakeEnter(after);
                                }
                        }

        // Find the popup window that contains a particular mouse position.
        private PopupWindow Find(int x, int y, bool defaultIsTop)
                        {
                                int index;
                                PopupWindow popup;
                                for(index = 0; index < list.Length; ++index)
                                {
                                        popup = list[index];
                                        if(x >= popup.x && x < (popup.x + 
popup.width) &&
                                           y >= popup.y && y < (popup.y + 
popup.height))
                                        {
                                                return popup;
                                        }
                                }
                                if(defaultIsTop && list.Length > 0)
                                {
                                        return list[list.Length - 1];
                                }
                                else
                                {
                                        return null;
                                }
                        }

        // Dispatch an event to this widget.
        internal override void DispatchEvent(ref XEvent xevent)
                        {
                                Xlib.KeySym keysym;
                                PopupWindow popup;

                                switch(xevent.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;
                                                }
                                                ChangeEntered(popup);
                                                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);
                                                }
                                        }
                                        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.Button1Mask <<
                                                                        
(((int)(xevent.xbutton.button__)) - 1));
                                                                
if((xevent.xbutton.state & mask) == 0)
                                                                {
                                                                        
lastButton = null;
                                                                }
                                                        }
                                                }
                                                ChangeEntered(popup);
                                                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);
                                                }
                                        }
                                        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);
                                                        }
                                                }
                                                ChangeEntered(popup);
                                                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);
                                                }
                                        }
                                        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)
                                                {
                                                        popup.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)
                                                {
                                                        
popup.DispatchKeyReleaseEvent
                                                                
((KeyName)keysym, xevent.xkey.state);
                                                }
                                        }
                                        break;

                                        default:
                                        {
                                                // Everything else is handled 
normally.
                                                base.DispatchEvent(ref xevent);
                                        }
                                        break;
                                }
                        }

} // class GrabWindow

} // namespace Xsharp

--- NEW FILE ---
/*
 * OverrideWindow.cs - Widget handling for override-redirect windows.
 *
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

namespace Xsharp
{

using System;

/// <summary>
/// <para>The <see cref="T:Xsharp.OverrideWindow"/> class manages
/// windows that have the override-redirect bit set.</para>
///
/// <para>Applications should inherit from <see cref="T:Xsharp.PopupWindow"/>
/// instead of this class.</para>
/// </summary>
public class OverrideWindow : InputOutputWidget
{
        // Constructor.
        internal OverrideWindow(Widget parent, int x, int y, int width, int 
height)
                        : base(parent, x, y, width, height,
                                   new Color(StandardColor.Foreground),
                                   new Color(StandardColor.Background),
                                   true, true)
                        {
                                // Nothing to do here.
                        }

} // class OverrideWindow

} // namespace Xsharp

--- NEW FILE ---
/*
 * PopupWindow.cs - Widget handling for popup windows.
 *
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

namespace Xsharp
{

using System;

/// <summary>
/// <para>The <see cref="T:Xsharp.PopupWindow"/> class manages
/// popup windows that display top-level on the screen, but do not
/// have window manager borders.  The mouse and keyboard will be
/// grabbed while a popup window is mapped to the screen.</para>
/// </summary>
public class PopupWindow : OverrideWindow
{
        /// <summary>
        /// <para>Constructs a new <see cref="T:Xsharp.PopupWindow"/>
        /// instance.</para>
        /// </summary>
        ///
        /// <param name="x">
        /// <para>The X position of the new window.</para>
        /// </param>
        ///
        /// <param name="y">
        /// <para>The Y position of the new window.</para>
        /// </param>
        ///
        /// <param name="width">
        /// <para>The width of the new window.</para>
        /// </param>
        ///
        /// <param name="height">
        /// <para>The height of the new window.</para>
        /// </param>
        ///
        /// <exception cref="T:Xsharp.XException">
        /// <para>Raised if any of the parameters are out of range.</para>
        /// </exception>
        ///
        /// <summary>
        /// <para>This version of the constructor creates the window on
        /// the default screen of the primary display.</para>
        /// </summary>
        public PopupWindow(int x, int y, int width, int height)
                        : base(TopLevelWindow.GetRoot(null), x, y, width, 
height)
                        {
                                // Nothing to do here.
                        }

        /// <summary>
        /// <para>Constructs a new <see cref="T:Xsharp.PopupWindow"/>
        /// instance.</para>
        /// </summary>
        ///
        /// <param name="screen">
        /// <para>The screen to display the window on, or <see langword="null"/>
        /// to use the default screen of the primary display.</para>
        /// </param>
        ///
        /// <param name="x">
        /// <para>The X position of the new window.</para>
        /// </param>
        ///
        /// <param name="y">
        /// <para>The Y position of the new window.</para>
        /// </param>
        ///
        /// <param name="width">
        /// <para>The width of the new window.</para>
        /// </param>
        ///
        /// <param name="height">
        /// <para>The height of the new window.</para>
        /// </param>
        ///
        /// <exception cref="T:Xsharp.XException">
        /// <para>Raised if any of the parameters are out of range.</para>
        /// </exception>
        public PopupWindow(Screen screen, int x, int y, int width, int height)
                        : base(TopLevelWindow.GetRoot(screen), x, y, width, 
height)
                        {
                                // Nothing to do here.
                        }

        // Get the grab window that is associated with this popup.
        private GrabWindow GetGrabWindow()
                        {
                                return screen.grabWindow;
                        }

        /// <summary>
        /// <para>Destroy this widget if it is currently active.</para>
        /// </summary>
        public override void Destroy()
                        {
                                GetGrabWindow().RemovePopup(this);
                                base.Destroy();
                        }

        /// <summary>
        /// <para>Map this widget to the screen.</para>
        /// </summary>
        public override void Map()
                        {
                                if(!IsMapped)
                                {
                                        GetGrabWindow().AddPopup(this);
                                        base.Raise();
                                        base.Map();
                                }
                        }

        /// <summary>
        /// <para>Unmap this widget from the screen.</para>
        /// </summary>
        public override void Unmap()
                        {
                                if(IsMapped)
                                {
                                        GetGrabWindow().RemovePopup(this);
                                        base.Unmap();
                                }
                        }

        /// <summary>
        /// <para>Raise this widget to the top of its layer.</para>
        /// </summary>
        public override void Raise()
                        {
                                if(IsMapped)
                                {
                                        GetGrabWindow().AddPopup(this);
                                }
                                base.Raise();
                        }

        /// <summary>
        /// <para>Lower this widget to the bottom of its layer.</para>
        /// </summary>
        public override void Lower()
                        {
                                if(IsMapped)
                                {
                                        GetGrabWindow().LowerPopup(this);
                                }
                                base.Lower();
                        }

} // class PopupWindow

} // namespace Xsharp

Index: ModifierMask.cs
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnetlib/Xsharp/ModifierMask.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -r1.1 -r1.2
*** ModifierMask.cs     28 May 2003 04:17:53 -0000      1.1
--- ModifierMask.cs     24 Jun 2003 02:18:56 -0000      1.2
***************
*** 45,49 ****
        Button4Mask             = (1<<11),
        Button5Mask             = (1<<12),
!       AnyModifier             = (1<<15)
  
  } // enum ModifierMask
--- 45,51 ----
        Button4Mask             = (1<<11),
        Button5Mask             = (1<<12),
!       AnyModifier             = (1<<15),
!       AllButtons              = Button1Mask | Button2Mask | Button3Mask |
!                                         Button4Mask | Button5Mask
  
  } // enum ModifierMask

Index: Screen.cs
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnetlib/Xsharp/Screen.cs,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -r1.2 -r1.3
*** Screen.cs   7 Jun 2003 00:13:09 -0000       1.2
--- Screen.cs   24 Jun 2003 02:18:56 -0000      1.3
***************
*** 45,48 ****
--- 45,49 ----
        private const int GCCacheSize = 16;
        private Color[] standardColors;
+       internal GrabWindow grabWindow;
  
        // Constructor.
***************
*** 74,77 ****
--- 75,81 ----
                                // Create the placeholder window for 
parent-less widgets.
                                placeholder = new PlaceholderWindow(rootWindow);
+ 
+                               // Create the grab window for managing popup 
window events.
+                               grabWindow = new GrabWindow(rootWindow);
                        }
  

Index: Xlib.cs.in
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnetlib/Xsharp/Xlib.cs.in,v
retrieving revision 1.10
retrieving revision 1.11
diff -C2 -r1.10 -r1.11
*** Xlib.cs.in  20 Jun 2003 23:28:28 -0000      1.10
--- Xlib.cs.in  24 Jun 2003 02:18:56 -0000      1.11
***************
*** 210,213 ****
--- 210,230 ----
                         out Xuint border_width_return, out Xuint depth_return);
  
+       [DllImport("X11")]
+       extern public static @X_int@ XGrabKeyboard
+                       (IntPtr display, Window grab_window, Bool owner_events,
+                        @X_int@ pointer_mode, @X_int@ keyboard_mode, Time 
time);
+ 
+       [DllImport("X11")]
+       extern public static @X_int@ XGrabPointer
+                       (IntPtr display, Window grab_window, Bool owner_events,
+                        @X_uint@ event_mask, @X_int@ pointer_mode, @X_int@ 
keyboard_mode,
+                        Window confine_to, Cursor cursor, Time time);
+ 
+       [DllImport("X11")]
+       extern public static @X_int@ XUngrabKeyboard(IntPtr display, Time time);
+ 
+       [DllImport("X11")]
+       extern public static @X_int@ XUngrabPointer(IntPtr display, Time time);
+ 
        // Declare pixmap-related external functions.
  





reply via email to

[Prev in Thread] Current Thread [Next in Thread]