Archivo de la categoría: Trucos

Trucos generales para distribuciones

Pintando en el Spectrum (4)

Ha llegado el momento de empezar a pintar cosas en la pantalla. Obviamente lo que queremos pintar serán Sprites. Como explica la wikipedia, se trata de gráficos 2D que se integran con una escena de fondo. Como sabemos, el Spectrum no tiene soporte de sprites por hardware, lo que significa que nos toca a nosotros hacer todo el trabajo de pintarlos. Afortunadamente, en las entradas anteriores vimos cómo hacer una rutina que copie a la pantalla una imagen completa desde un buffer organizado de manera secuencial, y esto nos va a simplificar la tarea, como veremos.

Lo primero que necesitamos saber para pintar algo en pantalla es a partir de qué dirección de memoria tenemos que hacerlo. Si recordamos, la pantalla del Spectrum está formada por una matriz de 256 píxels de ancho por 192 de alto, y cada píxel puede tener dos colores, por lo que cada uno ocupa un bit. Esto significa que cada fila o scanline de la pantalla ocupa 32 bytes, y la parte de píxeles de la pantalla ocupa en total 6 144 bytes o 6 Kbytes exactos.

Sin embargo, justo a continuación viene una segunda zona denominada atributos, que define una matriz de 32 por 24 atributos y asigna un byte a cada uno. Este byte de atributos especifica qué colores tendrán un grupo de píxeles. En concreto, cada byte define dos colores para cada grupo de 8×8 píxeles de la pantalla: uno será el color que se mostrará cuando el bit correspondiente al píxel esté a cero, y el otro cuando esté a uno. Esta zona empieza en la dirección de memoria 22 528 y ocupa un total de 768 bytes. Este sistema permite al Spectrum mostrar hasta 16 colores simultáneos en pantalla pero consumiendo muy poca memoria.

Como ya vimos en la primera entrada, la organización de la pantalla es algo caótica. Veámoslo en un gráfico:

Vemos que los bytes situados en las direcciones de memoria en hexadecimal 0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600 y 0x4700 se corresponden con el bloque de 8×8 píxeles superior izquierdo de la pantalla, y que los atributos de dicho bloque están almacenados en la dirección 0x5800, que especifica que los dos colores de ese grupo de píxeles son blanco y negro. El siguiente bloque de 8×8 píxeles está en las direcciones 0x4001, 0x4101, 0x4201, 0x4301, 0x4401, 0x4501, 0x4601 y 0x4701, y sus atributos, que indican que los dos colores mostrados serán celeste y rojo, están en la dirección 0x5801. Y así sucesivamente. Esta disposición puede parecer absurda, pero si nos fijamos, vemos que la dirección de memoria de un scanline de píxeles y la de los atributos que le corresponden tienen el mismo valor en los ocho bits inferiores. Gracias a esta característica, es posible leer los dos bytes necesarios para mostrar los ocho píxeles en sólo tres ciclos de reloj, en lugar de los cuatro que se necesitarían si ambas direcciones no tuviesen siempre un byte idéntico (lo que se denomina fast-page). Y si tenemos en cuenta que cada bloque de 8 píxeles tarda cuatro ciclos de reloj en ser pintado, salta a la vista de donde sale el ciclo de contención de memoria que vimos en el primer artículo: la circuitería «compacta» la lectura de dos grupos de 8 píxeles consecutivos, de manera que en lugar de bloquear al procesador durante tres ciclos y liberarlo uno, lo bloquea durante seis ciclos y lo libera durante dos consecutivos. Además, de esta manera se garantiza también que los siete bits bajos se recorren completos aproximadamente cada milisegundo, lo que es más que de sobra para garantizar el refresco de la RAM.

Obviamente este sistema se implementó porque permite abaratar y simplificar el hardware, pero tiene el inconveniente de que, a la hora de programar para él, es bastante engorroso calcular la dirección de memoria que se corresponde con cada coordenada. Así, si dividimos la pantalla en caracteres (bloques de 8×8 píxeles) y queremos encontrar las ocho direcciones de memoria de sus ocho bytes, la operación que hay que hacer es la siguiente (gráficamente):

