Desktop Window Manager, Los entresijos de la interfaz visual de Windows Vista (1ª Parte)

Uno de los temas más comentados del nuevo Windows Vista es sin duda las novedades incluidas en su interfaz visual. Trasparencias en las ventanas, Windows Flip o Windows Flip3D tienen un denominador común, el uso de la nueva API de Windows Vista, Desktop Window Manager, o como la conocen sus más allegados, la WoWAPI. ¿Pero qué posibilidades brinda a los programadores esta nueva librería?Uno de los aspectos más potenciados y destacables de Windows Vista, nuevo sistema operativo de escritorio de Microsoft, es sin lugar a dudas su interfaz gráfica, y en particular el nuevo estilo creado para presentar sus características, el Aero Glass, pero este estilo no es más que un cliente o fachada de la característica más importante de toda la interfaz de Vista, la composición de escritorio.


El poder de delegar


En las versiones previas de Windows, la visualización de las ventanas en pantalla se realiza mediante accesos directos a zonas de memoria de video, de forma estándar, usando las funciones mínimas de los dispositivos de visualización, para asegurar así un nivel total de compatibilidad. Ahora gracias a Windows Vista, cuando el sistema operativo necesita mostrar una ventana por pantalla, ya no interactúa directamente con el hardware, sino que delega esta misión a la capa de composición de escritorio, bautizada en esta ocasión como Desktop Window Manager y que en lo sucesivo denominaremos DWM.


La simple idea de delegar tareas que hasta el momento se venían aplicando directamente puede conducirnos a la conclusión de que estamos sobrecargando la arquitectura innecesariamente, y eso sería cierto si no tuviéramos en cuenta el detalle más importante, y es que DWM no sólo actúa de puente para trasladar la información a visualizar hasta el dispositivo de salida, si no que lo hará teniendo en cuenta las características de dicho dispositivo.


Aceleración gráfica


Hasta la llegada de Vista la elección de una tarjeta gráfica para un ordenador de escritorio destinado a ejecutar Windows venía condicionada casi exclusivamente a la siguiente sencilla pregunta: ¿Piensas ejecutar videojuegos? O dicho de un modo más técnico: ¿Vas a necesitar que tu máquina dé soporte a DirectX? Si la respuesta a las anteriores preguntas era negativa, la elección se simplificaba en grado sumo, ya que con tarjetas gráficas sencillas se obtienen resoluciones, profundidades de color y rendimientos suficientes para ejecutar aplicaciones de escritorio de forma fluida y correcta. Si por el contrario nos adentrábamos en territorio jugón la elección de un dispositivo pensado para soportar DirectX venía siendo mucho más compleja, y por qué no decirlo, bastante más cara. Esta situación no entrañaría ninguna particularidad destacable si no fuera por un hecho muy habitual para muchos usuarios de Windows, y es que en muchas ocasiones se encuentran con que su tarjeta de video en el contexto de un videojuego es capaz de mover gran cantidad de polígonos, a la vez que les aplica efectos visuales y técnicas de sombreado complejas, pero que cuando acaban de jugar y vuelven al escritorio, se pueden encontrar que algo tan simple como arrastrar una ventana sobre otra, puede ocasionar que no se redibuje de forma fluida el contenido de la ventana sobre volada, produciendo efectos visuales molestos y poco vistosos (Imagen 1).


Imagen 1


Imagen 1


Mediante DWM las aplicaciones de escritorio también tienen acceso a las características de aceleración gráfica de los dispositivos de visualización, que hasta la fecha venían usando en exclusiva los videojuegos y las aplicaciones implementadas mediante DirectX. Con Windows Vista y la composición de escritorio podemos disfrutar de un entorno de trabajo más elegante y productivo, con un mejor rendimiento, aprovechando todos los recursos que nos ofrece el hardware de nuestras máquinas.


Primera toma de contacto


DWM reside en disco dentro del ejecutable dwm.exe, pero como programadores accederemos a sus funcionalidades mediante su interfaz pública dwmapi.dll. Para conocer en detalle la interfaz expuesta por DWM no existe mejor recurso que la documentación en línea de Microsoft que podemos consultar en el siguiente enlace: http://msdn2.microsoft.com/en-us/library/aa969540.aspx


Lamentablemente dwmapi.dll no expone una interfaz COM ni soporta código administrado, con lo que deberemos redefinir la interfaz, de forma íntegra o parcial, mediante importaciones de la librería dentro de nuestras aplicaciones.


Detectar y establecer el entorno


Antes de usar la composición de escritorio es bueno tener en cuenta que versiones de Windows Vista como la Home Basic, no soportan composición de escritorio, ni todas las configuraciones de hardware son capaces de soportarlo, con lo que podemos encontrarnos con que las ventajas inherentes de esta tecnología visual no siempre se mostrarán disponibles. También podemos hallar escenarios donde a pesar de disponer y soportar todos los prerrequisitos la composición de escritorio se encuentre desactivada. Es por ello, que nuestro primer objetivo desde el punto de vista de un programador será detectar el estado del sistema de composición de escritorio, y activarlo o desactivarlo dependiendo de la situación y nuestros intereses.


