Beispiel #1
0
		void UpdateMessageQueue (XEventQueue queue, bool allowIdle) {
			DateTime	now;
			int		pending;
			Hwnd		hwnd;

			now = DateTime.UtcNow;

			lock (XlibLock) {
				pending = XPending (DisplayHandle);
			}

			if (pending == 0 && allowIdle) {
				if ((queue == null || queue.DispatchIdle) && Idle != null) {
					Idle (this, EventArgs.Empty);
				}

				lock (XlibLock) {
					pending = XPending (DisplayHandle);
				}
			}

			if (pending == 0) {
				int	timeout = 0;

				if (queue != null) {
					if (queue.Paint.Count > 0)
						return;

					timeout = NextTimeout (queue.timer_list, now);
				}

				if (timeout > 0) {
					#if __MonoCS__
					int length = pollfds.Length - 1;
					lock (wake_waiting_lock) {
						if (wake_waiting == false) {
							length ++;
							wake_waiting = true;
						}
					}

					Syscall.poll (pollfds, (uint)length, timeout);
					// Clean out buffer, so we're not busy-looping on the same data
					if (length == pollfds.Length) {
						if (pollfds[1].revents != 0)
							wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None);
						lock (wake_waiting_lock) {
							wake_waiting = false;
						}
					}
					#endif
					lock (XlibLock) {
						pending = XPending (DisplayHandle);
					}
				}
			}

			if (queue != null)
				CheckTimers (queue.timer_list, now);

			while (true) {
				XEvent xevent = new XEvent ();

				lock (XlibLock) {
					if (XPending (DisplayHandle) == 0)
						break;

					XNextEvent (DisplayHandle, ref xevent);

					if (xevent.AnyEvent.type == XEventName.KeyPress ||
					    xevent.AnyEvent.type == XEventName.KeyRelease) {
						// PreFilter() handles "shift key state updates.
						Keyboard.PreFilter (xevent);
						if (XFilterEvent (ref xevent, Keyboard.ClientWindow)) {
							// probably here we could raise WM_IME_KEYDOWN and
							// WM_IME_KEYUP, but I'm not sure it is worthy.
							continue;
						}
					}
					else if (XFilterEvent (ref xevent, IntPtr.Zero))
						continue;
				}

				hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
				if (hwnd == null)
					continue;

				DebugHelper.WriteLine  ("UpdateMessageQueue got Event: " + xevent.ToString ());

				switch (xevent.type) {
				case XEventName.Expose:
					AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
					break;

				case XEventName.SelectionClear: {
					// Should we do something?
					break;
				}

				case XEventName.SelectionRequest: {
					if (Dnd.HandleSelectionRequestEvent (ref xevent))
						break;
					XEvent sel_event;

					sel_event = new XEvent();
					sel_event.SelectionEvent.type = XEventName.SelectionNotify;
					sel_event.SelectionEvent.send_event = true;
					sel_event.SelectionEvent.display = DisplayHandle;
					sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection;
					sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target;
					sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor;
					sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time;
					sel_event.SelectionEvent.property = IntPtr.Zero;

					IntPtr format_atom = xevent.SelectionRequestEvent.target;

					// Seems that some apps support asking for supported types
					if (format_atom == TARGETS) {
						int[]	atoms;
						int	atom_count;

						atoms = new int[5];
						atom_count = 0;

						if (Clipboard.IsSourceText) {
							atoms[atom_count++] = (int)Atom.XA_STRING;
							atoms[atom_count++] = (int)OEMTEXT;
							atoms[atom_count++] = (int)UTF8_STRING;
							atoms[atom_count++] = (int)UTF16_STRING;
							atoms[atom_count++] = (int)RICHTEXTFORMAT;
						} else if (Clipboard.IsSourceImage) {
							atoms[atom_count++] = (int)Atom.XA_PIXMAP;
							atoms[atom_count++] = (int)Atom.XA_BITMAP;
						} else {
							// FIXME - handle other types
						}

						XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, 
								(IntPtr)xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count);
						sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
					} else if (format_atom == (IntPtr)RICHTEXTFORMAT) {
						string rtf_text = Clipboard.GetRtfText ();
						if (rtf_text != null) {
							// The RTF spec mentions that ascii is enough to contain it
							Byte [] bytes = Encoding.ASCII.GetBytes (rtf_text);
							int buflen = bytes.Length;
							IntPtr buffer = Marshal.AllocHGlobal (buflen);

							for (int i = 0; i < buflen; i++)
								Marshal.WriteByte (buffer, i, bytes[i]);

							XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property,
									(IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen);
							sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
							Marshal.FreeHGlobal(buffer);
						}
					} else if (Clipboard.IsSourceText && 
					           (format_atom == (IntPtr)Atom.XA_STRING 
					            || format_atom == OEMTEXT
					            || format_atom == UTF16_STRING
					            || format_atom == UTF8_STRING)) {
						IntPtr	buffer = IntPtr.Zero;
						int	buflen;
						Encoding encoding = null;

						buflen = 0;

						// Select an encoding depending on the target
						IntPtr target_atom = xevent.SelectionRequestEvent.target;
						if (target_atom == (IntPtr)Atom.XA_STRING || target_atom == OEMTEXT)
							// FIXME - EOMTEXT should encode into ISO2022
							encoding = Encoding.ASCII;
						else if (target_atom == UTF16_STRING)
							encoding = Encoding.Unicode;
						else if (target_atom == UTF8_STRING)
							encoding = Encoding.UTF8;

						Byte [] bytes;

						bytes = encoding.GetBytes (Clipboard.GetPlainText ());
						buffer = Marshal.AllocHGlobal (bytes.Length);
						buflen = bytes.Length;

						for (int i = 0; i < buflen; i++)
							Marshal.WriteByte (buffer, i, bytes [i]);

						if (buffer != IntPtr.Zero) {
							XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen);
							sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
							Marshal.FreeHGlobal(buffer);
						}
					} else if (Clipboard.GetSource (format_atom.ToInt32 ()) != null) { // check if we have an available value of this format
						if (DataFormats.GetFormat (format_atom.ToInt32 ()).is_serializable) {
							object serializable = Clipboard.GetSource (format_atom.ToInt32 ());

							BinaryFormatter formatter = new BinaryFormatter ();
							MemoryStream memory_stream = new MemoryStream ();
							formatter.Serialize (memory_stream, serializable);

							int buflen = (int)memory_stream.Length;
							IntPtr buffer = Marshal.AllocHGlobal (buflen);
							memory_stream.Position = 0;
							for (int i = 0; i < buflen; i++)
								Marshal.WriteByte (buffer, i, (byte)memory_stream.ReadByte ());
							memory_stream.Close ();

							XChangeProperty (DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target,
									8, PropertyMode.Replace, buffer, buflen);
							sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
							Marshal.FreeHGlobal (buffer);
						}

					} else if (Clipboard.IsSourceImage) {
						if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
							// FIXME - convert image and store as property
						} else if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
							// FIXME - convert image and store as property
						}
					}

					XSendEvent(DisplayHandle, xevent.SelectionRequestEvent.requestor, false, new IntPtr ((int)EventMask.NoEventMask), ref sel_event);
					break;
				}

				case XEventName.SelectionNotify: {
					if (Clipboard.Enumerating) {
						Clipboard.Enumerating = false;
						if (xevent.SelectionEvent.property != IntPtr.Zero) {
							XDeleteProperty(DisplayHandle, FosterParent, (IntPtr)xevent.SelectionEvent.property);
							if (!Clipboard.Formats.Contains(xevent.SelectionEvent.property)) {
								Clipboard.Formats.Add(xevent.SelectionEvent.property);
								DriverDebug("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property);
							}
						}
					} else if (Clipboard.Retrieving) {
						Clipboard.Retrieving = false;
						if (xevent.SelectionEvent.property != IntPtr.Zero) {
							TranslatePropertyToClipboard(xevent.SelectionEvent.property);
						} else {
							Clipboard.ClearSources ();
							Clipboard.Item = null;
						}
					} else {
						Dnd.HandleSelectionNotifyEvent (ref xevent);
					}
					break;
				}

				case XEventName.KeyRelease:
					if (!detectable_key_auto_repeat && XPending (DisplayHandle) != 0) {
						XEvent nextevent = new XEvent ();

						XPeekEvent (DisplayHandle, ref nextevent);

						if (nextevent.type == XEventName.KeyPress &&
						    nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode &&
						    nextevent.KeyEvent.time == xevent.KeyEvent.time) {
							continue;
						}
					}
					goto case XEventName.KeyPress;
					
				case XEventName.MotionNotify: {
					XEvent peek;

					/* we can't do motion compression across threads, so just punt if we don't match up */
					if (Thread.CurrentThread == hwnd.Queue.Thread && hwnd.Queue.Count > 0) {
						peek = hwnd.Queue.Peek();
						if (peek.AnyEvent.type == XEventName.MotionNotify) {
							continue;
						}
					}
					goto case XEventName.KeyPress;
				}

				case XEventName.KeyPress:
					hwnd.Queue.EnqueueLocked (xevent);
					/* Process KeyPresses immediately. Otherwise multiple Compose messages as a result of a
					 * single physical keypress are not processed correctly */
					return;
				case XEventName.ButtonPress:
				case XEventName.ButtonRelease:
				case XEventName.EnterNotify:
				case XEventName.LeaveNotify:
				case XEventName.CreateNotify:
				case XEventName.DestroyNotify:
				case XEventName.FocusIn:
				case XEventName.FocusOut:
				case XEventName.ClientMessage:
				case XEventName.ReparentNotify:
				case XEventName.MapNotify:
				case XEventName.UnmapNotify:
					hwnd.Queue.EnqueueLocked (xevent);
					break;

				case XEventName.ConfigureNotify:
					AddConfigureNotify(xevent);
					break;

				case XEventName.PropertyNotify:
					DriverDebug ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ());
					if (xevent.PropertyEvent.atom == _NET_ACTIVE_WINDOW) {
						IntPtr	actual_atom;
						int	actual_format;
						IntPtr	nitems;
						IntPtr	bytes_after;
						IntPtr	prop = IntPtr.Zero;
						IntPtr	prev_active;

						prev_active = ActiveWindow;
						XGetWindowProperty(DisplayHandle, RootWindow, _NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false, (IntPtr)Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
						if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
							ActiveWindow = Hwnd.GetHandleFromWindow((IntPtr)Marshal.ReadInt32(prop));							
							XFree(prop);

							DebugHelper.WriteLine ("PropertyNotify: _NET_ACTIVE_WINDOW: previous = 0x{0:x}, new = 0x{1:x}", prev_active.ToInt32 (), ActiveWindow.ToInt32 ());
							
							if (prev_active != ActiveWindow) {
								if (prev_active != IntPtr.Zero) {
									PostMessage(prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
								}
								if (ActiveWindow != IntPtr.Zero) {
									PostMessage(ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
								}
							}
							if (ModalWindows.Count == 0) {
								break;
							} else {
								// Modality Handling
								// 
								// If there is a modal window on the stack and the new active 
								// window is MWF window, but not the modal one and not a non-modal 
								// child of the modal one, switch back to the modal window.
								//
								// To identify if a non-modal form is child of a modal form 
								// we match their ApplicationContexts, which will be the same.
								// This is because each modal form runs the loop with a 
								// new ApplicationContext, which is inherited by the non-modal 
								// forms.

								Form activeForm = Control.FromHandle (ActiveWindow) as Form;
								if (activeForm != null) {
									Form modalForm = Control.FromHandle ((IntPtr)ModalWindows.Peek()) as Form;
									if (ActiveWindow != (IntPtr)ModalWindows.Peek() && 
									    (modalForm == null || activeForm.context == modalForm.context)) {
										Activate((IntPtr)ModalWindows.Peek());
									}
								}
								break;
							}
						}
					}
					else if (xevent.PropertyEvent.atom == _NET_WM_STATE) {
						// invalidate our cache - we'll query again the next time someone does GetWindowState.
						hwnd.cached_window_state = (FormWindowState)(-1);
						PostMessage (hwnd.Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
					}
					break;

				}
			}
		}
