Loading...
Loading...
Compare original and translation side by side
var(--variable)@variablecolor-mix()filter: brightness()@media (prefers-color-scheme: dark)var(--window-bg-color)/* ❌ GTK3 syntax - breaks in GTK4 */
@define-color my_color red;
@define-color window_bg var(--window-bg);
color: @my_color;/* ✅ GTK4 syntax - correct */
:root {
--my-color: red;
--window-bg: var(--window-bg-color);
}
.card {
background-color: var(--my-color);
color: var(--window-bg);
}references/libadwaita-styling.mdvar(--variable)@variablecolor-mix()filter: brightness()@media (prefers-color-scheme: dark)var(--window-bg-color)/* ❌ GTK3语法 - 在GTK4中会失效 */
@define-color my_color red;
@define-color window_bg var(--window-bg);
color: @my_color;/* ✅ GTK4语法 - 正确写法 */
:root {
--my-color: red;
--window-bg: var(--window-bg-color);
}
.card {
background-color: var(--my-color);
color: var(--window-bg);
}references/libadwaita-styling.md/* Use system fonts for platform consistency */
window {
font-family: "Cantarell", system-ui, sans-serif;
font-weight: 400;
}
/* Headlines get emphasis */
.title {
font-family: "Cantarell", system-ui, sans-serif;
font-weight: 700;
font-size: 24pt;
}
/* Monospace for code */
.code {
font-family: "JetBrains Mono", "Monospace", monospace;
}/* 使用系统字体保证平台一致性 */
window {
font-family: "Cantarell", system-ui, sans-serif;
font-weight: 400;
}
/* 标题文字强调显示 */
.title {
font-family: "Cantarell", system-ui, sans-serif;
font-weight: 700;
font-size: 24pt;
}
/* 代码使用等宽字体 */
.code {
font-family: "JetBrains Mono", "Monospace", monospace;
}document-symbolicedit-find-symboliccolor: var(--accent-bg-color);// Add symbolic icon to button
GtkWidget *button = gtk_button_new_from_icon_name("document-open-symbolic");
gtk_button_set_icon_name(GTK_BUTTON(button), "document-save-symbolic");document-symbolicedit-find-symboliccolor: var(--accent-bg-color);// 为按钮添加符号化图标
GtkWidget *button = gtk_button_new_from_icon_name("document-open-symbolic");
gtk_button_set_icon_name(GTK_BUTTON(button), "document-save-symbolic");/* Use CSS variables for theme integration */
:root {
/* Override accent color for brand identity */
--accent-bg-color: var(--accent-blue);
--accent-fg-color: white;
}
/* Custom accent color - e.g., purple brand */
:root {
--accent-bg-color: var(--accent-purple);
--accent-color: oklab(from var(--accent-bg-color) var(--standalone-color-oklab));
}
/* Dark mode overrides */
@media (prefers-color-scheme: dark) {
.card {
background-color: rgba(255, 255, 255, 0.05);
}
}
/* High contrast mode */
@media (prefers-contrast: more) {
.card {
border: 2px solid currentColor;
}
}/* 使用CSS变量实现主题集成 */
:root {
/* 覆盖强调色以塑造品牌标识 */
--accent-bg-color: var(--accent-blue);
--accent-fg-color: white;
}
/* 自定义强调色 - 例如紫色品牌风格 */
:root {
--accent-bg-color: var(--accent-purple);
--accent-color: oklab(from var(--accent-bg-color) var(--standalone-color-oklab));
}
/* 深色模式覆盖样式 */
@media (prefers-color-scheme: dark) {
.card {
background-color: rgba(255, 255, 255, 0.05);
}
}
/* 高对比度模式 */
@media (prefers-contrast: more) {
.card {
border: 2px solid currentColor;
}
}/* Cards with subtle shadows */
.card {
background-color: var(--card-bg-color);
border-radius: 12px;
padding: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
}
/* Primary buttons use accent color */
.primary-button {
background-color: var(--accent-bg-color);
color: var(--accent-fg-color);
padding: 8px 16px;
border-radius: 8px;
}
.primary-button:hover {
/* GTK4: Use color-mix() instead of filter: brightness() */
background-color: color-mix(in srgb, var(--accent-bg-color) 90%, white);
}/* 带有柔和阴影的卡片 */
.card {
background-color: var(--card-bg-color);
border-radius: 12px;
padding: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
}
/* 主按钮使用强调色 */
.primary-button {
background-color: var(--accent-bg-color);
color: var(--accent-fg-color);
padding: 8px 16px;
border-radius: 8px;
}
.primary-button:hover {
/* GTK4:使用color-mix()替代filter: brightness() */
background-color: color-mix(in srgb, var(--accent-bg-color) 90%, white);
}/* 4px base unit */
.space-xs { padding: 4px; }
.space-sm { padding: 8px; }
.space-md { padding: 12px; }
.space-lg { padding: 16px; }
.space-xl { padding: 24px; }
.space-2xl { padding: 32px; }/* 以4px为基础单位 */
.space-xs { padding: 4px; }
.space-sm { padding: 8px; }
.space-md { padding: 12px; }
.space-lg { padding: 16px; }
.space-xl { padding: 24px; }
.space-2xl { padding: 32px; }/* Match Adwaita conventions */
button {
border-radius: 8px;
}
window {
border-radius: 12px;
}
.card {
border-radius: 12px;
}/* 匹配Adwaita规范 */
button {
border-radius: 8px;
}
window {
border-radius: 12px;
}
.card {
border-radius: 12px;
}/* Smooth property transitions */
button {
transition: background-color 200ms ease,
transform 100ms ease,
box-shadow 200ms ease;
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);
}
button:active {
transform: translateY(0);
}/* 平滑的属性过渡 */
button {
transition: background-color 200ms ease,
transform 100ms ease,
box-shadow 200ms ease;
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);
}
button:active {
transform: translateY(0);
}/* Fade in for new content */
fade-in {
animation: fadeIn 300ms ease-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
/* Avoid excessive animations - use sparingly for emphasis *//* 新内容淡入效果 */
fade-in {
animation: fadeIn 300ms ease-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
/* 避免过度动画 - 仅在需要强调时使用 *//* Use AdwLeaflet for mobile-first layouts */
GtkWidget *leaflet = adw_leaflet_new();
adw_leaflet_set_collapsed(GTK_LEAFLET(leaflet), TRUE);
/* Content adapts based on fold state */
g_signal_connect(leaflet, "notify::folded",
G_CALLBACK(on_fold_changed), NULL);/* 使用AdwLeaflet实现移动端优先布局 */
GtkWidget *leaflet = adw_leaflet_new();
adw_leaflet_set_collapsed(GTK_LEAFLET(leaflet), TRUE);
/* 根据折叠状态适配内容 */
g_signal_connect(leaflet, "notify::folded",
G_CALLBACK(on_fold_changed), NULL);/* Compact layouts for narrow windows */
window {
min-width: 360px;
min-height: 240px;
}
@media (max-width: 600px) {
.sidebar {
display: none;
}
}
/* Use AdwBreakpoint for more complex responsive behavior *//* 窄窗口下的紧凑布局 */
window {
min-width: 360px;
min-height: 240px;
}
@media (max-width: 600px) {
.sidebar {
display: none;
}
}
/* 更复杂的响应式行为使用AdwBreakpoint */// Ensure all interactive elements are keyboard focusable
gtk_widget_set_can_focus(widget, TRUE);
// Set focus order
gtk_widget_set_focus_on_click(button, TRUE);
// Mnemonic shortcuts
gtk_label_set_mnemonic_widget(label, entry);// 确保所有交互元素可通过键盘聚焦
gtk_widget_set_can_focus(widget, TRUE);
// 设置聚焦顺序
gtk_widget_set_focus_on_click(button, TRUE);
// 助记快捷键
gtk_label_set_mnemonic_widget(label, entry);// Label widgets properly
gtk_accessible_update_property(GTK_ACCESSIBLE(widget),
GTK_ACCESSIBLE_PROPERTY_LABEL, "Save changes",
-1
);
// Add descriptions for complex widgets
gtk_accessible_update_property(GTK_ACCESSIBLE(widget),
GTK_ACCESSIBLE_PROPERTY_DESCRIPTION,
"Saves the current document to disk",
-1
);// 为组件设置正确标签
gtk_accessible_update_property(GTK_ACCESSIBLE(widget),
GTK_ACCESSIBLE_PROPERTY_LABEL, "保存更改",
-1
);
// 为复杂组件添加描述
gtk_accessible_update_property(GTK_ACCESSIBLE(widget),
GTK_ACCESSIBLE_PROPERTY_DESCRIPTION,
"将当前文档保存到磁盘",
-1
);@media (prefers-contrast: more) {
* {
border: 1px solid currentColor;
}
button {
background-color: transparent;
border: 2px solid currentColor;
}
}@media (prefers-contrast: more) {
* {
border: 1px solid currentColor;
}
button {
background-color: transparent;
border: 2px solid currentColor;
}
}// Subclass GtkApplication
struct _MyApp {
GtkApplication parent;
GSettings *settings;
};
G_DEFINE_TYPE(MyApp, my_app, GTK_TYPE_APPLICATION);
static void my_app_activate(GApplication *app) {
GtkWindow *window = gtk_application_window_new(GTK_APPLICATION(app));
// Create window content
MyWindow *my_window = my_window_new(GTK_APPLICATION(app));
gtk_window_present(GTK_WINDOW(my_window));
}// 继承GtkApplication
struct _MyApp {
GtkApplication parent;
GSettings *settings;
};
G_DEFINE_TYPE(MyApp, my_app, GTK_TYPE_APPLICATION);
static void my_app_activate(GApplication *app) {
GtkWindow *window = gtk_application_window_new(GTK_APPLICATION(app));
// 创建窗口内容
MyWindow *my_window = my_window_new(GTK_APPLICATION(app));
gtk_window_present(GTK_WINDOW(my_window));
}// Class init - load UI from resource
static void my_window_class_init(MyWindowClass *klass) {
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
gtk_widget_class_set_template_from_resource(widget_class,
"/org/example/app/ui/window.ui");
// Bind widgets
gtk_widget_class_bind_template_child(widget_class, MyWindow, header_bar);
gtk_widget_class_bind_template_child(widget_class, MyWindow, content_box);
}
// Instance init - initialize template
static void my_window_init(MyWindow *self) {
gtk_widget_init_template(GTK_WIDGET(self));
}// 类初始化 - 从资源加载UI
static void my_window_class_init(MyWindowClass *klass) {
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
gtk_widget_class_set_template_from_resource(widget_class,
"/org/example/app/ui/window.ui");
// 绑定组件
gtk_widget_class_bind_template_child(widget_class, MyWindow, header_bar);
gtk_widget_class_bind_template_child(widget_class, MyWindow, content_box);
}
// 实例初始化 - 初始化模板
static void my_window_init(MyWindow *self) {
gtk_widget_init_template(GTK_WIDGET(self));
}// Create reusable composite widgets
struct _MyCompositeWidget {
GtkBox parent;
GtkLabel *title_label;
GtkButton *action_button;
};
G_DEFINE_TYPE(MyCompositeWidget, my_composite_widget, GTK_TYPE_BOX);
static void my_composite_widget_init(MyCompositeWidget *self) {
gtk_orientable_set_orientation(GTK_ORIENTABLE(self),
GTK_ORIENTATION_VERTICAL);
gtk_box_set_spacing(GTK_BOX(self), 6);
// Create children
self->title_label = gtk_label_new(NULL);
gtk_widget_add_css_class(GTK_WIDGET(self->title_label), "title");
gtk_box_append(GTK_BOX(self), GTK_WIDGET(self->title_label));
self->action_button = gtk_button_new_with_label("Action");
gtk_box_append(GTK_BOX(self), GTK_WIDGET(self->action_button));
}// 创建可复用的复合组件
struct _MyCompositeWidget {
GtkBox parent;
GtkLabel *title_label;
GtkButton *action_button;
};
G_DEFINE_TYPE(MyCompositeWidget, my_composite_widget, GTK_TYPE_BOX);
static void my_composite_widget_init(MyCompositeWidget *self) {
gtk_orientable_set_orientation(GTK_ORIENTABLE(self),
GTK_ORIENTATION_VERTICAL);
gtk_box_set_spacing(GTK_BOX(self), 6);
// 创建子组件
self->title_label = gtk_label_new(NULL);
gtk_widget_add_css_class(GTK_WIDGET(self->title_label), "title");
gtk_box_append(GTK_BOX(self), GTK_WIDGET(self->title_label));
self->action_button = gtk_button_new_with_label("操作");
gtk_box_append(GTK_BOX(self), GTK_WIDGET(self->action_button));
}// Modern GtkListView pattern
static void setup_listitem_cb(GtkListItem *list_item, gpointer user_data) {
GtkWidget *label = gtk_label_new(NULL);
gtk_list_item_set_child(list_item, label);
}
static void bind_listitem_cb(GtkListItem *list_item, gpointer user_data) {
GObject *item = gtk_list_item_get_item(list_item);
GtkWidget *label = gtk_list_item_get_child(list_item);
const char *text = my_item_get_text(MY_ITEM(item));
gtk_label_set_text(GTK_LABEL(label), text);
}
// Create list view
GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
g_signal_connect(factory, "setup", G_CALLBACK(setup_listitem_cb), NULL);
g_signal_connect(factory, "bind", G_CALLBACK(bind_listitem_cb), NULL);
GtkSelectionModel *model = gtk_single_selection_new(G_LIST_MODEL(create_model()));
GtkWidget *listview = gtk_list_view_new(model, factory);// 现代GtkListView模式
static void setup_listitem_cb(GtkListItem *list_item, gpointer user_data) {
GtkWidget *label = gtk_label_new(NULL);
gtk_list_item_set_child(list_item, label);
}
static void bind_listitem_cb(GtkListItem *list_item, gpointer user_data) {
GObject *item = gtk_list_item_get_item(list_item);
GtkWidget *label = gtk_list_item_get_child(list_item);
const char *text = my_item_get_text(MY_ITEM(item));
gtk_label_set_text(GTK_LABEL(label), text);
}
// 创建列表视图
GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
g_signal_connect(factory, "setup", G_CALLBACK(setup_listitem_cb), NULL);
g_signal_connect(factory, "bind", G_CALLBACK(bind_listitem_cb), NULL);
GtkSelectionModel *model = gtk_single_selection_new(G_LIST_MODEL(create_model()));
GtkWidget *listview = gtk_list_view_new(model, factory);// Define action entries
static GActionEntry app_entries[] = {
{ "quit", on_quit, NULL, NULL },
{ "preferences", on_preferences, NULL, NULL },
{ "about", on_about, NULL, NULL }
};
// Add actions in startup
static void on_startup(GApplication *app) {
g_action_map_add_action_entries(G_ACTION_MAP(app),
app_entries,
G_N_ELEMENTS(app_entries),
app);
// Set accelerators
const char *quit_accels[] = { "<Control>q", NULL };
gtk_application_set_accels_for_action(GTK_APPLICATION(app),
"app.quit",
quit_accels);
}// 定义操作条目
static GActionEntry app_entries[] = {
{ "quit", on_quit, NULL, NULL },
{ "preferences", on_preferences, NULL, NULL },
{ "about", on_about, NULL, NULL }
};
// 在启动时添加操作
static void on_startup(GApplication *app) {
g_action_map_add_action_entries(G_ACTION_MAP(app),
app_entries,
G_N_ELEMENTS(app_entries),
app);
// 设置快捷键
const char *quit_accels[] = { "<Control>q", NULL };
gtk_application_set_accels_for_action(GTK_APPLICATION(app),
"app.quit",
quit_accels);
}<!-- Define menu in .ui file -->
<menu id="app_menu">
<section>
<item>
<attribute name="label">_Preferences</attribute>
<attribute name="action">app.preferences</attribute>
<attribute name="verb-icon">preferences-system-symbolic</attribute>
</item>
</section>
<section>
<item>
<attribute name="label">_About</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
</menu><!-- 在.ui文件中定义菜单 -->
<menu id="app_menu">
<section>
<item>
<attribute name="label">_偏好设置</attribute>
<attribute name="action">app.preferences</attribute>
<attribute name="verb-icon">preferences-system-symbolic</attribute>
</item>
</section>
<section>
<item>
<attribute name="label">_关于</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
</menu>// Create settings
GSettings *settings = g_settings_new("org.example.app");
// Bind to widget properties
g_settings_bind(settings, "window-width",
window, "default-width",
G_SETTINGS_BIND_DEFAULT);
// Watch for changes
g_signal_connect(settings, "changed::theme",
G_CALLBACK(on_theme_changed), NULL);// 创建设置实例
GSettings *settings = g_settings_new("org.example.app");
// 将设置绑定到组件属性
g_settings_bind(settings, "window-width",
window, "default-width",
G_SETTINGS_BIND_DEFAULT);
// 监听设置变化
g_signal_connect(settings, "changed::theme",
G_CALLBACK(on_theme_changed), NULL);// Bidirectional binding between widgets
g_object_bind_property(
entry, "text",
label, "label",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE
);
// Transform bindings with transform functions
g_object_bind_property_full(
slider, "value",
label, "label",
G_BINDING_DEFAULT,
slider_to_label_transform,
label_to_slider_transform,
NULL, NULL
);// 组件间双向绑定
g_object_bind_property(
entry, "text",
label, "label",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE
);
// 使用转换函数实现转换绑定
g_object_bind_property_full(
slider, "value",
label, "label",
G_BINDING_DEFAULT,
slider_to_label_transform,
label_to_slider_transform,
NULL, NULL
);// Use event controllers instead of signals
GtkEventController *key_controller = gtk_event_controller_key_new();
gtk_widget_add_controller(widget, key_controller);
g_signal_connect(key_controller, "key-pressed",
G_CALLBACK(on_key_pressed), self);// 使用事件控制器替代传统信号
GtkEventController *key_controller = gtk_event_controller_key_new();
gtk_widget_add_controller(widget, key_controller);
g_signal_connect(key_controller, "key-pressed",
G_CALLBACK(on_key_pressed), self);// Click gesture
GtkGesture *click = gtk_gesture_click_new();
g_signal_connect(click, "pressed", G_CALLBACK(on_click_pressed), widget);
gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(click));
// Drag gesture
GtkGesture *drag = gtk_gesture_drag_new();
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(drag), GDK_BUTTON_PRIMARY);
g_signal_connect(drag, "drag-begin", G_CALLBACK(on_drag_begin), NULL);
g_signal_connect(drag, "drag-update", G_CALLBACK(on_drag_update), NULL);
gtk_widget_add_controller(drawing_area, GTK_EVENT_CONTROLLER(drag));// 点击手势
GtkGesture *click = gtk_gesture_click_new();
g_signal_connect(click, "pressed", G_CALLBACK(on_click_pressed), widget);
gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(click));
// 拖拽手势
GtkGesture *drag = gtk_gesture_drag_new();
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(drag), GDK_BUTTON_PRIMARY);
g_signal_connect(drag, "drag-begin", G_CALLBACK(on_drag_begin), NULL);
g_signal_connect(drag, "drag-update", G_CALLBACK(on_drag_update), NULL);
gtk_widget_add_controller(drawing_area, GTK_EVENT_CONTROLLER(drag));GtkWidget *child = gtk_button_new_with_label("Click");
gtk_box_append(GTK_BOX(box), child);
g_object_unref(child); // DANGER: May leak or crashGtkWidget *child = gtk_button_new_with_label("点击");
gtk_box_append(GTK_BOX(box), child);
g_object_unref(child); // 危险:可能导致内存泄漏或崩溃GtkWidget *child = gtk_button_new_with_label("Click");
gtk_box_append(GTK_BOX(box), child);
// Box takes ownership - no unref neededGtkWidget *child = gtk_button_new_with_label("点击");
gtk_box_append(GTK_BOX(box), child);
// 容器会接管所有权 - 无需手动释放static void my_widget_init(MyWidget *self) {
g_signal_connect(self->button, "clicked",
G_CALLBACK(on_clicked), self);
}
// Never disconnects - memory leak!static void my_widget_init(MyWidget *self) {
g_signal_connect(self->button, "clicked",
G_CALLBACK(on_clicked), self);
}
// 从未断开连接 - 内存泄漏!static void my_widget_dispose(GObject *object) {
MyWidget *self = MY_WIDGET(object);
g_clear_signal_handler(&self->button_clicked_id, self->button);
G_OBJECT_CLASS(my_widget_parent_class)->dispose(object);
}static void my_widget_dispose(GObject *object) {
MyWidget *self = MY_WIDGET(object);
g_clear_signal_handler(&self->button_clicked_id, self->button);
G_OBJECT_CLASS(my_widget_parent_class)->dispose(object);
}g_signal_connect(widget, "key-press-event",
G_CALLBACK(old_handler), NULL); // GTK3 patterng_signal_connect(widget, "key-press-event",
G_CALLBACK(old_handler), NULL); // GTK3模式GtkEventController *controller = gtk_event_controller_key_new();
gtk_widget_add_controller(widget, controller);
g_signal_connect(controller, "key-pressed",
G_CALLBACK(modern_handler), NULL);GtkEventController *controller = gtk_event_controller_key_new();
gtk_widget_add_controller(widget, controller);
g_signal_connect(controller, "key-pressed",
G_CALLBACK(modern_handler), NULL);GtkWidget *window = gtk_window_new(); // GTK3
GtkApplicationWindow *app_win = gtk_application_window_new(app); // GTK4GtkWidget *window = gtk_window_new(); // GTK3
GtkApplicationWindow *app_win = gtk_application_window_new(app); // GTK4GtkWidget *app_win = gtk_application_window_new(app);GtkWidget *app_win = gtk_application_window_new(app);void on_data_changed(void) {
gtk_widget_queue_draw(widget); // Triggers full redraw
}void on_data_changed(void) {
gtk_widget_queue_draw(widget); // 触发完整重绘
}void on_data_changed(void) {
gtk_widget_notify(widget, "content"); // More efficient
}void on_data_changed(void) {
gtk_widget_notify(widget, "content"); // 更高效
}void update_list(void) {
gtk_list_view_set_model(listview, create_new_model()); // Slow
}void update_list(void) {
gtk_list_view_set_model(listview, create_new_model()); // 缓慢
}void update_list(void) {
GListStore *store = get_current_store();
g_list_store_remove(store, old_item);
g_list_store_append(store, new_item); // Fast
}void update_list(void) {
GListStore *store = get_current_store();
g_list_store_remove(store, old_item);
g_list_store_append(store, new_item); // 快速
}references/gnome-hig.mdgtk4-best-practices.mdlibadwaita-styling.mdaccessibility.mdreferences/gnome-hig.mdgtk4-best-practices.mdlibadwaita-styling.mdaccessibility.md// UI resource (window.ui)
<interface>
<template class="MyWindow" parent="AdwApplicationWindow">
<property name="default-width">800</property>
<property name="default-height">600</property>
<child>
<object class="AdwBreakpoint">
<condition>max-width: 600sp</condition>
</object>
</child>
<property name="content">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar">
<property name="title-widget">
<object class="AdwViewSwitcherTitle">
<property name="stack">view_stack</property>
</object>
</property>
</object>
</child>
<property name="content">
<object class="GtkStack" id="view_stack">
<!-- Stack children added here -->
</object>
</property>
</object>
</property>
</template>
</interface>// C implementation
G_DEFINE_TYPE(MyWindow, my_window, ADW_TYPE_APPLICATION_WINDOW);
static void my_window_class_init(MyWindowClass *klass) {
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
gtk_widget_class_set_template_from_resource(widget_class,
"/org/example/app/ui/window.ui");
}
static void my_window_init(MyWindow *self) {
gtk_widget_init_template(GTK_WIDGET(self));
// Load custom CSS
GtkCssProvider *provider = gtk_css_provider_new();
gtk_css_provider_load_from_resource(provider,
"/org/example/app/styles/style.css");
gtk_style_context_add_provider_for_display(
gdk_display_get_default(),
GTK_STYLE_PROVIDER(provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
);
}/* Custom styling (style.css) */
window {
background-color: var(--window-bg-color);
}
.title {
font-weight: 700;
font-size: 24pt;
}
.primary-button {
background-color: var(--accent-bg-color);
color: var(--accent-fg-color);
}
.primary-button:hover {
/* GTK4: Use color-mix() instead of filter: brightness() */
background-color: color-mix(in srgb, var(--accent-bg-color) 90%, white);
}// UI资源文件(window.ui)
<interface>
<template class="MyWindow" parent="AdwApplicationWindow">
<property name="default-width">800</property>
<property name="default-height">600</property>
<child>
<object class="AdwBreakpoint">
<condition>max-width: 600sp</condition>
</object>
</child>
<property name="content">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar">
<property name="title-widget">
<object class="AdwViewSwitcherTitle">
<property name="stack">view_stack</property>
</object>
</property>
</object>
</child>
<property name="content">
<object class="GtkStack" id="view_stack">
<!-- 在此添加栈子组件 -->
</object>
</property>
</object>
</property>
</template>
</interface>// C语言实现
G_DEFINE_TYPE(MyWindow, my_window, ADW_TYPE_APPLICATION_WINDOW);
static void my_window_class_init(MyWindowClass *klass) {
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
gtk_widget_class_set_template_from_resource(widget_class,
"/org/example/app/ui/window.ui");
}
static void my_window_init(MyWindow *self) {
gtk_widget_init_template(GTK_WIDGET(self));
// 加载自定义CSS
GtkCssProvider *provider = gtk_css_provider_new();
gtk_css_provider_load_from_resource(provider,
"/org/example/app/styles/style.css");
gtk_style_context_add_provider_for_display(
gdk_display_get_default(),
GTK_STYLE_PROVIDER(provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
);
}/* 自定义样式(style.css) */
window {
background-color: var(--window-bg-color);
}
.title {
font-weight: 700;
font-size: 24pt;
}
.primary-button {
background-color: var(--accent-bg-color);
color: var(--accent-fg-color);
}
.primary-button:hover {
/* GTK4:使用color-mix()替代filter: brightness() */
background-color: color-mix(in srgb, var(--accent-bg-color) 90%, white);
}