diff --git a/wm/x11/cwmX11 b/wm/x11/cwmX11 new file mode 100755 index 0000000..d0d4289 Binary files /dev/null and b/wm/x11/cwmX11 differ diff --git a/wm/x11/src/main.c b/wm/x11/src/main.c new file mode 100644 index 0000000..2d39411 --- /dev/null +++ b/wm/x11/src/main.c @@ -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 +#include +#include +#include + +// X11, OpenGL и FreeBSD специфичные заголовки +#include +#include +#include +#include +#include + +#include + +// Sciter C API (не C++!) +#include + +// Глобальные переменные 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 = + "" + "" + "

Calista + Sciter

" + "

Sciter работает через OpenGL на FreeBSD!

" + "" + "
Система готова
" + "
"; + + // Загружаем 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; +} \ No newline at end of file diff --git a/wm/x11/src/makefile b/wm/x11/src/makefile new file mode 100644 index 0000000..9974f2b --- /dev/null +++ b/wm/x11/src/makefile @@ -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 \ No newline at end of file