Beispiel #2
0
		XEventQueue ThreadQueue(Thread thread) {
			XEventQueue	queue;

			queue = (XEventQueue)MessageQueues[thread];
			if (queue == null) {
				queue = new XEventQueue(thread);
				MessageQueues[thread] = queue;
			}

			return queue;
		}
Beispiel #3
0
		void UpdateMessageQueue (XEventQueue queue) {
			UpdateMessageQueue(queue, true);
		}
Beispiel #4
0
		private XplatUIX11GTK ()
		{
			Console.WriteLine ("XplatUIX11GTK ctor...");
			// Handle singleton stuff first
			RefCount = 0;
			
			// init gdk
			gdk_init_check (IntPtr.Zero, IntPtr.Zero);
			
			// Now regular initialization
			XlibLock = new object ();
			MessageQueue = new XEventQueue ();
			TimerList = new ArrayList ();
			XInitThreads ();
			
			ErrorExceptions = false;
			
			// X11 Initialization
			SetDisplay (gdk_x11_display_get_xdisplay (gdk_display_get_default ()));
			X11DesktopColors.Initialize ();
			
			// Handle any upcoming errors; we re-set it here, X11DesktopColor stuff might have stolen it (gtk does)
			ErrorHandler = new XErrorHandler (HandleError);
			XSetErrorHandler (ErrorHandler);
		}