Para ello usaremos las funciones DwmIsCompositionEnabled y DwmEnableComposition contenidas en dwmapi.dll. Mediante la primera consultaremos el estado del servicio de composición de escritorio, y con la segunda podremos modificar el estado del mismo. De este modo, con tan sólo una sentencia (Código 1) podemos conmutar el estado del servicio de composición de escritorio.


Importar declaraciones:


 


1 [DllImport(«dwmapi.dll«, PreserveSig = false)]
2 public static extern bool DwmIsCompositionEnabled();
3 [DllImport(«dwmapi.dll«, PreserveSig = false)]
4 public static extern void DwmEnableComposition(bool Activo);

 


Ejemplo de uso:


 


1 //Conmutar el estado de la composición de escritorio
2 DwmEnableComposition(!DwmIsCompositionEnabled());

 


El efecto glass


El usuario que por primera vez se enfrente al estilo Aero Glass de Windows Vista, enseguida se dará cuenta de que ahora muchos de los elementos del sistema operativo se muestran de forma semitransparente. El efecto glass es la primera característica que los formularios de nuestras aplicaciones podrán heredar sin tener que escribir ni una sola línea de código, aunque con una única salvedad, las transparencias no se aplicarán a la zona de cliente, es decir, allí donde podemos desplazar nuestros controles para dibujar el contenido de los formularios, sino que únicamente afectarán al contorno y título de la ventana (Imagen 2).


Imagen 2


Imagen 2


Gracias a DWM no tendremos que conformarnos con las limitaciones del comportamiento estándar respecto a los formularios de nuestras aplicaciones. Mediante la función DwmExtendFrameIntoClientArea, también incluida en dwmapi.dll,  podemos extender el comportamiento y la apariencia del marco de la ventana al conjunto de la misma (Imagen 3). Tan sólo deberemos indicar los márgenes que deseamos que queden excluidos de dicho comportamiento, aunque para conseguir los resultados deseados deberemos realizar un pequeño paso más, consistente en pintar de color negro el fondo de la ventana (Código 2). De este modo la máscara de trasparencia coincidirá con la máscara del color de fondo, activando así el efecto.


Imagen 3


Imagen 3


Definir las estructuras necesarias:


1 [StructLayout(LayoutKind.Sequential)]
2 public class MARGINS
3 {
4 public int margenIzquierdo, margenDerecho;
5 public int margenSuperior, margenInferior;
6 public MARGINS(int izquierda, int arriba,
7 int derecha, int abajo)
8 {
9 margenIzquierdo = izquierda; margenSuperior = arriba;
10 margenDerecho = derecha; margenInferior = abajo;
11 }
12 }

Importar declaraciones:


 


1 [DllImport(«dwmapi.dll«, PreserveSig = false)]
2 public static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, MARGINS pMargins);

 


Ejemplo de uso:


1 MARGINS margenes = new MARGINS(1, 0, 0, 0);
2 if (DwmIsCompositionEnabled())
3 {
4 //MUY IMPORTANTE! Poner el color de fondo en negro
5 gf.BackColor = Color.Black;
6 DwmExtendFrameIntoClientArea(this.Handle, margenes);
7 }

Si lo que deseamos es aplicar el efecto a la ventana completa emplearemos márgenes negativos.


Vistas en miniatura


La otra novedad incluida en la interfaz Windows Vista, y disponible mediante composición de escritorio, son las miniaturas de ventanas (thumbnails), mediante las cuales podremos monitorizar la interfaz visual de cualquiera de las ventanas que tengamos abiertas. Podemos apreciar esta característica tanto en la barra de tareas (Imagen 4), como en las dos versiones de flip (la estándar y la tridimensional), el conmutador de aplicaciones de Windows.


Imagen 4


Imagen 4


Disponemos de esta nueva característica mediante la función DwmRegisterThumbnail. Tan solo deberemos indicar la ventana que deseamos monitorizar, así como que otra ventana mostrará dicho escaner visual. Usando la función DwmUpdateThumbnailProperties podremos modificar las propiedades de la vista en miniatura, controlando características como el  tamaño o la opacidad de la misma.


Como ejemplo (Código 3) podemos crear dos instancias de un formulario, modificar su color de fondo, uno en rojo y el otro en azul, para posteriormente crear un tercer formulario que monitorice la actividad visual de los dos anteriores. Una vez ejecutado el último formulario, podremos redimensionar el tamaño de cualquiera de las dos ventanas coloreadas, viendo como las vistas en miniatura reflejan al instante los cambios efectuados.


Definir las estructuras necesarias:


1 [StructLayout(LayoutKind.Sequential)]
2 public class DWM_THUMBNAIL_PROPERTIES
3 {
4 public uint interruptores;
5 public RECT destino;
6 public RECT fuente;
7 public byte opacidad;
8 [MarshalAs(UnmanagedType.Bool)]
9 public bool visible;
10 [MarshalAs(UnmanagedType.Bool)]
11 public bool fuenteSoloCliente;
12 public const uint DWM_TNP_RECTDESTINO = 0x00000001;
13 public const uint DWM_TNP_RECTFUENTE = 0x00000002;
14 public const uint DWM_TNP_OPACIDAD = 0x00000004;
15 public const uint DWM_TNP_VISIBLE = 0x00000008;
16 public const uint DWM_TNP_FUENTESOLOCLIENTE = 0x00000010;
17 }