En azul tenemos la coordenada X, que puede valer entre 0 y 31 para las 32 columnas del Spectrum. En verde y magenta tenemos la coordenada Y en líneas: en la parte verde estaría la coordenada Y en caracteres (de 0 a 23), y en magenta sería el scanline dentro de ese carácter, todo de arriba a abajo y de izquierda a derecha. A mayores es necesario poner los tres bits superiores a 010 para que apunte al bloque de memoria concreto. Como vemos, la cosa es bastante complicada y requiere rotaciones y máscaras. Sin embargo, gracias a las rutinas que vimos en las entradas anteriores esta complicación desaparece completamente. Si las utilizamos, la conversión es tan sencilla como:

Ponemos los tres bits superiores a 100 porque, para simplificar, colocamos el buffer en la dirección 0x8000 (32768). De esta manera, si ponemos la coordenada X en el byte inferior y la coordenada Y en la superior, sólo tendremos que poner a uno el bit 7 del byte inferior y ya tendremos la dirección de memoria del scanline superior del carácter con dichas coordenadas; para pasar al siguiente carácter sólo tenemos que sumar uno; para pasar al anterior, restar uno; para pasar al que está encima, restar 32, y para pasar al que está debajo, sumar 32. Tan simple como esto. ¿Y si tenemos una dirección de píxeles, cómo calculamos la de sus atributos? Pues sólo tenemos que hacer esto:

Sencillo ¿no? Aunque para los que no se quieran complicar, aquí está un trozo de código que lo hace:

; Asumimos que HL contiene la dirección de memoria
; de un byte de pantalla
    ld a, l
    and 0x1F
    ld l, a
    ld a, h
    rrca
    rrca
    rrca
    ld h, a
    and 0xE0
    or l
    ld l, a
    ld a, h
    and 3
    or 0x98
    ld h, a
; Ahora HL contiene la dirección de memoria del atributo
; que corresponde con el byte de pantalla inicial

Y como esta entrada quedó ya algo larga, seguiré en la siguiente.

A ritmo de conga (12)

Hasta ahora he estado utilizando la web app para controlar mi aspiradora robot tanto desde el ordenador como desde el móvil. El problema es que es bastante pesado, en el móvil, tener que:

  • Abrir el navegador
  • Abrir una pestaña en blanco
  • Escribir la IP del servidor número a número

Así que decidí que tenía que hacer una app para Android. Obviamente no me iba a matar repitiendo todo el trabajo que ya había hecho en JavaScript, así que la solución obvia era hacer una aplicación que simplemente tuviese un WebView (que no es más que un widget con un navegador web completo) y que cargase automáticamente la web app de OpenDoñita automáticamente cada vez que se abriese. Así cualquier cambio que hiciese a la web app aparecería automáticamente también en la app de Android.

Sin embargo, antes que eso tenía que resolver un problema nada trivial: ¿cómo saber la IP del servidor de OpenDoñita? Sí, en mi casa se cual es, pero obviamente si quiero que otras personas puedan usarlo, no es plan de tener que poner la IP «a mano». Además ¿y si el DHCP hace de las suyas en un reinicio y cambia la IP?

La solución vino de la mano de uPnP. Se trata de un estándar para que dispositivos multimedia puedan anunciarse en una red doméstica, y que otros dispositivos puedan identificarlos y comunicarse con ellos de manera estandarizada. También sirve (y será lo que les suene a muchos) para poder abrir puertos externos en el router cuando usamos NAT.

El protocolo uPnP es, en esencia, relativamente sencillo: se utiliza la dirección multicast 239.255.255.250 y el puerto 1900 para enviar y recibir paquetes UDP. Así, si un dispositivo quiere anunciar que cumple con el estándar uPnP, emitirá una serie de paquetes NOTIFY a dicha dirección y puerto, y aquellos dispositivos interesados estarán suscritos a ella para detectar dichos mensajes. Otra manera es que un dispositivo envíe a dicha dirección y puerto un paquete M-SEARCH, y los dispositivos responderán cada uno indicando sus capacidades y demás.

Por supuesto, cuando entramos en detalles nos encontramos con que el protocolo es mucho más rico y complejo de lo que parece. Pero afortunadamente existe el módulo de python iot-upnp, que permite de manera sencilla configurar un dispositivo como servidor uPnP. Precisamente ella ha sido el motivo de que convirtiese el código a asyncio. Básicamente basta con asignar un UUID y un par de cosas más a un diccionario, y nuestro programa ya es un servidor uPnP y responde a los anuncios. Este código está añadido en la última versión del servidor OpenDoñita.

