// Handle a move/resize operation from "CaptionWidget".
	internal void HandleMoveResize(int x, int y, int width, int height)
			{
				bool changed = (x != this.x || y != this.y ||
				                width != this.width || height != this.height);
				this.x = x;
				this.y = y;
				this.width = width;
				this.height = height;
				if(changed)
				{
					// Queue up the "OnMoveResize" for the next idle period.
					if(resizeTimer == null)
					{
						resizeTimer = new Timer
							(new TimerCallback(PerformResize), null,
							 0, -1);
					}
				}
			}
	// Perform an actual resize operation.  This will be called at the
	// next convenient idle period, to avoid overflowing the event queue.
	private void PerformResize(Object state)
			{
				if(resizeTimer != null)
				{
					resizeTimer.Stop();
					resizeTimer = null;
				}
				expectedWidth = -1;
				expectedHeight = -1;
				if(mdiClient != null)
				{
					mdiClient.PositionControls();
				}
				OnMoveResize(x, y, width, height);
			}
	// Dispatch an event to this widget.
	internal override void DispatchEvent(ref XEvent xevent)
			{
				XKeySym keysym;
				Widget widget;
				InputOnlyWidget io;
				Xlib.Xlong[] data;

				switch((Xsharp.Events.EventType)(xevent.xany.type__))
				{
					case Xsharp.Events.EventType.ClientMessage:
						{
						// Handle messages from the window manager.
						if(xevent.xclient.message_type == dpy.wmProtocols)
						{
							if(xevent.xclient.l(0) == (int)(dpy.wmDeleteWindow))
							{
								// User wants the window to close.
								Close();
							}
							else if(xevent.xclient.l(0) == (int)(dpy.wmTakeFocus))
							{
								// We were given the primary input focus.
								PrimaryFocusIn();
							}
							else if(xevent.xclient.l(0) == (int)(dpy.wmContextHelp))
							{
								// The user pressed the "help" button.
								OnHelp();
							}
							else if(xevent.xclient.l(0) == (int)(dpy.wmPing))
							{
								// The window manager has pinged us to see
								// if we are still responding or are dead.
								// We send the message straight back to the WM.
								try
								{
									IntPtr display = dpy.Lock();
									xevent.xany.window = screen.RootWindow.GetWidgetHandle();
									Xlib.XSendEvent
										(display, xevent.xany.window,
										 XBool.False,
										 (int)(EventMask.NoEventMask),
										 ref xevent);
								}
								finally
								{
									dpy.Unlock();
								}
							}
						}
					}
					break;

				case Xsharp.Events.EventType.PropertyNotify:
					{
						// Handle a property change notification.
						if(xevent.xproperty.atom == dpy.wmState)
						{
							// The "WM_STATE" property has changed.
							if(xevent.xproperty.state == 0)
							{
								// New value for the window state.
								data = GetWindowProperty(dpy.wmState);
								if(data.Length >= 1 && data[0] == (Xlib.Xlong)3)
								{
									// The window is now in the iconic state.
									if(!iconic)
									{
										iconic = true;
										OnIconicStateChanged(true);
									}
								}
								else
								{
									// The window is now in the normal state.
									if(iconic)
									{
										iconic = false;
										OnIconicStateChanged(false);
									}
								}
							}
							else
							{
								// Property removed, so it is "normal" now.
								if(iconic)
								{
									iconic = false;
									OnIconicStateChanged(false);
								}
							}
						}
						else if(xevent.xproperty.atom == dpy.wmNetState)
						{
							// The "_NET_WM_STATE" property has changed.
							if(xevent.xproperty.state == 0)
							{
								// New value: look for maximized state atoms.
								data = GetWindowProperty(dpy.wmNetState);
								if(ContainsMaximizedAtom(data))
								{
									// The window is now maximized.
									if(!maximized)
									{
										maximized = true;
										OnMaximizedStateChanged(true);
									}
								}
								else
								{
									// The window has been restored.
									if(maximized)
									{
										maximized = false;
										OnMaximizedStateChanged(false);
									}
								}
							}
							else
							{
								// Value removed, so not maximized any more.
								if(maximized)
								{
									maximized = false;
									OnMaximizedStateChanged(false);
								}
							}
						}
						else if(xevent.xclient.message_type == dpy.internalBeginInvoke)
						{
							OnBeginInvokeMessage((IntPtr)xevent.xclient.l(0));
						}
					}
					break;

				case Xsharp.Events.EventType.FocusIn:
					{
						// This window has received the focus.
						PrimaryFocusIn();
					}
					break;

				case Xsharp.Events.EventType.FocusOut:
					{
						// This window has lost the focus.
						if(hasPrimaryFocus)
						{
							hasPrimaryFocus = false;
							if(focusWidget != null)
							{
								focusWidget.DispatchFocusOut(null);
							}
							OnPrimaryFocusOut();
						}
					}
					break;

				case Xsharp.Events.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;
						}

						// Special case: check for Alt+F4 to close the window.
						// Some window managers trap Alt+F4 themselves, but not
						// all.  People who are used to System.Windows.Forms
						// under Windows expect Alt+F4 to close the window,
						// irrespective of what key the window manager uses.
						//
						// Note: this check is not foolproof.  The window
						// manager or the kernel may have redirected Alt+F4
						// for some other purpose (e.g. switching between
						// virtual consoles).  On such systems, there is
						// nothing that we can do to get the key event and
						// this code will never be called.
						//
						if((((KeyName)keysym) == KeyName.XK_F4 ||
						    ((KeyName)keysym) == KeyName.XK_KP_F4) &&
						   (xevent.xkey.state & ModifierMask.Mod1Mask) != 0)
						{
							Close();
							break;
						}

						// If we have an MDI client, then give it a chance
						// to process the keypress just in case it is
						// something like Ctrl+F4 or Ctrl+Tab.
						if(mdiClient != null)
						{
							if(mdiClient.DispatchKeyEvent
								((KeyName)keysym, xevent.xkey.state, str))
							{
								break;
							}
						}

						// Dispatch the event.
						widget = focusWidget;
						while(widget != null)
						{
							io = (widget as InputOnlyWidget);
							if(io != null)
							{
								if(io.DispatchKeyEvent
									((KeyName)keysym, xevent.xkey.state, str))
								{
									break;
								}
							}
							if(widget == this)
							{
								break;
							}
							widget = widget.Parent;
						}
					}
					break;

				case Xsharp.Events.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.
						widget = focusWidget;
						while(widget != null)
						{
							io = (widget as InputOnlyWidget);
							if(io != null)
							{
								if(io.DispatchKeyReleaseEvent
									((KeyName)keysym, xevent.xkey.state))
								{
									break;
								}
							}
							if(widget == this)
							{
								break;
							}
							widget = widget.Parent;
						}
					}
					break;

				case Xsharp.Events.EventType.ButtonPress:
					{
						if ((xevent.xbutton.button == ButtonName.Button4) ||
						    (xevent.xbutton.button == ButtonName.Button5))
							return;
					}
					break;

				case Xsharp.Events.EventType.ButtonRelease:
					{
						// Handle mouse wheel events.

						// Sanity check
						if ((xevent.xbutton.button != ButtonName.Button4) &&
						    (xevent.xbutton.button != ButtonName.Button5))
							break;

						// Dispatch the event.
						widget = focusWidget;
						while(widget != null)
						{
							io = (widget as InputOnlyWidget);
							if (io != null)
							{
								if (io.DispatchWheelEvent (ref xevent))
								{
									return;
								}
							}
							if (widget == this)
							{
								break;
							}
							widget = widget.Parent;
						}
					}
					break;

				case Xsharp.Events.EventType.ConfigureNotify:
					{
						// The window manager may have caused us to move/resize.
						if(xevent.xconfigure.window != xevent.window)
						{
							// SubstructureNotify - not interesting to us.
							break;
						}
						if(Parent is CaptionWidget)
						{
							// Ignore configure events if we are an MDI child.
							break;
						}
						if(xevent.xconfigure.width != width ||
						   xevent.xconfigure.height != height ||
						   expectedWidth != -1)
						{
							// The size has been changed by the window manager.
							if(expectedWidth == -1)
							{
								// Resize from the window manager, not us.
								width = xevent.xconfigure.width;
								height = xevent.xconfigure.height;
							}
							else if(expectedWidth == xevent.xconfigure.width &&
									expectedHeight == xevent.xconfigure.height)
							{
								// This is the size that we were expecting.
								// Further ConfigureNotify's will be from
								// the window manager instead of from us.
								expectedWidth = -1;
								expectedHeight = -1;
							}
							if(resizeTimer == null)
							{
								resizeTimer = new Timer
									(new TimerCallback(PerformResize), null,
									 0, -1);
							}
						}
						if(xevent.send_event || !reparented)
						{
							// The window manager moved us to a new position.
							if(x != xevent.xconfigure.x ||
							   y != xevent.xconfigure.y)
							{
								x = xevent.xconfigure.x;
								y = xevent.xconfigure.y;
								OnMoveResize(x, y, width, height);
							}
						}
					}
					break;

				case Xsharp.Events.EventType.ReparentNotify:
					{
						// We may have been reparented by the window manager.
						if(xevent.xreparent.window != (XWindow)handle)
						{
							// SubstructureNotify - not interesting to us.
							break;
						}
						if(xevent.xreparent.parent !=
								(XWindow)(screen.RootWindow.handle))
						{
							// Reparented by the window manager.
							reparented = true;
						}
						else
						{
							// Window manager crashed: we are back on the root.
							reparented = false;
							x = xevent.xreparent.x;
							y = xevent.xreparent.y;
							OnMoveResize(x, y, width, height);
						}
					}
					break;

				case Xsharp.Events.EventType.MapNotify:
					{
						// The window manager mapped us to the screen.
						if(Parent is CaptionWidget)
						{
							break;
						}
						if(iconic)
						{
							iconic = false;
							OnIconicStateChanged(false);
						}
						if(!mapped)
						{
							mapped = true;
							OnMapStateChanged();
						}
					}
					break;

				case Xsharp.Events.EventType.UnmapNotify:
					{
						// We were unmapped from the screen.  If "mapped"
						// is true, then we are being iconified by the window
						// manager.  Otherwise, we asked to be withdrawn.
						if(Parent is CaptionWidget)
						{
							break;
						}
						if(!iconic && mapped)
						{
							iconic = true;
							OnIconicStateChanged(true);
						}
					}
					break;
				}
				base.DispatchEvent(ref xevent);
			}
	// Internal constructor, that can create a top-level window on either
	// the root window or underneath an MDI client parent.
	public TopLevelWindow(Widget parent, String name,
						  int x, int y, int width, int height)
			: base(parent, x, y, width, height,
			       new Color(StandardColor.Foreground),
			       new Color(StandardColor.Background),
				   true, false)
			{
				// Check the parent.
				if(!(parent is RootWindow) && !(parent is CaptionWidget))
				{
					throw new XInvalidOperationException();
				}

				// Initialize this object's state.
				this.name = ((name != null) ? name : String.Empty);
				this.iconic = false;
				this.maximized = false;
				this.hasPrimaryFocus = false;
				this.reparented = false;
				this.sticky = false;
				this.shaded = false;
				this.hidden = false;
				this.fullScreen = false;
				this.keyBuffer = IntPtr.Zero;
				this.focusWidget = this;
				this.defaultFocus = null;
				this.decorations = MotifDecorations.All;
				this.functions = MotifFunctions.All;
				this.inputType = MotifInputType.Normal;
				this.transientFor = null;
				this.resizeTimer = null;
				this.expectedWidth = -1;
				this.expectedHeight = -1;

				// Top-level widgets receive all key and focus events.
				SelectInput(EventMask.KeyPressMask |
							EventMask.KeyReleaseMask |
							EventMask.FocusChangeMask |
							EventMask.StructureNotifyMask |
							EventMask.PropertyChangeMask);

				// We don't use WM properties if the parent is a CaptionWidget.
				if(parent is CaptionWidget)
				{
					return;
				}

				// Set the initial WM properties.
				try
				{
					// Lock down the display and get the window handle.
					IntPtr display = dpy.Lock();
					XWindow handle = GetWidgetHandle();

					// Make this the group leader if we don't have one yet.
					bool isFirst = false;
					if(dpy.groupLeader == XWindow.Zero)
					{
						dpy.groupLeader = handle;
						isFirst = true;
					}

					// Set the WM_CLASS hint.
					Application app = Application.Primary;
					if(app != null)
					{
						XClassHint classHint = new XClassHint();
						classHint.res_name = app.ResourceName;
						classHint.res_class = app.ResourceClass;
						Xlib.XSetClassHint(display, handle, ref classHint);
						classHint.Free();
					}

					// Set the title bar and icon names.
					SetWindowName(display, handle, this.name);

					// Ask for "WM_DELETE_WINDOW" and "WM_TAKE_FOCUS".
					SetProtocols(display, handle);

					// Set the window hints.
					if(isFirst && app != null && app.StartIconic)
					{
						// The user supplied "-iconic" on the command-line.
						iconic = true;
					}
					SetWMHints(display, handle);

					// Set some other string properties.
					String cultureName = CultureInfo.CurrentCulture.Name;
					if(cultureName == null || (cultureName.Length == 0))
					{
						cultureName = "en_US";
					}
					else
					{
						cultureName = cultureName.Replace("-", "_");
					}
					SetTextProperty(display, handle, "WM_LOCALE_NAME",
									cultureName);
					String hostname = Application.Hostname;
					if(hostname != null)
					{
						SetTextProperty(display, handle,
										"WM_CLIENT_MACHINE", hostname);
					}
					if(isFirst)
					{
						String[] args = Environment.GetCommandLineArgs();
						if(args != null && args.Length > 0)
						{
							// We put "ilrun" at the start of the command,
							// because the command needs to be in a form
							// that can be directly executed by fork/exec,
							// and IL binaries normally aren't in this form.
							String[] newArgs = new String [args.Length + 1];
							newArgs[0] = "ilrun";
							Array.Copy(args, 0, newArgs, 1, args.Length);
							SetTextProperty(display, handle,
											"WM_COMMAND", newArgs);
						}
					}

				#if CONFIG_EXTENDED_DIAGNOSTICS
					// Put the process ID on the window.
					int pid = Process.GetCurrentProcess().Id;
					if(pid != -1 && pid != 0)
					{
						Xlib.XChangeProperty
							(display, handle,
							 Xlib.XInternAtom(display, "_NET_WM_PID",
							 				  XBool.False),
							 Xlib.XInternAtom(display, "CARDINAL",
							 				  XBool.False),
							 32, 0 /* PropModeReplace */,
							 new Xlib.Xlong [] {(Xlib.Xlong)(pid)}, 1);
					}
				#endif
				}
				finally
				{
					dpy.Unlock();
				}
			}
