Edit

kc3-lang/kc3/window/cairo/win32/window_cairo_win32.c

Branch :

  • window/cairo/win32/window_cairo_win32.c
  • /* kc3
     * Copyright from 2022 to 2025 kmx.io <contact@kmx.io>
     *
     * Permission is hereby granted to use this software granted the above
     * copyright notice and this permission paragraph are included in all
     * copies and substantial portions of this software.
     *
     * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
     * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
     * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
     * THIS SOFTWARE.
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <xkbcommon/xkbcommon.h>
    #include <windows.h>
    #include <cairo.h>
    #include <cairo-win32.h>
    #include "../../../libkc3/kc3.h"
    #include "vk_to_xkbcommon.h"
    #include "window_cairo_win32.h"
    
    bool window_cairo_run (s_window_cairo *window)
    {
      return window_cairo_win32_run(window);
    }
    
    LRESULT CALLBACK window_cairo_win32_proc (HWND hwnd, UINT message,
    					  WPARAM wParam, LPARAM lParam)
    {
      HBITMAP buffer_hbitmap;
      HDC buffer_hdc;
      cairo_t *cr;
      HDC hdc;
      u32 keysym;
      PAINTSTRUCT ps;
      cairo_surface_t *surface;
      u32 vk;
      s_window_cairo *window;
      HDC window_hdc;
      window = (s_window_cairo *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
      switch (message) {
      case WM_DESTROY:
        printf("WM_DESTROY\n");
        PostQuitMessage(0);
        break;
      case WM_ERASEBKGND:
        return 1;
      case WM_KEYDOWN:
        vk = (u32) wParam;
        keysym = vk_to_xkbcommon(vk);
        if (! window->key(window, keysym)) {
          printf("window->key -> false\n");
          PostQuitMessage(1);
        }
        break;
      case WM_PAINT:
        window_hdc = GetDC(hwnd);
        buffer_hdc = CreateCompatibleDC(window_hdc);
        buffer_hbitmap = CreateCompatibleBitmap(window_hdc, window->w,
                                                window->h);
        SelectObject(buffer_hdc, buffer_hbitmap);
        surface = cairo_win32_surface_create(buffer_hdc);
        cr = cairo_create(surface);
        window->cr = cr;
        if (! window->render(window)) {
          printf("render -> false\n");
          PostQuitMessage(1);
        }
        cairo_surface_flush(surface);
        cairo_destroy(window->cr);
        cairo_surface_destroy(surface);
        hdc = BeginPaint(hwnd, &ps);
        BitBlt(hdc, 0, 0, window->w, window->h, buffer_hdc, 0, 0, SRCCOPY);
        EndPaint(hwnd, &ps);
        DeleteObject(buffer_hbitmap);
        DeleteDC(buffer_hdc);
        DeleteDC(window_hdc);
        DeleteDC(hdc);
        break;
      case WM_SIZE:
        if (! window->resize(window, LOWORD(lParam), HIWORD(lParam)))
          PostQuitMessage(1);
        window->w = LOWORD(lParam);
        window->h = HIWORD(lParam);
        InvalidateRect(hwnd, NULL, TRUE);
        break;
      default:
        return DefWindowProc(hwnd, message, wParam, lParam);
      }
      return 0;
    }
    
    bool window_cairo_win32_run (s_window_cairo *window)
    {
      HWND hwnd;
      MSG msg;
      s_timespec sleep;
      WNDCLASSEX wc;
      wc.cbSize        = sizeof(WNDCLASSEX);
      wc.style         = 0;
      wc.lpfnWndProc   = window_cairo_win32_proc;
      wc.cbClsExtra    = 0;
      wc.cbWndExtra    = 0;
      wc.hInstance     = GetModuleHandle(NULL);
      wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
      wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
      wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
      wc.lpszMenuName  = NULL;
      wc.lpszClassName = "Libkc3WindowCairoWin32";
      wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
      if (!RegisterClassEx(&wc)) {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
                   MB_ICONEXCLAMATION | MB_OK);
        return 0;
      }
      hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
                            "Libkc3WindowCairoWin32",
                            window->title,
                            WS_OVERLAPPEDWINDOW,
                            window->x, window->y, window->w, window->h,
                            NULL, NULL, GetModuleHandle(NULL), NULL);
      if (hwnd == NULL) {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
                   MB_ICONEXCLAMATION | MB_OK);
        return 0;
      }
      SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) window);
      if (! window->load(window))
        PostQuitMessage(1);
      ShowWindow(hwnd, SW_SHOWDEFAULT);
      UpdateWindow(hwnd);
      while (true) {
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
          if (msg.message == WM_QUIT)
            goto quit;
          TranslateMessage(&msg);
          DispatchMessage(&msg);
        }
        sleep.tv_sec = 0;
        sleep.tv_nsec = 1000000000 / 120;
        nanosleep(&sleep, NULL);
        InvalidateRect(hwnd, NULL, TRUE);
      }
     quit:
      return msg.wParam ? false : true;
    }