La segunda parte es conseguir que la app de Android pida a los dispositivos uPnP que se identifiquen. En este caso no me compliqué y me limité a crear un socket UDP y enviar directamente una petición uPnP de tipo M-SEARCH, que es un paquete con estos datos:

M-SEARCH * HTTP/1.1\r\n
HOST: 239.255.255.250:1900\r\n
MAN: \"ssdp:discover\"\r\n
MX: 2\r\n
ST: upnp:rootdevice\r\n\r\n

Con eso recibiré un paquete UDP por cada dispositivo raíz uPnP directamente al mismo socket desde el que envié el paquete. Y como sólo quiero conocer la IP y nada más, lo único que necesito hacer es esperar a que aparezca uno que contenga el UUID que envía mi web app, y ese será.

Por supuesto, las cosas no son tan sencillas, pues la clase de sockets, DatagramSocket, es síncrona, lo que significa que no la podemos utilizar desde el bucle principal de Android sino que necesitamos crear un thread. Para ello utilicé una clase que extiende AsyncTask. Aunque es un método obsoleto, lo es a partir de la API 30, la cual fue lanzada ayer como quien dice (pertenece a Android 11), por lo que prefiero utilizarla y garantizar que mi código va a funcionar en móviles antiguos. Ahora simplemente implemento el método doInBackground() y dentro hago un bucle en el que envío el paquete anterior, me pongo a esperar respuestas con un timeout de 2 segundos (que coincide con el valor de MX de mi petición), y cuando salte éste, si no he conseguido la IP, repito el proceso. Pero si en alguno de los paquetes venía el UUID correcto, salgo del bucle y retorno del método. Es entonces cuando se ejecutará el método onPostExecute() recibiendo como parámetro el valor que devolví en doInBackground(). Lo interesante es que mientras que ésta última se ejecutaba en otro thread, onPostExecute() se ejecuta en el mismo thread desde el que se creó el objeto, o sea, desde el bucle principal en mi caso, con lo que ahí podré llamar al método loadUrl() del WebView para que cargue la página.

La otra cuestión importante es poder capturar el botón de Atras de Android para poder ocultar la pantalla de configuración si se pulsa, pero salir de la app si se pulsa desde la pantalla principal. Para ello sobreescribo en la actividad principal el método onBackPressed(), que es el que se llama cuando el usuario pulsa el botón, y dentro de él utilizo evaluateJavascript() para llamar a la función back_android() de la web app. Esta función hará lo que tenga que hacer y devolverá el valor 0 si no se debe hacer nada, o 1 si se debe salir de la aplicación.

Y el resto no es más que el típico código para gestionar el ciclo de vida de una aplicación de Android.

El código está disponible en mi repositorio gitlab de OpenDoñita para Android.

Parte 13

Memes animados de hoy y de siempre

Estoy preparando una entrada nueva y me apeteció añadir memes en el texto, porque ayudan a leerlo al permitir descansar la vista entre párrafo y párrafo, y le dan un toque más divertido y agradable.

Por desgracia, la cosa no es tan sencilla. Una primera opción es buscar GIFs animados, pero esto tiene varios problemas:

  • El tamaño de un GIF es bastante grande
  • El número de colores es limitado

La solución obvia es utilizar vídeos en su lugar, algo que WordPress soporta perfectamente. Para ello hay que embeberlo, activar la reproducción automática, el bucle, quitar los controles y, sobre todo, quitar el sonido. Esto último es muy importante, pues si no, el navegador se negará a reproducirlo hasta que el usuario haya interaccionado con la página (lo que obliga a haber hecho click en ella, pero no sirve con hacer scroll). El motivo para esto es evitar que una página recién cargada empiece a reproducir sonido por sorpresa, pues es algo muy molesto. Si no se hace, el vídeo no se reproducirá hasta que el usuario lo ponga en marcha a mano.

Aunque es muy fácil, por desgracia tiene el problema de que obliga a acordarse de todos los pasos, con lo que es bastante sencillo que, por despiste, se nos cuele alguno y nos quede el meme mal. Por eso decidí hacer un poco de JavaScript para solucionar esto de manera sencilla.