Example #5
0
	// fix all timers in the queue if the system time has been changed
	internal static void FixTimers( Timer timer ) {
		DateTime fixTime = DateTime.UtcNow;
		long tpms = TimeSpan.TicksPerMillisecond;
		while( null != timer ) {
			timer.nextDue = fixTime + new TimeSpan(timer.period * tpms);
			timer = timer.next;
		}
	}
Example #6
0
	// Activate timers that have fired on a particular display.
	// We assume that this is called with the display lock.
	internal static bool ActivateTimers(Display dpy)
			{
				// Bail out early if there are no timers, to avoid
				// calling "DateTime.UtcNow" if we don't need to.
				if(dpy.timerQueue == null)
				{
					return false;
				}

				DateTime now = DateTime.UtcNow;
				Timer timer;
				DateTime next;
				bool activated = false;
				for(;;)
				{
					// Remove the first timer from the queue if
					// it has expired.  Bail out if it hasn't.
					timer = dpy.timerQueue;
					if(timer == null)
					{
						break;
					}
					else if(timer.nextDue <= now)
					{
						timer.RemoveTimer();
					}
					else
					{
						break;
					}

					// Invoke the timer's callback delegate.
					activated = true;
					if(timer.callback is TimerCallback)
					{
						TimerCallback cb1 = timer.callback as TimerCallback;
						dpy.Unlock();
						try
						{
							cb1(timer.state);
						}
						finally
						{
							dpy.Lock();
						}
					}
					else
					{
						EventHandler cb2 = timer.callback as EventHandler;
						dpy.Unlock();
						try
						{
							cb2(timer.state, EventArgs.Empty);
						}
						finally
						{
							dpy.Lock();
						}
					}

					// Add the timer back onto the queue if necessary.
					if(!timer.stopped && !timer.onDisplayQueue)
					{
						if(timer.period < 0)
						{
							timer.stopped = true;
						}
						else
						{
							next = timer.nextDue +
								new TimeSpan(timer.period *
											 TimeSpan.TicksPerMillisecond);
											 
							// if the next due is less than now, the date/time may have changed.
							// since the timer expired right now the next due might be now + period
							if(next <= now)
							{
								next += new TimeSpan
									(((((Int64)(now - next).TotalMilliseconds) / timer.period) + 1) *
										timer.period * 
										TimeSpan.TicksPerMillisecond);
							}
							
							/* 
							do not increment here, since the time might have changed with years
							this would do a long loop here 
							
							while(next <= now)
							{
								next += new TimeSpan
										(timer.period *
										 TimeSpan.TicksPerMillisecond);
							}
							*/
							timer.nextDue = next;
							timer.AddTimer();
						}
					}
				}
				return activated;
			}
Example #7
0
	// Remove the timer from the display's timer queue.
	private void RemoveTimer()
			{
				lock(dpy)
				{
					if(onDisplayQueue)
					{
						if(next != null)
						{
							next.prev = prev;
						}
						if(prev != null)
						{
							prev.next = next;
						}
						else
						{
							dpy.timerQueue = next;
						}
						onDisplayQueue = false;
						next = null;
						prev = null;
					}
				}
			}
Example #8
0
	// Add the timer to the display's timer queue.
	private void AddTimer()
			{
				lock(dpy)
				{
					if(!onDisplayQueue)
					{
						Timer current = dpy.timerQueue;
						Timer prev = null;
						int iCount = 0;
						while(current != null && current.nextDue <= nextDue)
						{
							prev = current;
							current = current.next;
						}
						this.next = current;
						this.prev = prev;
						if(current != null)
						{
							current.prev = this;
						}
						if(prev != null)
						{
							prev.next = this;
						}
						else
						{
							dpy.timerQueue = this;
						}
						onDisplayQueue = true;
					}
				}
			}