Criando uma Janela X11 com um código mínimo

O sistema X Window, também conhecido como X11, é um sistema de janelas amplamente utilizado em sistemas operacionais baseados em Unix, como o Linux. A criação de janelas em um ambiente X11 é feita usando a API Xlib, que permite que os programas se comuniquem com o servidor X e gerenciem as janelas e outros objetos gráficos.

Neste artigo, vamos mostrar um exemplo mínimo de código em C para criar uma janela usando a API Xlib. Este código vai criar uma janela simples que pode ser redimensionada e movida pelo usuário.

Antes de começarmos, é importante notar que o código que vamos mostrar aqui é apenas um exemplo mínimo e não inclui muitas das funcionalidades que seriam necessárias em uma aplicação real. Além disso, o código foi testado em um sistema Linux e pode precisar de adaptação em outros sistemas operacionais.

Vamos começar criando um arquivo chamado “main.c” e incluindo os seguintes cabeçalhos:

#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>

O cabeçalho “X11/Xlib.h” é o principal cabeçalho da API Xlib e fornece as definições das funções e tipos de dados necessários para criar uma janela. O cabeçalho “stdio.h” fornece as definições para funções de entrada e saída padrão, enquanto “stdlib.h” fornece definições para funções de alocação de memória e outras funções de propósito geral.

Em seguida, precisamos definir algumas constantes que serão usadas pelo nosso programa:

#define BORDER_WIDTH 2
#define WINDOW_TITLE "Minha janela X11"
#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 300

A constante “BORDER_WIDTH” define a largura da borda da janela em pixels, enquanto “WINDOW_TITLE” define o título da janela. “WINDOW_WIDTH” e “WINDOW_HEIGHT” definem a largura e altura da janela em pixels, respectivamente.

Agora podemos definir a função principal do programa:

int main()
{
    Display *display;
    Window window;
    int screen;
    XEvent event;
 
    display = XOpenDisplay(NULL);
    if(display == NULL)
    {
        fprintf(stderr, "Não foi possível abrir o display\n");
        exit(1);
    }
 
    screen = DefaultScreen(display);
 
    window = XCreateSimpleWindow(display, RootWindow(display, screen),
                           0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, BORDER_WIDTH,
                           BlackPixel(display, screen), WhitePixel(display, screen));
 
    XStoreName(display, window, WINDOW_TITLE);
    XSelectInput(display, window, ExposureMask | KeyPressMask | StructureNotifyMask);
 
    XMapWindow(display, window);
 
    while(1)
    {
        XNextEvent(display, &event);
        switch(event.type)
        {
            case Expose:
                break;
 
            case ConfigureNotify:
                XResizeWindow(display, window, event.xconfigure.width,
                              event.xconfigure.height);
                break;
 
            case KeyPress:
                XCloseDisplay(display);
                exit(0);
        }
    }
 
    return 0;
}

Vamos agora analisar este código em detalhes. A primeira coisa que fazemos é declarar algumas variáveis, incluindo um ponteiro para a estrutura “Display”, que representa a conexão com o servidor X, um identificador de janela, um número de tela e uma estrutura XEvent, que será usada para armazenar eventos do servidor X.

Em seguida, usamos a função XOpenDisplay para abrir uma conexão com o servidor X. Se essa função retornar NULL, significa que não foi possível abrir o display e o programa é encerrado. Caso contrário, obtemos o número de tela padrão usando a função DefaultScreen e prosseguimos criando a janela usando a função XCreateSimpleWindow.

A função XCreateSimpleWindow cria uma janela com a posição (0,0) e as dimensões especificadas em WINDOW_WIDTH e WINDOW_HEIGHT, com uma borda de largura BORDER_WIDTH e as cores preto e branco para o pixel de borda e fundo, respectivamente. Também é especificado o ID da janela raiz usando a função RootWindow.

Em seguida, usamos a função XStoreName para definir o título da janela e a função XSelectInput para especificar quais tipos de eventos a janela deve receber. No nosso caso, estamos interessados nos eventos de exposição (Exposure), teclas pressionadas (KeyPress) e mudanças na estrutura da janela (ConfigureNotify).

Depois disso, chamamos a função XMapWindow para exibir a janela na tela. Em seguida, entramos em um loop infinito que espera por eventos do servidor X usando a função XNextEvent e os processa de acordo com o tipo de evento.

Se um evento de exposição ocorrer, não precisamos fazer nada, então o código apenas pula para o próximo evento. Se ocorrer um evento de mudança de configuração da janela, usamos a função XResizeWindow para redimensionar a janela de acordo com as novas dimensões especificadas no evento. Se um evento de tecla pressionada ocorrer, usamos a função XCloseDisplay para fechar a conexão com o servidor X e sair do programa.

Por fim, o programa retorna 0 para indicar que a execução foi concluída com sucesso.

Em resumo, este exemplo de código cria uma janela simples usando a API Xlib, que pode ser redimensionada e movida pelo usuário. Embora seja um exemplo mínimo e não inclua muitas das funcionalidades que seriam necessárias em uma aplicação real, deve ajudar a entender como a API Xlib funciona e como criar janelas em um ambiente X11.