Lo primero es bajarse algún plugin que permita añadir JavaScript a nuestra plantilla. Yo uso WordPress, por lo que escogí Simple Custom CSS and JS. Una vez instalado y activado, sólo tenemos que añadir en nuestra plantilla este trozo de código:

let memeList = [];
function setPlayStatus(element) {
// check if it is visible
var rect = element.getBoundingClientRect();
let isVisible = (
rect.bottom >= 0 &&
rect.right >= 0 &&
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.left <= (window.innerWidth || document.documentElement.clientWidth)
);
if (isVisible != element.memeData.isVisible) {
if (isVisible) {
element.memeData.video.play();
} else {
element.memeData.video.pause();
}
element.memeData.isVisible = isVisible;
}
}

function checkForMemes() {
let elements = document.getElementsByTagName(«figure»);
for (let element of elements) {
if (!element.classList.contains(‘meme’)) {
continue;
}
memeList.push(element);
element.memeData = {};
for (let child of element.childNodes) {
if (‘controls’ in child) {
element.memeData.video = child;
element.memeData.isVisible = false;
child.muted = true;
child.controls = false;
child.loop = true;
child.autoplay = true;
setPlayStatus(element);
}
}
}
}

function refreshMemesStatus() {
for (let meme of memeList) {
setPlayStatus(meme);
}
return true;
}

window.addEventListener(«load», checkForMemes);
window.addEventListener(«DOMContentLoaded», refreshMemesStatus, false);
window.addEventListener(«scroll», refreshMemesStatus, false);
window.addEventListener(«resize», refreshMemesStatus, false);

Con esto lo único que tenemos que hacer es añadir al elemento video la clase CSS meme, y automáticamente se establecerán los parámetros necesarios para que el vídeo funcione a la primera. A mayores, cuando el meme/vídeo se sale de la zona visible de la pantalla, se le da la orden de pausa para que no consuma nada de procesador. Aunque es probable que los navegadores lo tengan en cuenta, no es mala idea dejar indicado de manera explícita que nos da igual que el vídeo no siga avanzando mientras no lo vemos.

Resolución nativa en QEmu

Como ya comenté anteriormente, estoy pasando de VirtualBox a Gnome-Boxes, el cual utiliza KVMQEmu por debajo. Esto lo hice en origen porque tenía problemas con los drivers gráficos de VirtualBox en Fedora, mientras que en Boxes, Fedora funcionaba a resolución nativa (esto es, ajustando la resolución de la máquina virtual al tamaño de la ventana) sin necesidad de instalar nada. Sin embargo, algo raro ocurría con Debian Buster (la actual estable), pues no conseguía dicho efecto.

La solución, después de buscar por ahí, fue instalar el paquete spice-vdagent y reiniciar. Con él, la resolución del sistema gráfico se ajusta automáticamente al tamaño de la ventana, con lo que trabajar en dichas máquinas virtuales es tan cómodo como en las de VirtualBox.

Multipackager, Fedora y Debian

Desde hace tiempo puedo generar paquetes fácilmente para varias distribuciones gracias a un pequeño programa que me hice, multipackager, que a partir de las fuentes, me hace paquetes para Debian estable y SID, Ubuntu LTS y actual, Fedora y Arch. Para ello genera un contenedor con la distribución concreta, añade los paquetes necesarios y ejecuta el programa que genera el paquete.

Por desgracia, ya llevaba una temporada con problemas con Fedora: no tenía manera de generar una imagen para Fedora 31. Afortunadamente, echando un vistazo a cómo lo hacía LXC pude encontrar una manera, algo chapucera, para qué negarlo.

Por desgracia, hace unos días terminó de romper del todo: hasta ahora, para generar las imágenes de contenedores utilizaba yum, la herramienta de paquetería de Fedora/Red Hat, que, afortunadamente, estaba disponible en Debian SID. Pero por desgracia, hace unos días fue eliminada de los repositorios. Algunos dirán que esa herramienta está obsoleta, y que hoy en día se utiliza dnf, y es verdad, pero por desgracia esa nunca estuvo disponible en Debian, y no fui capaz de instalarla a partir de las fuentes.

Ante esto, necesitaba una solución. Decidí echar un vistazo de nuevo a ver qué hacía LXC, y me encontré con que partía de la imagen Live ISO de Fedora, montándola, extrayendo el fichero con la imagen squashfs, extrayendo de ella el sistema de archivos, y configurando un sistema nuevo con ellos. Lo veía bastante lioso, pero no veía otra opción, así que empecé a ver cómo automatizar la descarga de la ISO… y de pronto encontré un interesante directorio en el servidor web llamado Containers… y efectivamente, contenía imágenes del sistema de archivos básicas, listas para ser utilizadas. Lo único que tenía que hacer era procesar la página web que listaba el contenido de la carpeta para obtener el nombre del fichero correcto, y a correr.

Y gracias a eso, multipackager ya vuelve a funcionar a pleno rendimiento, y he podido sacar un nuevo paquete de Cronopete que funciona en Fedora 32.

Marcadores en una nueva pestaña, y portando todo a una nueva sesión de Firefox

Hace tiempo empecé a utilizar una extensión de Firefox llamada newtab-bookmarks, pues me permitía disponer de los marcadores directamente de fondo de cualquier nueva pestaña. Sin embargo, recientemente me encontré con que mi sesión de Firefox se ha… degradado. Básicamente me ocurrían «cosas raras», cosas que en otro equipo con el mismo sistema operativo (Debian SID) y configuración no ocurrían. Probé a crear una nueva sesión desde cero y los problemas desaparecieron, por lo que decidí migrarlo todo desde la vieja a la nueva. A fin de cuentas, esta configuración fue pasando de versión en versión desde hace más de una década, por lo que tiene sentido que pueda haber algún problemilla. Y aquí empezaron mis problemas: para empezar, al ir a descargar esa extensión me encontré con que ya no está soportada, aunque afortunadamente redirige a Perfect Home, otra extensión que hace más o menos lo mismo… excepto utilizar favicons en los enlaces.

Una vez resuelto este problema, exportar los marcadores fue sencillo. Y entonces llegó el verdadero quebradero de cabeza: ¿como exporto las contraseñas guardadas? Suponía que sería algo tan sencillo como utilizar la opción de exportar, pero, sorprendentemente, dicha opción no existe. Y no es que lo diga yo, es que en Mozilla lo reconocen abiertamente.

Vemos que la opción que dan es utilizar un exportador de terceros, pero es algo que no me convence nada; a fin de cuentas, estamos hablando de dar acceso a mis contraseñas… y siendo más de cien, no me apetecía ponerme a copiarlas a mano. Afortunadamente, tras rebuscar un poco más encontré que basta con copiar los ficheros key4.db y logins.json al nuevo perfil, y dispondremos de todas nuestras contraseñas guardadas.

Compilando Gnome Shell

Estos últimos meses he estado preparando un parche para Mutter, y he necesitado instalar la rama de desarrollo de Gnome Shell. Y aunque hay bastante documentación, hay detalles que están algo incompletos, así que voy a poner aquí lo que he ido aprendiendo.

Para empezar, toda la compilación se hace mediante jhbuild, lo que simplifica muchísimo el trabajo. Y aunque es mucho más sencillo que bajarse a mano todo, aún tiene algunos detalles peliagudos.

Lo primero, si queréis tener éxito en compilar una versión de desarrollo, es mejor que utilicéis Fedora, en concreto la versión de desarrollo (o beta) también. De esta manera no tendréis problemas de versiones con las dependencias. Para ello, nada mejor que utilizar una máquina virtual. Aunque VirtualBox es una buena opción, yo tuve serios problemas con los controladores de pantalla (y es raro… con Debian o Ubuntu siempre fueron perfectamente), por lo que al final me decanté por Gnome Boxes, una herramienta más sencilla, pero con la que no tuve ningún problema.

Una vez instalada, bajamos jhbuild y lo instalamos con:

git clone https://gitlab.gnome.org/GNOME/jhbuild.git
cd jhbuild
./autogen.sh
make
make install

Una vez hecho esto debemos añadir (si no lo tenemos ya) a nuestro PATH el directorio ~/.local/bin. Y ya tendremos jhbuild instalado.

El siguiente paso es pedir que nos construya Gnome Shell. Para ello escribimos:

jhbuild build gnome-shell

Sin embargo, lo más probable es que no funcione y nos diga que nos faltan un montón de dependencias. Para instalarlas, basta con ejecutar:

jhbuild sysdeps – -install gnome-shell

y tomarse un café (o dos), porque tarda un buen rato en bajar e instalar las dependencias. Cuando termine volvemos a ejecutar el comando previo, y probablemente nos dirá que nos falta aún libavcodec y compañía. Por suerte es posible compilarlo aún así, mediante:

jhbuild build – -nodeps gnome-shell

Ahí empezará a compilar por fin, y tardará, tardará mucho (y requerirá mucho disco duro, por cierto. Aseguraos de que vuestra máquina virtual tiene suficiente). Pero lo importante que debemos saber es que el código lo baja en ~/jhbuild/checkout, por lo que si queremos aplicar parches, es ahí donde hay que tocar el código.

Cuando termina de compilar, instala todo en ~/jhbuild/install, y ya podemos probarlo. Yo lo que suelo hacer es cerrar la sesión gráfica, irme a una consola de texto (con Alt+F2), y ahí ejecutar primero:

jhbuild shell

para tener una shell dentro del entorno, y luego ejecutar:

dbus-run-session – – ~/jhbuild/install/bin/gnome-shell – -wayland – -display-server

y se arranca la sesión. Un problema que yo no he conseguido resolver es que la opción de Cerrar sesión no funciona. Yo lo resuelvo abriendo una terminal y matando el proceso.

Ubuntu arranca lento en VirtualBox

De un tiempo a esta parte, cada vez que instalaba una Ubuntu en una máquina de VirtualBox, me encontraba con que a la mitad del arranque se quedaba parada. En una de éstas me dio por probar a esperar, y muuucho tiempo después, terminó de arrancar.

Al principio parecía que tenía que ver con VirtualBox en sí, porque ocurría después de instalar los drivers para máquinas virtuales. Sin embargo, era consciente de que no tenía sentido, porque si no habría reportes por toda internet. Por eso empecé a revisar con calma la configuración, y me di cuenta de que en el procesador estaba desactivado el soporte de PAE. Esto me mosqueó, pues había leído en varios sitios que en Ubuntu al menos ahora era obligatorio, pues el núcleo por defecto viene con dicha opción activa.

Así pues, fui a la configuración, en Sistema -> Procesador, y la activé, y, efectivamente, el problema estuvo resuelto.

Creando un pincho USB de instalación de Windows

A veces no nos queda otra que usar Windows. Hay muchas circunstancias, pero podemos resumirlas en:

  • tenemos un programa que sólo funciona en Windows, y Wine no es una opción.
  • Alguien nos pide que le (re)instalemos el Windows en su equipo.

Aunque los fabricantes suelen incluir la opción de restaurar el sistema a los valores de fábrica, en mi opinión es mejor instalar la versión oficial, pues no trae mucha de la basura que meten los fabricantes. Para ello podemos bajar la ISO oficial desde la página de Microsoft. No hay problema por que nuestro ordenador no tenga una pegatina con un número de activación, pues éste se guarda en la BIOS. Es más: si no tenemos licencia, Windows 10 funciona exactamente igual, y la única limitación es que muestra un pequeño mensaje en la esquina inferior derecha pidiendo que te registres, y que no permite personalizarlo (cambiar colores, el fondo de escritorio…).

El problema viene cuando nos encontramos con que muchos equipos actuales no traen unidad de DVD, con lo que, o no podemos grabar la imagen ISO. La solución en ese caso consiste en crear un pincho USB para arrancarlo. Y aunque hay muchas utilidades para ello, en realidad es mucho más sencillo de lo que parece: basta con coger un pincho formateado en FAT32, copiar dentro todos los ficheros que hay dentro de la imagen ISO, y listo: ya tenemos un pincho arrancable en cualquier sistema UEFI… al menos hasta que descubrimos que la última versión de la ISO de Windows tiene un fichero que ocupa más de 4GB, y por tanto no se puede copiar en una partición FAT32.

Aunque algunas BIOS pueden arrancar también desde particiones NTFS, no todas lo permiten. Pero, afortunadamente, hay una solución, apuntada por win10guru:

  • Creamos dos particiones en el pincho USB: la primera, de unos 5GB, en formato FAT32, y la segunda en formato NTFS.
  • Copiamos en la primera todas las carpetas de la ISO excepto la de Sources.
  • Creamos una carpeta Sources vacía en la partición FAT32 y copiamos dentro únicamente el fichero boot.wim, que está dentro de la carpeta Sources de la imagen ISO.
  • Por último, copiamos todos los ficheros y carpetas de la ISO en la partición NTFS.