Importar declaraciones:


 


1 [DllImport(«dwmapi.dll«, PreserveSig = false)]
2 public static extern IntPtr DwmRegisterThumbnail(
3 IntPtr destino, IntPtr fuente);
4 [DllImport(«dwmapi.dll«, PreserveSig = false)]
5 public static extern void DwmUpdateThumbnailProperties(
6 IntPtr miniatura,
7 DWM_THUMBNAIL_PROPERTIES propiedadesMiniatura);

 

Ejemplo de uso:

1 private void ActualizarMiniatura(IntPtr miniatura,
2 int margenIzquierdo, int margenSuperior, int ancho, int alto){
3 if (miniatura != IntPtr.Zero)
4 {
5 // Crear una estructura de propiedades de miniatura
6 DWM_THUMBNAIL_PROPERTIES propiedadesMiniatura;
7 propiedadesMiniatura = new DWM_THUMBNAIL_PROPERTIES();
8 // Establecer que propiedades se pueden actualizar:
9 // – Visibilidad, opacidad, posición y tamaño de la
10 // miniatura y sección de la ventana a monitorizar
11 propiedadesMiniatura.interruptores = DWM_THUMBNAIL_PROPERTIES.DWM_TNP_VISIBLE +
12 DWM_THUMBNAIL_PROPERTIES.DWM_TNP_OPACIDAD +
13 DWM_THUMBNAIL_PROPERTIES.DWM_TNP_RECTDESTINO +
14 DWM_THUMBNAIL_PROPERTIES.DWM_TNP_FUENTESOLOCLIENTE;
15 // Indicamos el tamaño y posición de la miniatura
16 propiedadesMiniatura.destino =
17 new DWMLibrary.RECT(margenIzquierdo, margenSuperior, ancho, alto);
18 // Solicitamos monitorizar el global de la ventana,
19 // tanto la zona de cliente, como la de sistema
20 propiedadesMiniatura.fuenteSoloCliente = false;
21 // Asignamos la visibilidad y opacidad
22 propiedadesMiniatura.opacidad = 255;
23 propiedadesMiniatura.visible = true;
24 // Asignamos las nuevas propiedades a la miniatura
25 DwmUpdateThumbnailProperties(miniatura,
26 propiedadesMiniatura);
27 }
28 }
En el formulario que visualizará las miniaturas:

1 // Crear los formularios a monitorizar, uno rojo y el otro azul
2 IntPtr miniaturaRoja; IntPtr miniaturaAzul;
3 Form formularioRojo = new Form();
4 Form formularioAzul = new Form();
5 formularioRojo.BackColor = Color.Red;
6 formularioAzul.BackColor = Color.Blue;
7 formularioRojo.Show();
8 formularioAzul.Show();
9 if (DwmIsCompositionEnabled())
10 {
11 // Capturar miniaturas
12 miniaturaRoja = DWMLibrary.DwmRegisterThumbnail(this.Handle,
13 (IntPtr)(formularioRojo.Handle));
14 miniaturaAzul = DWMLibrary.DwmRegisterThumbnail(this.Handle,
15 (IntPtr)(formularioAzul.Handle));
16 // Posicionar las miniaturas
17 ActualizarMiniatura(miniaturaRoja, 10, 10, 110, 110);
18 ActualizarMiniatura(miniaturaAzul, 10, 120, 110, 230);
19 }

Resumen


Hasta el momento hemos introducido los conceptos básicos de la composición de escritorio y las particularidades de esta tecnología aplicadas a Windows Vista. También hemos podido ver cómo empezar a trabajar con esta tecnología desde .NET.


Más adelante trataremos de implementar un pequeño ejemplo algo más completo.


[Crossposting desde http://www.tonirecio.com]

2 comentarios sobre “Desktop Window Manager, Los entresijos de la interfaz visual de Windows Vista (1ª Parte)”

  1. use ubuntu, es mejor ^^

    Windows Vista aunque tenga lo que tenga, pienso que hay mas grado de personalizacion en linux, ademas, hay muchos programas necesarios incompatibles con vista, ademas de que linuix posee todo lo necesario en un solo paquete, 3 gigas gasta, encima que si instalas mas cosas al propio vista, te salen mas de 5 gigas…

    ademas, el vista, por lo minimo, gasta 256 RAM y Ubuntu la mitad…

    Y la ventaja de usar linux que es no le afecten virus, lo hace mejor ^^

    conclusion: Usar linux y borrar Vista xD

  2. mira no te cierres a una tecnologia, yo igual uso linux ubuntu, suse etc de igual manera uso windows no no ando peleado con ambos, simpre es bueno saber de ambas asi cuando te lo pidan en windows lo puedes hacer y vicecesa con linux – no saber programar para windows es suficiente pretexto como para que no te contraten

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *