예제 #1
0
		public static extern int poll( pollfd[] fds, int fdsCount, int timeout);
예제 #2
0
        private void runLinux(Control control)
        {
            this.mainControl = control;

            if ( userCanvasSize.IsEmpty ) {
                // Create physical canvas with actual terminal size
                winsize ws = Libc.GetTerminalSize( isDarwin );
                canvas = new PhysicalCanvas( ws.ws_col, ws.ws_row );
            } else {
                canvas = new PhysicalCanvas( userCanvasSize.Width, userCanvasSize.Height );
            }
            renderer.Canvas = canvas;
            renderer.RootElementRect = userRootElementRect.IsEmpty
                ? new Rect( canvas.Size ) : userRootElementRect;
            renderer.RootElement = mainControl;
            //
            mainControl.Invalidate ();

            // Terminal initialization sequence

            // This is magic workaround to avoid messing up terminal after program finish
            // The bug is described at https://bugzilla.xamarin.com/show_bug.cgi?id=15118
            bool ignored = Console.KeyAvailable;

            IntPtr stdscr = NCurses.initscr ();
            NCurses.cbreak ();
            NCurses.noecho ();
            NCurses.nonl ();
            NCurses.intrflush (stdscr, false);
            NCurses.keypad (stdscr, true);
            NCurses.start_color ();

            HideCursor ();
            try {
                renderer.UpdateLayout( );
                renderer.FinallyApplyChangesToCanvas(  );

                termkeyHandle = LibTermKey.termkey_new( 0, TermKeyFlag.TERMKEY_FLAG_SPACESYMBOL );

                // Setup the input mode
                Console.Write( "\x1B[?1002h" );
                pollfd fd = new pollfd( );
                fd.fd = 0;
                fd.events = POLL_EVENTS.POLLIN;

                pollfd[ ] fds = new pollfd[ 2 ];
                fds[ 0 ] = fd;
                fds[ 1 ] = new pollfd( );
                int pipeResult = Libc.pipe( pipeFds );
                if ( pipeResult == -1 ) {
                    throw new InvalidOperationException( "Cannot create self-pipe." );
                }
                fds[ 1 ].fd = pipeFds[ 0 ];
                fds[ 1 ].events = POLL_EVENTS.POLLIN;

                try {
            #if !WIN32
                    // Catch SIGWINCH to handle terminal resizing
                    UnixSignal[] signals = new UnixSignal [] {
                        new UnixSignal (Signum.SIGWINCH)
                    };
                    Thread signal_thread = new Thread (delegate () {
                        while (true) {
                            // Wait for a signal to be delivered
                            int index = UnixSignal.WaitAny (signals, -1);
                            Signum signal = signals [index].Signum;
                            Libc.writeInt64 (pipeFds[1], 2);
                        }
                    }
                    );
                    signal_thread.IsBackground = false;
                    signal_thread.Start ();
            #endif
                    TermKeyKey key = new TermKeyKey( );
                    //
                    this.running = true;
                    this.mainThreadId = Thread.CurrentThread.ManagedThreadId;
                    //
                    int nextwait = -1;
                    while ( true ) {
                        int pollRes = Libc.poll( fds, 2, nextwait );
                        if ( pollRes == 0 ) {
                            if (nextwait == -1)
                                throw new InvalidOperationException( "Assertion failed." );
                            if (TermKeyResult.TERMKEY_RES_KEY == LibTermKey.termkey_getkey_force(termkeyHandle, ref key) ) {
                                processLinuxInput( key );
                            }
                        }
                        if ( pollRes == -1 ) {
                            int errorCode = Marshal.GetLastWin32Error();
                            if ( errorCode != Libc.EINTR ) {
                                throw new InvalidOperationException(string.Format("poll() returned with error code {0}", errorCode));
                            }
                        }

                        if ( fds[ 1 ].revents != POLL_EVENTS.NONE ) {
                            UInt64 u;
                            Libc.readInt64( fds[ 1 ].fd, out u );
                            if ( u == 1 ) {
                                // Exit from application
            #if !WIN32
                                signal_thread.Abort ();
            #endif
                                break;
                            }
                            if ( u == 2 ) {
                                // Get new term size and process appropriate INPUT_RECORD event
                                INPUT_RECORD inputRecord = new INPUT_RECORD( );
                                inputRecord.EventType = EventType.WINDOW_BUFFER_SIZE_EVENT;

                                winsize ws = Libc.GetTerminalSize( isDarwin );

                                inputRecord.WindowBufferSizeEvent.dwSize.X = ( short ) ws.ws_col;
                                inputRecord.WindowBufferSizeEvent.dwSize.Y = ( short ) ws.ws_row;
                                processInputEvent( inputRecord );
                            }
                            if (u == 3 ) {
                                // It is signal from async actions invocation stuff
                            }
                        }

                        if ( ( fds[ 0 ].revents & POLL_EVENTS.POLLIN ) == POLL_EVENTS.POLLIN ||
                             ( fds[ 0 ].revents & POLL_EVENTS.POLLHUP ) == POLL_EVENTS.POLLHUP ||
                             ( fds[ 0 ].revents & POLL_EVENTS.POLLERR ) == POLL_EVENTS.POLLERR ) {
                            LibTermKey.termkey_advisereadable( termkeyHandle );
                        }

                        TermKeyResult result = ( LibTermKey.termkey_getkey( termkeyHandle, ref key ) );
                        while (result == TermKeyResult.TERMKEY_RES_KEY ) {
                            processLinuxInput( key );
                            result = ( LibTermKey.termkey_getkey( termkeyHandle, ref key ) );
                        }

                        if (result == TermKeyResult.TERMKEY_RES_AGAIN) {
                            nextwait = LibTermKey.termkey_get_waittime(termkeyHandle);
                        } else {
                            nextwait = -1;
                        }

                        while ( true ) {
                            bool anyInvokeActions = isAnyInvokeActions( );
                            bool anyRoutedEvent = !EventManager.IsQueueEmpty( );
                            bool anyLayoutToRevalidate = renderer.AnyControlInvalidated;

                            if (!anyInvokeActions && !anyRoutedEvent && !anyLayoutToRevalidate)
                                break;

                            EventManager.ProcessEvents();
                            processInvokeActions(  );
                            renderer.UpdateLayout(  );
                        }

                        renderer.FinallyApplyChangesToCanvas( );
                    }

                } finally {
                    LibTermKey.termkey_destroy( termkeyHandle );
                    Libc.close( pipeFds[ 0 ] );
                    Libc.close( pipeFds[ 1 ] );
                    Console.Write( "\x1B[?1002l" );
                }
            } finally {
                // Restore cursor visibility before exit
                ShowCursor( );
                NCurses.endwin( );
            }

            renderer.RootElement = null;
        }