De esta manera, la BIOS arrancará desde la partición FAT32, y cederá el control a la partición NTFS.

Una vez instalado, conviene eliminar la basura que mete Microsoft. Hay varias opciones: la primera es eliminar Windows Search y Superfetch. La segunda, utilizar uno de los muchos scripts que eliminan programas que no se utilizan, tales como:

Por supuesto, yo no soy responsable de lo que hagan estos scripts, así que cada uno debe revisarlos antes para ver si lo que hacen es lo que se espera.

Un pasito p’alante María, y uno p’atrás

Hace cosa de un mes se publicó la versión 3.34 de Gnome Shell, la cual incorporaba muchas mejoras internas de rendimiento. Por desgracia, también incorporaba tantos cambios internos que un amplio porcentaje de extensiones no funcionan con ella. Esto era algo de lo que ya nos habíamos olvidado, pues desde hace unas cuantas versiones no había cambios de arquitectura internos tan grandes que afectasen de esta manera a las extensiones. Aunque tuve suerte con ActivityAppLauncher y con Desktop Icons NG (pues ambas funcionan perfectamente sin ningún cambio), no la hubo con la extensión Desktop Icons original, principalmente por culpa del nuevo sistema de herencia en clases Javascript, que, al permitir heredar desde clases de GObject, ya no obliga a meter un actor St en una propiedad de una clase, sino que la clase en sí puede heredar directamente de ella.

Afortunadamente, Marco Trevisan se encargó de subir un parche que corregía este problema; sin embargo, para poder garantizar que funcionaba correctamente tuve que esperar a que Debian Sid actualizase Gnome Shell desde 3.30 a 3.34, cosa que ocurrió hace casi dos semanas. Tras unas cuantas pruebas del código procedí a empaquetarlo y subirlo. Alegría, alboroto, labor cumplida, bla bla bla…

Hasta que empiezan a llegar los avisos de bugs. En concreto, había uno muy grave, que rompía completamente el escritorio cada vez que se intentaba renombrar un icono. Ante semejante problema, tuve que poner en cuarentena rápidamente la nueva versión de la extensión y empezar a trabajar en el parche. Desgraciadamente, no conseguía avanzar: todo lo que intentaba seguía fallando de manera misteriosa. Afortunadamente, una vez más Marco Trevisan se puso manos a la obra y subió otro parche que corregía este problema y, de paso, actualizaba la forma del cuadro de diálogo para renombrar ficheros, haciéndola más consistente con Nautilus (nunca le podré estar lo suficientemente agradecido).

Ya puestos, aproveché para pedirle que revisase un parche mío que llevaba tiempo esperando ser aplicado: uno que corregía el tamaño de los thumbnails. Finalmente se pudo aplicar a tiempo, por lo que es posible que los usuarios de Ubuntu 19.10 puedan disfrutarla «de serie».

Pero los problemas no se acabaron ahí, pues surgieron dos bugs extra que afectaban, esta vez sí, a Desktop Icons NG. El primero es que, por un error en Mutter, el gestor de ventanas de Gnome Shell, el drag and drop desde el escritorio hacia una ventana de Nautilus deja de funcionar, cuando en Gnome Shell 3.30 y 3.32 siempre funcionó perfectamente. Tras mucho esfuerzo conseguí encontrar el parche concreto en el que se introdujo el error, y lo reporté. EDITO: ya lo han corregido. ¡Genial!

El segundo problema era más grave, pues por un bug en Gnome Shell en sí, crear una ventana de tipo DESKTOP con Gnome Shell trabajando en X.org (no se en Wayland, pues actualmente no se puede), rompía el modo de Actividades: era entrar en él y el escritorio se quedaba tonto. Afortunadamente lo resolvieron a tiempo para la versión 3.34.1, que salió hace cuatro días, por lo que ya no es un problema

Por lo tanto, si estás utilizando Gnome Desktop y Gnome Shell 3.34.0, te recomiendo que actualices de inmediato a Gnome Shell 3.34.1, para asegurarse de que mis extensiones trabajen lo mejor posible.