Phantom OS: subsistema de ventana - hacer controles

Hoy hablaremos sobre cómo se organiza la interfaz gráfica de usuario fantasma.

(¿Qué es Phantom OS que puede encontrar leyendo estos artículos ?)

Más precisamente: cómo nació esta interfaz gráfica de usuario. Durante mucho tiempo, el Fantasma solo tuvo una conclusión gráfica: era casi imposible transmitir nada al sistema con el mouse.

Ahora ha llegado el momento de simplificar al menos las aplicaciones, lo que significa que necesita una interfaz de usuario. De todos modos, el sistema, seremos honestos, parecía aterrador. Y esto no está de moda ahora.

¿Qué estaba disponible al comienzo del proyecto de interfaz de usuario? En principio, mucho.

De hecho, había gráficos: un controlador de video, un subsistema de ventana en el modo de solo visualización, fuentes de mapa de bits, un subsistema de eventos de ventana (eventos), control de foco de ventana y primitivas relacionadas.

Ahora los pasos y un poco más.

El subsistema de controlador de video puede ejecutar la función de sonda () de varios controladores a su vez, recibir solicitudes de ellos para obtener la máxima resolución y color, además de la capacidad de trabajar en el modo acelerador 2D. El sistema requiere un mínimo de color de 24 bits. En este nivel, tenemos un framebuffer (una pantalla en memoria), un mouse y varios tipos de primitivas bitblt.

Primitivas de Bitblt: se implementaron tres tipos básicos: copia completa de los gráficos (con rectángulos recortados), copia teniendo en cuenta la transparencia binaria (un píxel es completamente transparente o completamente opaco) y z-buffer. Es decir, la capacidad de copiar en la pantalla solo aquellos píxeles que tienen una coordenada z mayor que la coordenada z de un píxel existente, para resolver una superposición parcial de ventanas.

La siguiente capa de funciones es el subsistema de ventana. Aquí está el concepto de ventana, decoración de ventanas (marco, ventana de título con botones), coordenadas x / y / z de ventanas y un conjunto de funciones que son responsables de dibujar ventanas en la pantalla y controlar su movimiento a lo largo de todos los ejes.

La documentación

Siguen los siguientes eventos: la cola de microtask, que es procesada por el controlador de nivel inferior para representar y administrar el estado de las ventanas.

Cabe señalar que las mejores mentes de la humanidad afirman que un sistema de gráficos de ventana que funcionaría de manera estable y sin problemas en un entorno multiproceso no se puede escribir sin una cola de eventos. Mis modestos intentos de ignorar esta declaración hasta ahora solo la han confirmado. Es muy difícil prescindir de la cola de mensajes y hacer que todos los hilos que soliciten eventos de ventana para el programa y, a veces, conduzcan a la guerra en la pantalla.

Por lo tanto, la mayoría de las primitivas del sistema de ventanas relacionadas con algo más grande que la imagen dentro de la ventana se implementan a través de una cola de mensajes. La solicitud envía a la cola el mensaje "dibuje esta área en la pantalla" o "reorganice la ventana encima de las otras", y un hilo separado en la parte inferior las ejecuta ordenada y cuidadosamente.

Simplemente obtiene la secuencia de eventos desde el mouse (presionado, arrastrado), el teclado (presionado, liberado) y el sistema de ventanas en sí (eventos secundarios, después de mover la ventana hacia arriba, volver a dibujar el área de la pantalla).

Una tarea separada a nivel del flujo de eventos es el llamado foco. Una ventana enfocada recibe una secuencia de eventos desde el teclado y, de hecho, se resalta claramente en la pantalla como un punto para abordar la actividad del usuario. Además de la tarea obvia de elegir una ventana para dirigir el evento, este sistema también informa a la ventana sobre la pérdida de enfoque, que a veces es importante.

La documentación

El siguiente nivel son las primitivas gráficas para dibujar en la ventana.

Hay dos opciones principales para la implementación. Viejo, económico: cuando una ventana no almacena una copia de lo que se dibuja en ella. Si se borra dicha ventana, y necesita dibujarla nuevamente (por ejemplo, la ventana se devolvió a la pantalla desde el borde), entonces la ventana llama a la función desde su programa, y ​​esta función debe dibujar todo lo que se necesita. Este es un modelo típico y terriblemente inconveniente por una variedad de razones. La segunda se selecciona en Phantom: cada ventana tiene un mapa de bits en el que se dibuja actualmente el contenido de la ventana. El sistema de gráficos siempre puede hacer referencia a esta copia y actualizarla en la pantalla sin extraer el programa del usuario.

Tenga en cuenta que la ventana que pertenece al programa de usuario (y no al núcleo) en Phantom, por supuesto, es persistente, se almacena en una memoria persistente y después de reiniciar el sistema operativo guarda todo lo dibujado en él. Esto, por cierto, es sorprendentemente útil y simplifica el código de la aplicación en algunos lugares para indecentes.

