gvsbuild + theme 찍먹하기

지난날 우리는 meson을 찍먹하면서 gvsbuild를 통한 윈도위 GUI 앱 개발을 시도했고 성공적으로 마무리 했었다.

이제 테마를 찍먹해보고자 한다. 일단 프로젝트 디렉터리에 style.css를 추가한다.

/* 윈도우 전체 배경 */
window {
  background: linear-gradient(to bottom right, #2c3e50, #3498db);
  color: white;
}

/* 버튼 스타일 */
button {
  background-image: none;
  background-color: #e74c3c;
  color: white;
  border-radius: 10px;
  padding: 10px 20px;
  font-weight: bold;
}

button:hover {
  background-color: #c0392b;
}

/* 라벨 폰트 키우기 */
label {
  font-size: 20px;
}

#include <gtk/gtk.h>

// CSS 로드 함수
static void load_css() {
    GtkCssProvider *provider = gtk_css_provider_new();
    GdkDisplay *display = gdk_display_get_default();

    // style.css 파일 로드
    gtk_css_provider_load_from_resource(provider, "/org/gtk/example/style.css");

    // 화면 전체에 CSS 적용 (우선순위 높게)
    gtk_style_context_add_provider_for_display(display,
                                               GTK_STYLE_PROVIDER(provider),
                                               GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
    g_object_unref(provider);
}

static void activate(GtkApplication* app, gpointer user_data) {
    GtkWidget* window;
    GtkWidget* box;
    GtkWidget* label;
    GtkWidget* button;

    // 1. CSS 로드 (앱 실행 시 최초 1회)
    load_css();

    window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Stylish GTK");
    gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);

    // 레이아웃 박스 (수직 정렬)
    box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 20);
    gtk_widget_set_halign(box, GTK_ALIGN_CENTER);
    gtk_widget_set_valign(box, GTK_ALIGN_CENTER);
    gtk_window_set_child(GTK_WINDOW(window), box);

    // 라벨
    label = gtk_label_new("안녕하세요, GTK4!");
    gtk_box_append(GTK_BOX(box), label);

    // 버튼
    button = gtk_button_new_with_label("클릭해보세요");
    gtk_box_append(GTK_BOX(box), button);
    g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_window_destroy), window);

    gtk_widget_show(window);
}

int main(int argc, char** argv) {

    GtkApplication* app;
    int status;

    app = gtk_application_new("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

이제 meson.build 파일도 수정해본다.

project('gtk_hello', 'c', 'cpp',
  version : '0.1',
  default_options : ['cpp_std=c++17'])

# [추가 1] 윈도우 인코딩 해결
if host_machine.system() == 'windows'
  add_project_arguments('/utf-8', language : 'cpp')
endif

# [추가 2] gnome 모듈 가져오기 (리소스를 굽기 위해 필요)
gnome = import('gnome')

# [추가 3] 리소스 컴파일 (xml -> c 파일로 변환)
resources = gnome.compile_resources(
  'project-resources',
  'resources.gresource.xml',
  source_dir : '.'
)

gtk_dep = dependency('gtk4')

executable('gtk_hello',
           'main.cpp',
           resources, # [추가 4] 여기에 구워진 리소스 추가
           dependencies : gtk_dep,
           win_subsystem : 'console') # 배포시엔 'windows'로 변경

이제 같은 위치에 resources.gresource.xml 이라는 파일도 추가해준다.

<?xml version="1.0" encoding="UTF-8"?>
<gresources>
  <gresource prefix="/org/gtk/example">
    <file>style.css</file>
  </gresource>
</gresources>

set PKG_CONFIG_PATH=Q:\gtk-build\gtk\x64\release\lib\pkgconfig
set PATH=%PATH%;Q:\gtk-build\gtk\x64\release\bin

다시 환경변수를 설정해준다.

meson setup build_vs --reconfigure

다음과 같이 컴파일을 완료하면 exe파일이 생성된다.

다음과 같이 테마가 바뀐 것을 볼 수 있다.

# deploy.ps1
$BuildDir = ".\build_vs"  # Meson 빌드 폴더
$GtkDir = "Q:\gtk-build\gtk\x64\release" # GTK 설치 경로
$DistDir = ".\dist"       # 배포판이 저장될 폴더

# 1. 배포 폴더 초기화
Write-Host "Creating distribution folder..."
if (Test-Path $DistDir) { Remove-Item -Recurse -Force $DistDir }
New-Item -ItemType Directory -Force $DistDir | Out-Null
New-Item -ItemType Directory -Force "$DistDir\bin" | Out-Null

# 2. 실행 파일 복사 (CSS 포함)
Write-Host "Copying App..."
Copy-Item "$BuildDir\gtk_hello.exe" "$DistDir\bin\"
Copy-Item ".\style.css" "$DistDir\bin\"

# 3. DLL 복사 (무식하지만 확실한 방법: GTK bin 폴더 통째로 복사)
# 실제 배포시에는 필요한 dll만 추려야 하지만, 찍먹용으론 이게 제일 확실함
Write-Host "Copying Dependencies (DLLs)..."
Get-ChildItem "$GtkDir\bin\*.dll" | Copy-Item -Destination "$DistDir\bin"

# 4. 리소스 복사 (share 폴더 - 스키마, 아이콘 등)
# 이게 없으면 앱이 실행되다가 "GSettings 스키마 없음" 에러로 죽음
Write-Host "Copying Resources (share)..."
Copy-Item -Recurse "$GtkDir\share" "$DistDir\"

Write-Host "Done! Run $DistDir\bin\gtk_hello.exe"

와 같이 배포파일을 만들어서 실행한다.


좋다 이젠 whitesur light 테마를 써서 더 이쁘게 꾸며볼것이다.

우선 기존의 cpp 코드의 load_css 구문을 주석 처리한다.

meson setup build_vs --reconfigure
meson compile -C build_vs

https://github.com/vinceliuice/WhiteSur-gtk-theme

다음 링크에서 소스 코드를 다운 받는다.

압축을 푼다.

dist\share\themes 디렉터리를 만든다.

그리고 그 아래 WhiteSur-Light 디렉터리를 만든다.

이제 gtk-4.0 의 파일들을 집어 넣는다.

Q:\Coding\...\dist\
  └─ bin\
       └─ gtk_hello.exe
  └─ share\
       └─ themes\
            └─ WhiteSur-Light\
                 └─ gtk-4.0\
                      ├─ gtk.css  <-- 핵심 파일
                      ├─ gtk-dark.css
                      └─ assets\  (이미지들)

와 같은 느낌으로 하면 된다.

이제

dist\etc\gtk4.0\settings.inidist\etc\gtk-4.0\settings.ini

파일을 만든다.

[Settings]
gtk-theme-name=WhiteSur-Light
gtk-font-name=Segoe UI 10
gtk-xft-antialias=1
gtk-xft-hinting=1
gtk-xft-hintstyle=hintfull

이제 다시 exe 를 실행한다.

테마를 다크하게 바꾸려면 WhiteSur-Dark를 아까처럼 복사하고


[Settings]
gtk-theme-name=WhiteSur-Dark
gtk-application-prefer-dark-theme=1
gtk-font-name=Segoe UI 10
gtk-xft-antialias=1
gtk-xft-hinting=1
gtk-xft-hintstyle=hintfull

와 같이 바꾼다.