Добавление скелета wm

This commit is contained in:
svsptech 2026-04-19 19:21:57 +05:00
parent 859f1a9f29
commit 5fa590ff66
3 changed files with 384 additions and 0 deletions

BIN
wm/x11/cwmX11 Executable file

Binary file not shown.

348
wm/x11/src/main.c Normal file
View File

@ -0,0 +1,348 @@
// main.c - чистая версия для FreeBSD
#ifndef __linux__
#define __linux__ 1 // для совместимости
#endif
#ifndef _LINUX
#define _LINUX 1
#endif
#ifndef _SAPI
#define _SAPI SciterAPI
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
// X11, OpenGL и FreeBSD специфичные заголовки
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xcomposite.h>
#include <GL/glx.h>
#include <uchar.h>
// Sciter C API (не C++!)
#include <sciter-x.h>
// Глобальные переменные X11/GLX
Display *dpy = NULL;
Window root_win = 0;
Window comp_win = 0;
int screen = 0;
int screen_width = 0;
int screen_height = 0;
GLXContext glx_ctx = NULL;
GLXFBConfig fb_config = 0;
Atom wm_delete_window = 0;
// Окно Sciter (структура вместо класса)
HWINDOW g_sciter_hwnd = NULL;
// -------------------------------------------------------------
// Инициализация X11
// -------------------------------------------------------------
void init_x11(void) {
dpy = XOpenDisplay(NULL);
if (!dpy) {
fprintf(stderr, "Ошибка: не могу открыть дисплей\n");
exit(1);
}
screen = DefaultScreen(dpy);
root_win = DefaultRootWindow(dpy);
screen_width = WidthOfScreen(DefaultScreenOfDisplay(dpy));
screen_height = HeightOfScreen(DefaultScreenOfDisplay(dpy));
XSetWindowAttributes attrs;
attrs.override_redirect = True;
attrs.background_pixel = 0;
attrs.border_pixel = 0;
attrs.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask | KeyReleaseMask;
comp_win = XCreateWindow(dpy, root_win,
0, 0, screen_width, screen_height, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWEventMask,
&attrs);
// Установка состояния окна (поверх всех и полноэкранный режим)
Atom net_wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
Atom net_wm_state_above = XInternAtom(dpy, "_NET_WM_STATE_ABOVE", False);
Atom net_wm_state_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
Atom states[] = { net_wm_state_above, net_wm_state_fullscreen };
XChangeProperty(dpy, comp_win, net_wm_state, XA_ATOM, 32,
PropModeReplace, (unsigned char *)states, 2);
// Обработка закрытия окна
wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
XSetWMProtocols(dpy, comp_win, &wm_delete_window, 1);
XMapWindow(dpy, comp_win);
XRaiseWindow(dpy, comp_win);
XFlush(dpy);
printf("Окно создано: 0x%lx (%dx%d)\n", comp_win, screen_width, screen_height);
}
// -------------------------------------------------------------
// Инициализация GLX для FreeBSD
// -------------------------------------------------------------
void init_glx(void) {
XWindowAttributes win_attrs;
XGetWindowAttributes(dpy, comp_win, &win_attrs);
Visual *window_visual = win_attrs.visual;
VisualID window_visual_id = XVisualIDFromVisual(window_visual);
// Атрибуты для GLX
int fb_attribs[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_DOUBLEBUFFER, True,
None
};
int num_fb;
GLXFBConfig *fb_configs = glXChooseFBConfig(dpy, screen, fb_attribs, &num_fb);
if (!fb_configs) {
fprintf(stderr, "Ошибка: не удалось получить FBConfig\n");
exit(1);
}
// Поиск совместимого FBConfig
GLXFBConfig compatible_config = 0;
for (int i = 0; i < num_fb; i++) {
int visual_id = 0;
glXGetFBConfigAttrib(dpy, fb_configs[i], GLX_VISUAL_ID, &visual_id);
if ((VisualID)visual_id == window_visual_id) {
compatible_config = fb_configs[i];
break;
}
}
if (!compatible_config) {
compatible_config = fb_configs[0];
printf("Предупреждение: используется несовместимый FBConfig\n");
}
fb_config = compatible_config;
XFree(fb_configs);
// Создание контекста OpenGL
glx_ctx = glXCreateNewContext(dpy, fb_config, GLX_RGBA_TYPE, NULL, True);
if (!glx_ctx) {
fprintf(stderr, "Ошибка: не удалось создать GLX контекст\n");
exit(1);
}
// Делаем контекст текущим
if (!glXMakeCurrent(dpy, comp_win, glx_ctx)) {
fprintf(stderr, "Ошибка: glXMakeCurrent не удался\n");
exit(1);
}
printf("GLX инициализирован. OpenGL: %s\n", glGetString(GL_VERSION));
}
// -------------------------------------------------------------
// Функции обратного вызова Sciter
// -------------------------------------------------------------
// Вызывается при необходимости перерисовки окна
void sciter_on_paint(HWINDOW hwnd, UINT_PTR reserved) {
// Sciter сам обрабатывает отрисовку через OpenGL
// Просто вызываем обновление
SciterUpdateWindow(hwnd);
}
// -------------------------------------------------------------
// Инициализация Sciter
// -------------------------------------------------------------
void init_sciter(void) {
// Устанавливаем графический слой OpenGL (через Skia)
SciterSetOption(NULL, SCITER_SET_GFX_LAYER, GFX_LAYER_SKIA_OPENGL);
// Включаем возможности для скриптов
SciterSetOption(NULL, SCITER_SET_SCRIPT_RUNTIME_FEATURES,
ALLOW_FILE_IO | ALLOW_SOCKET_IO | ALLOW_EVAL | ALLOW_SYSINFO);
// Создаем окно Sciter (без WinAPI, через X11)
RECT frame_rect = {0, 0, screen_width, screen_height};
g_sciter_hwnd = SciterCreateWindow(
SW_MAIN | SW_ENABLE_DEBUG,
&frame_rect,
NULL,
NULL,
NULL
);
if (!g_sciter_hwnd) {
fprintf(stderr, "Ошибка: не удалось создать Sciter окно\n");
exit(1);
}
// Устанавливаем обработчик отрисовки
//sciter_callback(g_sciter_hwnd, SCITER_CB_PAINT, (void*)sciter_on_paint);
// HTML контент
const char *html =
"<!DOCTYPE html>"
"<html><head><meta charset='UTF-8'><style>"
"html { background: transparent; overflow: hidden; }"
"body { background: rgba(26,26,26,0.9); color:#e0e0e0; "
"display:flex; justify-content:center; align-items:center; "
"height:100vh; margin:0; font-family:system-ui; }"
".panel { background:#2b2b2b; border-radius:16px; padding:32px; "
"text-align:center; box-shadow:0 8px 20px rgba(0,0,0,0.3); }"
"h1 { color:#fff; margin-bottom:16px; }"
"button { background:#0060df; color:#fff; border:none; border-radius:6px; "
"padding:12px 24px; margin:8px; cursor:pointer; font-size:16px; "
"transition:background 0.2s; }"
"button:hover { background:#003eaa; }"
"#status { margin-top:20px; color:#00ff9d; font-weight:bold; }"
"</style></head>"
"<body><div class='panel'><h1>Calista + Sciter</h1>"
"<p>Sciter работает через OpenGL на FreeBSD!</p>"
"<button onclick='document.getElementById(\"status\").innerText=\"✓ Готово!\"'>"
"Нажми меня</button>"
"<div id='status'>Система готова</div>"
"</div></body></html>";
// Загружаем HTML
SciterLoadHtml(g_sciter_hwnd, html, (UINT)strlen(html), "/");
printf("Sciter инициализирован и HTML загружен\n");
}
// -------------------------------------------------------------
// Обновление позиции окна Sciter
// -------------------------------------------------------------
void update_sciter_window_size(int width, int height) {
if (g_sciter_hwnd) {
RECT rect = {0, 0, width, height};
//SciterSetWindowRect(g_sciter_hwnd, &rect);
}
}
// -------------------------------------------------------------
// Главный цикл обработки событий
// -------------------------------------------------------------
void main_loop(void) {
XEvent ev;
bool running = true;
printf("Композитор запущен. Нажмите Q или Escape для выхода.\n");
while (running) {
// Обработка событий X11
while (XPending(dpy) > 0) {
XNextEvent(dpy, &ev);
switch (ev.type) {
case Expose:
if (ev.xexpose.count == 0) {
// Обновляем Sciter при необходимости
SciterUpdateWindow(g_sciter_hwnd);
}
break;
case KeyPress:
{
char key_str[32];
KeySym keysym;
XLookupString(&ev.xkey, key_str, sizeof(key_str), &keysym, NULL);
// Выход по Q или Escape
if (keysym == XK_q || keysym == XK_Q || keysym == XK_Escape) {
printf("Выход по запросу пользователя\n");
running = false;
}
break;
}
case ConfigureNotify:
screen_width = ev.xconfigure.width;
screen_height = ev.xconfigure.height;
update_sciter_window_size(screen_width, screen_height);
break;
case ClientMessage:
if ((Atom)ev.xclient.data.l[0] == wm_delete_window) {
printf("Получен WM_DELETE_WINDOW\n");
running = false;
}
break;
case DestroyNotify:
printf("Окно разрушено\n");
running = false;
break;
}
}
// Обновляем Sciter
SciterUpdateWindow(g_sciter_hwnd);
// Небольшая задержка для снижения нагрузки на CPU
usleep(10000); // 10ms
}
}
// -------------------------------------------------------------
// Очистка ресурсов
// -------------------------------------------------------------
void cleanup(void) {
if (g_sciter_hwnd) {
//SciterCloseWindow(g_sciter_hwnd);
g_sciter_hwnd = NULL;
}
if (glx_ctx) {
glXMakeCurrent(dpy, None, NULL);
glXDestroyContext(dpy, glx_ctx);
glx_ctx = NULL;
}
if (comp_win) {
XDestroyWindow(dpy, comp_win);
comp_win = 0;
}
if (dpy) {
XCloseDisplay(dpy);
dpy = NULL;
}
printf("Ресурсы освобождены\n");
}
// -------------------------------------------------------------
// Точка входа
// -------------------------------------------------------------
int main(int argc, char **argv) {
// Игнорируем аргументы
(void)argc;
(void)argv;
printf("Запуск Calista композитора для FreeBSD\n");
init_x11();
init_glx();
init_sciter();
main_loop();
cleanup();
return 0;
}

36
wm/x11/src/makefile Normal file
View File

@ -0,0 +1,36 @@
# Makefile for Calista Compositor
CC = cc
CFLAGS = -Wall -Wextra -O2 -g
CFLAGS += -I/usr/local/include
CFLAGS += -I/calista/engine/include
LDFLAGS = -L/usr/local/lib -lX11 -lXcomposite -lXdamage -lXrender -lGL -lEGL
LDFLAGS += -L/calista/engine -lsciter
TARGET = cwmX11
SRCS = main.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(OBJS) -o $(TARGET) $(LDFLAGS)
mv $(TARGET) ./../
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) $(TARGET)
run: $(TARGET)
./$(TARGET)
install: $(TARGET)
cp $(TARGET) /usr/local/bin/
uninstall:
rm -f /usr/local/bin/$(TARGET)
.PHONY: all clean run install uninstall