Un conjunto de primitivas de dibujo permite que el código de la aplicación, como de costumbre, dibuje un punto, una línea, un mapa de bits, una línea de texto en una fuente de mapa de bits y algunas otras pequeñas cosas en la ventana.

En esta riqueza del subsistema de gráficos al comienzo del proyecto "Nueva interfaz de usuario fantasma" y terminó. En principio, el kit de este caballero fue suficiente para mucho, pero solo para el usuario. No hay entrada

Más precisamente, había un soporte rudimentario para el concepto de "botón", pero solo con el mouse, solo en la barra de herramientas y solo para cerrar la ventana. :)

La tarea de desarrollo fue la siguiente:

  • TrueType Sin esto, es una pena.
  • Eventos de teclado y controles de teclado. Al menos básico.
  • Pensar hacia la localización de los diseños, al menos el alfabeto cirílico, pero sentar las bases para cambiar los diseños.
  • Controles: botones, botones de opción, campos de texto, etiquetas, menús, etc.
  • El foco del control es la elección de un punto de control dentro de la ventana.
  • Algún tipo de componente de pantalla para administrar ventanas en la pantalla. Barra de tareas?
  • En realidad, las imágenes de controles y, en general, algún tipo de diseño de interfaz de usuario, no deberían ser tan granjas colectivas como lo fueron.

Fue así:

imagen

En el camino, resultó que también se necesitaba una combinación alfa, es decir, una transparencia parcial de píxeles al superponer imágenes. Bueno, quedó claro que era hora de tocar Unicode para la ubre.

El enfoque de este peso se divide en tres grandes partes: diseño, Trump, el resto.

Sobre el diseño, en resumen: hay diseños de interfaz de usuario gratuitos en Internet sin requisitos de mal uso. Tres días para la búsqueda y selección, tiempo sin fin para el corte artístico de elementos gráficos.

Tipo de Trump


Tenía miedo de esto, pero resultó ser en vano. Hay libfreetype, hay ejemplos de aplicación, después de dos días, la representación de las fuentes vectoriales funcionó bastante bien en modo de prueba.

Sin embargo, hay sutilezas, y no se ha cubierto todo el camino. A saber. Trabajar con fuentes del núcleo - es. Las fuentes son conducidas por el código rígido al núcleo binario. Esto es inevitable para una fuente del sistema, pero el código de usuario debe tener sus propios mecanismos de carga. Y aunque algunos FS en Phantom, por supuesto, son y serán, este modelo no es natural para él. Debe poder almacenar fuentes en objetos persistentes y obtenerlos a través de la red.

El segundo es más simple: las colonias de fuentes gratuitas son abundantes y su organización no será larga.

Pero el primero ...

Probablemente no lo sepas, pero las variables de cadena en Phantom poseen propiedades inesperadas para programadores que no están acostumbrados a la persistencia. Pueden reemplazar archivos. Una secuencia de bytes es una secuencia de bytes. No solo eso, también es, por definición, un mapa de memoria, es una variable. Eso es, en principio, lo que almacenamos en un sistema operativo normal en un archivo, en Phantom, simplemente puede ponerlo en una variable de cadena. Actúo muy a menudo, y el compilador Phantom incluso tiene un diseño, para absorber un archivo en una constante de cadena. Entonces, en el país de los usuarios, los Phantoms penetran, por ejemplo, mapas de bits. Pero este también es un método vergonzoso, porque entonces, en tiempo de ejecución, esta variable debe analizarse para obtener una representación operable del objeto. Sin embargo, en cuanto a los mapas de bits, entonces, en honor del concepto Phantom, todo está bien aquí. Compilamos el archivo gráfico en una cadena cuando lo compilamos, cuando Phantom se inicia por primera vez, se convierte en un objeto binario persistente del tipo bitmep, y ya se usa más tarde después de que se reinicie cualquier número de sistema operativo y no requiere la fuente original. También debe hacerse con fuentes, pero es un poco menos común. Cuando se trabaja, la fuente del vector se representa en un ráster, y sería necesario almacenar solo dichos rásteres renderizados. Esto no es un truco ni un problema: pueden volver a plegarse en objetos Phantom como el mapa de bits, pero ya se necesita algún tipo de infraestructura: un mapa de bits de glifo (código UTF) estilo-estilo-estilo-tamaño-glifo (código UTF).

Esto no es tan difícil, pero, aparentemente, la tarea de la siguiente etapa. Mientras que las fuentes se rasterizan en apelación.

La documentación

Unicode


La representación de fuentes por definición implica trabajar con Unicode. Esto, por supuesto, es bueno, porque uno tenía que comenzar en algún momento. De hecho, fue suficiente para equipar al renderizador con un convertidor de UTF-8 a UTF-32 (y este es el número de glifo en la fuente), descargar fuentes con el alfabeto cirílico y esta parte de la localización funcionó. Además, si queremos otros idiomas, entonces es necesario y suficiente reemplazar la fuente. Sin embargo, la fuente base seleccionada contiene mucho, para Europa, definitivamente suficiente. China necesitará un reemplazo de fuente, sí.

Trabajar con teclado


No había señales de acción militar, pero, más que esperanzas, tuve que luchar. Resultó que el viejo controlador del teclado todavía ... esperaba ver el hardware de IBM PC XT. Si, siglo pasado. El hecho es que el controlador del teclado puede (¡pudo!) Convertir códigos de escaneo de teclados modernos (el llamado segundo conjunto de códigos) en uno antiguo.

Resultó debido a la QEMU tardía, tal conversión, aparentemente, finalmente fue descartada. O accidentalmente se rompió. Pero el hecho es que el conductor se negó a trabajar. Con pena, durante una hora, con la ayuda de una madre, transporté al conductor de un amigable uOS a Phantom. Solo para descubrir que tiene el mismo problema. El primer set. Tuve que reescribir la tabla de códigos de escaneo y el analizador. No volví al viejo conductor, y por eso. Resultó que el controlador de uOS tiene una interfaz más elegante para el sistema. Es decir, no regresa a él, como era habitual, un par (código de caracteres, código de escaneo de botones), sino un carácter UTF-32 de 32 bits. Resulta que en UTF hay un rango especial de códigos asignados para uso local, y son más que suficientes para todas las teclas de función posibles. Trabajar con este flujo de eventos en el código de la interfaz de usuario es mucho más simple.

Además, la localización cayó perfectamente en tal modelo. Es suficiente superponer la tabla ASCII-> UTF32 para el idioma deseado (juego de caracteres), y saludos: tenemos cirílico. Bueno, casi allí. Ahora sería necesario transcodificarlo en UTF-8 o rehacer despojos de algunas partes de la interfaz de usuario a UTF-32. Yo también he puesto este momento como una prioridad baja.

Controles



Botones, radio, casillas de verificación y otros elementos específicos de la interfaz de usuario.

La infraestructura común incluye:

  • El mecanismo para almacenar controles en relación con la ventana.
  • Elementos de visualización de control típicos: marco, fondo, texto, icono, etc.
  • Transmisión al control de eventos y patrones de reacción típicos (pulsar / alternar)
  • Seguimiento de eventos del mouse y estado de desplazamiento
  • Callbacks y la generación de eventos secundarios para informar sobre cambios de estado

Control de enfoque


Para que el control (botón, por ejemplo) se use sin un mouse, se necesitan varias cosas.

  • La capacidad de seleccionarlo desde el teclado
  • Mostrar esta selección
  • Respuesta del teclado
  • Detección de pérdida de enfoque.

Este último es el más difícil.

De hecho, el control se enfoca tanto con el teclado como con el mouse, y esta es una misma entidad: si seleccionamos el campo de texto con el mouse, responderá a las teclas. Si después de eso presiona TAB, el derecho a trabajar con el teclado irá a otro.

Una tarea separada es que algunos controles pueden agruparse y su estado debe actualizarse de manera relacionada. Al presionar un radiobathorn "aprieta" a sus vecinos del grupo.

Una vez más, volvamos al hecho de que estamos escribiendo un sistema operativo persistente. Esto significa que el control potencial puede almacenarse en RAM persistente y sobrevivir al reinicio del núcleo del sistema.

Es decir, su conexión con el núcleo sería bueno para minimizar. Cada puntero a la memoria no persistente (en realidad al núcleo) después de un reinicio no será válido y tendrá que ser restaurado. Esto significa que dicho puntero no tiene derecho a almacenar información sobre el estado del control. La posición del cursor como un entero: sí. Un puntero a un búfer en el núcleo cuya posición está determinada por la posición del cursor no lo es. Bueno o sí, solo queda un número entero y es más importante. Esto en la práctica no es muy gravoso, pero debemos recordarlo.

Finalmente, la barra de tareas. Esto es así en la parte inferior (lateral, superior) de la pantalla donde el usuario asoma si pierde la ventana.

En principio, esto ya debería ser parte de la tierra del usuario, pero ... el núcleo ya está utilizando activamente la GUI, por lo que por ahora esta parte también estará en la parte inferior. Espero temporalmente

Total


imagen

En mi opinión, las tareas que se establecieron en esta dirección generalmente se han resuelto. Por supuesto, no hay límite para la perfección, pero, como me parece, la interfaz ha dado un paso tangible de hacker a universal.

Source: https://habr.com/ru/post/472160/


All Articles