mate-notification-daemon/0001-features-add-new-kiran-themes-in-mate-notification-p-507a6bf0.patch
2022-08-04 10:31:11 +08:00

1268 lines
37 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 507a6bf07ab39523df276a51a8b44ec8f9a235bd Mon Sep 17 00:00:00 2001
From: yuanxing <yuanxing@kylinos.com.cn>
Date: Fri, 22 Jan 2021 10:33:30 +0800
Subject: [PATCH 1/9] features: add new kiran themes in
mate-notification-properties
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 添加新的kiran消息框主题
Realated #33420
---
configure.ac | 1 +
po/POTFILES.in | 1 +
po/zh_CN.po | 13 +
src/capplet/mate-notification-properties.c | 4 +
src/daemon/daemon.c | 2 +-
src/themes/Makefile.am | 2 +-
src/themes/kiran/Makefile.am | 28 +
src/themes/kiran/data/icons/close_hover.svg | 16 +
src/themes/kiran/data/icons/close_normal.svg | 11 +
src/themes/kiran/data/icons/close_press.svg | 16 +
src/themes/kiran/data/kiran.css | 91 ++
src/themes/kiran/kiran.c | 934 +++++++++++++++++++
src/themes/kiran/kiran.gresource.xml | 9 +
13 files changed, 1126 insertions(+), 2 deletions(-)
create mode 100644 src/themes/kiran/Makefile.am
create mode 100644 src/themes/kiran/data/icons/close_hover.svg
create mode 100644 src/themes/kiran/data/icons/close_normal.svg
create mode 100644 src/themes/kiran/data/icons/close_press.svg
create mode 100644 src/themes/kiran/data/kiran.css
create mode 100644 src/themes/kiran/kiran.c
create mode 100644 src/themes/kiran/kiran.gresource.xml
diff --git a/configure.ac b/configure.ac
index a43ad19..dea982e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -249,6 +249,7 @@ src/themes/coco/Makefile
src/themes/nodoka/Makefile
src/themes/slider/Makefile
src/themes/standard/Makefile
+src/themes/kiran/Makefile
])
AC_OUTPUT
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 64a83b1..e3f7c90 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -8,3 +8,4 @@ src/themes/coco/coco-theme.c
src/themes/nodoka/nodoka-theme.c
src/themes/slider/theme.c
src/themes/standard/theme.c
+src/themes/kiran/kiran.c
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 294734f..e2f2551 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -187,3 +187,16 @@ msgstr "通知主体文本"
#: ../src/themes/standard/theme.c:752
msgid "Closes the notification."
msgstr "关闭通知"
+
+
+#: ../src/themes/kiran/kiran.c
+msgid "Normal Notification"
+msgstr "一般信息通知"
+
+#: ../src/themes/kiran/kiran.c
+msgid "Low Notification"
+msgstr "低优先级通知"
+
+#: ../src/themes/kiran/kiran.c
+msgid "Critical Notification"
+msgstr "重要通知"
\ No newline at end of file
diff --git a/src/capplet/mate-notification-properties.c b/src/capplet/mate-notification-properties.c
index 2f5b103..09b6643 100644
--- a/src/capplet/mate-notification-properties.c
+++ b/src/capplet/mate-notification-properties.c
@@ -340,6 +340,10 @@ static void notification_properties_dialog_setup_themes(NotificationAppletDialog
{
theme_label = g_strdup(_("Standard theme"));
}
+ else if (g_str_equal(theme_name, "kiran"))
+ {
+ theme_label = g_strdup(_("Kiran"));
+ }
else
{
theme_label = g_strdup(theme_name);
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index c418809..3ee2266 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -1352,8 +1352,8 @@ static gboolean notify_daemon_notify_handler(NotifyDaemonNotifications *object,
theme_clear_notification_actions (nw);
}
- theme_set_notification_text (nw, summary, body);
theme_set_notification_hints (nw, hints);
+ theme_set_notification_text (nw, summary, body);
/*
*XXX This needs to handle file URIs and all that.
diff --git a/src/themes/Makefile.am b/src/themes/Makefile.am
index 160000b..99df82a 100644
--- a/src/themes/Makefile.am
+++ b/src/themes/Makefile.am
@@ -1,3 +1,3 @@
-SUBDIRS = coco nodoka slider standard
+SUBDIRS = coco nodoka slider standard kiran
-include $(top_srcdir)/git.mk
diff --git a/src/themes/kiran/Makefile.am b/src/themes/kiran/Makefile.am
new file mode 100644
index 0000000..fcb1626
--- /dev/null
+++ b/src/themes/kiran/Makefile.am
@@ -0,0 +1,28 @@
+NULL =
+
+enginedir = $(libdir)/mate-notification-daemon/engines
+engine_LTLIBRARIES = libkiran.la
+
+RESOURCE_XML=kiran.gresource.xml
+GLIB_COMPILE_RESOURCE=glib-compile-resources
+
+AM_CPPFLAGS = $(THEME_CFLAGS)
+
+gresource.c: $(RESOURCE_XML)
+ $(GLIB_COMPILE_RESOURCE) --target $@ $< --generate --c-name kiran
+
+gresource.h: $(RESOURCE_XML)
+ $(GLIB_COMPILE_RESOURCE) --target $@ $< --generate --c-name kiran
+
+libkiran_la_SOURCES = kiran.c gresource.c gresource.h
+
+libkiran_la_LDFLAGS = -module -avoid-version -no-undefined
+libkiran_la_LIBADD = \
+ $(THEME_LIBS) \
+ $(NULL)
+
+-include $(top_srcdir)/git.mk
+
+.PHONY :clean
+clean:
+ rm -f gresource.c gresource.h
\ No newline at end of file
diff --git a/src/themes/kiran/data/icons/close_hover.svg b/src/themes/kiran/data/icons/close_hover.svg
new file mode 100644
index 0000000..1edd094
--- /dev/null
+++ b/src/themes/kiran/data/icons/close_hover.svg
@@ -0,0 +1,16 @@
+<svg id="close_s" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+ <defs>
+ <style>
+ .cls-1 {
+ fill: #ea4565;
+ }
+
+ .cls-2 {
+ fill: #fff;
+ fill-rule: evenodd;
+ }
+ </style>
+ </defs>
+ <rect id="矩形_705" data-name="矩形 705" class="cls-1" width="16" height="16"/>
+ <path id="关闭" class="cls-2" d="M1181.99,1090.16l-0.83.83-4.16-4.16-4.16,4.16-0.83-.83,4.16-4.16-4.16-4.16,0.83-.83,4.16,4.16,4.16-4.16,0.83,0.83-4.16,4.16Z" transform="translate(-1169 -1078)"/>
+</svg>
diff --git a/src/themes/kiran/data/icons/close_normal.svg b/src/themes/kiran/data/icons/close_normal.svg
new file mode 100644
index 0000000..5b94a31
--- /dev/null
+++ b/src/themes/kiran/data/icons/close_normal.svg
@@ -0,0 +1,11 @@
+<svg id="close_n" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+ <defs>
+ <style>
+ .cls-1 {
+ fill: #fff;
+ fill-rule: evenodd;
+ }
+ </style>
+ </defs>
+ <path id="关闭" class="cls-1" d="M1181.99,1090.16l-0.83.83-4.16-4.16-4.16,4.16-0.83-.83,4.16-4.16-4.16-4.16,0.83-.83,4.16,4.16,4.16-4.16,0.83,0.83-4.16,4.16Z" transform="translate(-1169 -1078)"/>
+</svg>
diff --git a/src/themes/kiran/data/icons/close_press.svg b/src/themes/kiran/data/icons/close_press.svg
new file mode 100644
index 0000000..7a75734
--- /dev/null
+++ b/src/themes/kiran/data/icons/close_press.svg
@@ -0,0 +1,16 @@
+<svg id="close_pre" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+ <defs>
+ <style>
+ .cls-1 {
+ fill: #b8354f;
+ }
+
+ .cls-2 {
+ fill: #fff;
+ fill-rule: evenodd;
+ }
+ </style>
+ </defs>
+ <rect id="矩形_705" data-name="矩形 705" class="cls-1" width="16" height="16"/>
+ <path id="关闭" class="cls-2" d="M1181.99,1090.16l-0.83.83-4.16-4.16-4.16,4.16-0.83-.83,4.16-4.16-4.16-4.16,0.83-.83,4.16,4.16,4.16-4.16,0.83,0.83-4.16,4.16Z" transform="translate(-1169 -1078)"/>
+</svg>
diff --git a/src/themes/kiran/data/kiran.css b/src/themes/kiran/data/kiran.css
new file mode 100644
index 0000000..2f9123e
--- /dev/null
+++ b/src/themes/kiran/data/kiran.css
@@ -0,0 +1,91 @@
+/******************Label******************************/
+#summary_label
+{
+ color:#ffffff;
+ font-size:14px;
+ font-family: "Noto Sans CJK SC regular";
+ padding-bottom: 8px;
+}
+
+#body_label
+{
+ color: #919191;
+ font-size: 12px;
+ font-family: "Noto Sans CJK SC regular";
+ line-height12px;
+}
+
+#actions_label
+{
+ color: #3197de;
+ font-size: 12px;
+ font-family: "PingFang SC Medium";
+}
+
+
+/*********************Button****************************/
+
+#actions_button,#actions_hbox
+{
+ padding:0px;
+ box-shadow:none;
+ margin:0px;
+}
+
+#actions_button:hover
+{
+ border-bottom:1px solid #3197DE;
+}
+
+#close_button
+{
+ background-image: url("/kiran/themes/close_normal");
+ background-repeat: no-repeat;
+ background-position: center;
+ background-color: transparent;
+ padding: 0px;
+ border: none;
+ margin: 0px;
+ box-shadow: 0px;
+}
+
+#close_button:hover
+{
+ background-image: url("/kiran/themes/close_hover");
+ background-repeat: no-repeat;
+ background-position: center;
+}
+
+#close_button:active
+{
+ background-image: url("/kiran/themes/close_press");
+ background-repeat: no-repeat;
+ background-position: center;
+}
+
+/***********************Box***********************/
+#main_hbox , #main_vbox
+{
+ margin: 0px;
+ padding: 0px;
+ box-shadow: 0px;
+}
+
+#main_hbox
+{
+ /* background-color: yellow; */
+ margin-right: 14px;
+ margin-bottom: 12px;
+}
+
+#icon_box
+{
+ margin-left: 12px;
+ margin-top: 12px;
+ margin-right: 12px;
+}
+
+#text_vbox ,#action_vbox
+{
+ margin-top: 16px;
+}
diff --git a/src/themes/kiran/kiran.c b/src/themes/kiran/kiran.c
new file mode 100644
index 0000000..9181e20
--- /dev/null
+++ b/src/themes/kiran/kiran.c
@@ -0,0 +1,934 @@
+/*
+ * kiran.c
+ * This file is part of notification-daemon-engine-kiran
+ *
+ * Copyright (C) 2012 - Stefano Karapetsas <stefano@karapetsas.com>
+ * Copyright (C) 2010 - Eduardo Grajeda
+ * Copyright (C) 2008 - Martin Sourada
+ *
+ * notification-daemon-engine-kiran is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * notification-daemon-engine-kiran is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with notification-daemon-engine-kiran; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gtk/gtkx.h>
+#include <gmodule.h>
+#include "gresource.h"
+
+/* Define basic kiran types */
+typedef void (*ActionInvokedCb)(GtkWindow *nw, const char *key);
+typedef void (*UrlClickedCb)(GtkWindow *nw, const char *url);
+
+typedef struct
+{
+ GtkWidget *win;
+ GtkWidget *top_spacer;
+ GtkWidget *bottom_spacer;
+ GtkWidget *main_hbox;
+ GtkWidget *iconbox;
+ GtkWidget *icon;
+ GtkWidget *close_button;
+ GtkWidget *summary_label;
+ GtkWidget *body_label;
+ GtkWidget *actions_box;
+ GtkWidget *last_sep;
+ GtkWidget *stripe_spacer;
+ GtkWidget *pie_countdown;
+
+ gboolean composited;
+ gboolean action_icons;
+
+ int width;
+ int height;
+ int last_width;
+ int last_height;
+
+ guchar urgency;
+ glong timeout;
+ glong remaining;
+
+ UrlClickedCb url_clicked;
+
+ GtkTextDirection rtl;
+} WindowData;
+
+
+enum
+{
+ URGENCY_LOW,
+ URGENCY_NORMAL,
+ URGENCY_CRITICAL
+};
+
+gboolean theme_check_init(unsigned int major_ver, unsigned int minor_ver,
+ unsigned int micro_ver);
+void get_theme_info(char **theme_name, char **theme_ver, char **author,
+ char **homepage);
+GtkWindow* create_notification(UrlClickedCb url_clicked);
+void set_notification_text(GtkWindow *nw, const char *summary,
+ const char *body);
+void set_notification_icon(GtkWindow *nw, GdkPixbuf *pixbuf);
+void set_notification_arrow(GtkWidget *nw, gboolean visible, int x, int y);
+void add_notification_action(GtkWindow *nw, const char *text, const char *key,
+ ActionInvokedCb cb);
+void clear_notification_actions(GtkWindow *nw);
+void move_notification(GtkWidget *nw, int x, int y);
+void set_notification_timeout(GtkWindow *nw, glong timeout);
+void set_notification_hints(GtkWindow *nw, GVariant *hints);
+void notification_tick(GtkWindow *nw, glong remaining);
+
+#define STRIPE_WIDTH 32
+#define WIDTH 270
+#define IMAGE_SIZE 32
+#define IMAGE_PADDING 10
+#define SPACER_LEFT 30
+#define PIE_RADIUS 7
+#define PIE_WIDTH (2 * PIE_RADIUS)
+#define PIE_HEIGHT (2 * PIE_RADIUS)
+#define BODY_X_OFFSET (IMAGE_SIZE + 8)
+#define DEFAULT_ARROW_OFFSET (SPACER_LEFT + 12)
+#define DEFAULT_ARROW_HEIGHT 14
+#define DEFAULT_ARROW_WIDTH 22
+#define DEFAULT_ARROW_SKEW -6
+#define BACKGROUND_OPACITY 1.0
+#define GRADIENT_CENTER 0.7
+
+/* Support Nodoka Functions */
+
+/* Handle clicking on link */
+static gboolean
+activate_link (GtkLabel *label, const char *url, WindowData *windata)
+{
+ windata->url_clicked (GTK_WINDOW (windata->win), url);
+ return TRUE;
+}
+
+static void
+destroy_windata(WindowData *windata)
+{
+ g_free(windata);
+}
+
+/* Draw fuctions */
+/* Standard rounded rectangle */
+static void
+nodoka_rounded_rectangle (cairo_t * cr,
+ double x, double y, double w, double h,
+ int radius)
+{
+ cairo_move_to (cr, x + radius, y);
+ cairo_arc (cr, x + w - radius, y + radius, radius, G_PI * 1.5, G_PI * 2);
+ cairo_arc (cr, x + w - radius, y + h - radius, radius, 0, G_PI * 0.5);
+ cairo_arc (cr, x + radius, y + h - radius, radius, G_PI * 0.5, G_PI);
+ cairo_arc (cr, x + radius, y + radius, radius, G_PI, G_PI * 1.5);
+}
+
+/* Fill background */
+static void
+fill_background(GtkWidget *widget, WindowData *windata, cairo_t *cr)
+{
+ float alpha;
+ if (windata->composited)
+ alpha = BACKGROUND_OPACITY;
+ else
+ alpha = 1.0;
+
+ cairo_pattern_t *pattern;
+ pattern = cairo_pattern_create_linear (0, 0, 0, windata->height);
+ cairo_pattern_add_color_stop_rgba (pattern, 0,
+ 34/255.0, 34/255.0, 34/255.0, alpha);
+ cairo_pattern_add_color_stop_rgba (pattern, GRADIENT_CENTER,
+ 34/255.0, 34/255.0, 34/255.0, alpha);
+ cairo_pattern_add_color_stop_rgba (pattern, 1,
+ 34/255.0, 34/255.0, 34/255.0, alpha);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+
+ nodoka_rounded_rectangle (cr, 0, 0, windata->width,
+ windata->height, 6);
+
+ cairo_fill (cr);
+}
+
+
+/**
+ * @brief 当鼠标进入消息框窗体时,重绘背景
+ */
+static void
+fill_background_when_pointer_enter(GtkWidget *widget, WindowData *windata, cairo_t *cr)
+{
+ float alpha;
+ if (windata->composited)
+ alpha = BACKGROUND_OPACITY;
+ else
+ alpha = 1.0;
+
+ cairo_pattern_t *pattern;
+ pattern = cairo_pattern_create_linear (0, 0, 0, windata->height);
+ cairo_pattern_add_color_stop_rgba (pattern, 0,
+ 51/255.0, 51/255.0, 51/255.0, alpha);
+ cairo_pattern_add_color_stop_rgba (pattern, GRADIENT_CENTER,
+ 51/255.0, 51/255.0, 51/255.0, alpha);
+ cairo_pattern_add_color_stop_rgba (pattern, 1,
+ 51/255.0, 51/255.0, 51/255.0, alpha);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+
+ nodoka_rounded_rectangle (cr, 0, 0, windata->width,
+ windata->height, 8);
+
+ cairo_fill (cr);
+}
+
+static void
+draw_pie(GtkWidget *pie, WindowData *windata, cairo_t *cr)
+{
+ if (windata->timeout == 0)
+ return;
+
+ gdouble arc_angle = 1.0 - (gdouble)windata->remaining / (gdouble)windata->timeout;
+ cairo_set_source_rgba (cr, 92/255.0, 92/255.0, 92/255.0, 1);
+ cairo_move_to(cr, PIE_RADIUS, PIE_RADIUS);
+ cairo_arc_negative(cr, PIE_RADIUS, PIE_RADIUS, PIE_RADIUS,
+ -G_PI/2, (-0.25 + arc_angle)*2*G_PI);
+ cairo_line_to(cr, PIE_RADIUS, PIE_RADIUS);
+
+ cairo_fill (cr);
+}
+
+static void
+update_shape_region (cairo_surface_t *surface,
+ WindowData *windata)
+{
+ if (windata->width == windata->last_width && windata->height == windata->last_height)
+ {
+ return;
+ }
+
+ if (windata->width == 0 || windata->height == 0)
+ {
+ GtkAllocation allocation;
+ gtk_widget_get_allocation (windata->win, &allocation);
+
+ windata->width = MAX (allocation.width, 1);
+ windata->height = MAX (allocation.height, 1);
+ }
+
+ if (!windata->composited) {
+ cairo_region_t *region;
+
+ region = gdk_cairo_region_create_from_surface (surface);
+ gtk_widget_shape_combine_region (windata->win, region);
+ cairo_region_destroy (region);
+ } else {
+ gtk_widget_shape_combine_region (windata->win, NULL);
+ return;
+ }
+
+ windata->last_width = windata->width;
+ windata->last_height = windata->height;
+}
+
+static void
+paint_window (GtkWidget *widget,
+ cairo_t *cr,
+ WindowData *windata)
+{
+ cairo_surface_t *surface;
+ cairo_t *cr2;
+
+ if (windata->width == 0 || windata->height == 0) {
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation(windata->win, &allocation);
+ windata->width = allocation.width;
+ windata->height = allocation.height;
+ }
+
+ surface = cairo_surface_create_similar(cairo_get_target(cr),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ windata->width,
+ windata->height);
+
+ cr2 = cairo_create (surface);
+ fill_background(widget, windata, cr2);
+ cairo_fill (cr2);
+
+ cairo_destroy (cr2);
+
+ cairo_save (cr);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+ cairo_restore (cr);
+
+ update_shape_region (surface, windata);
+
+ cairo_surface_destroy (surface);
+}
+
+/**
+ * @brief 当鼠标进入消息框窗体时,给窗体加上边框
+ */
+static void
+paint_window_when_pointer_enter(GtkWidget *widget,
+ cairo_t *cr,
+ WindowData *windata)
+{
+ cairo_surface_t *surface;
+ cairo_t *cr2;
+
+ if (windata->width == 0 || windata->height == 0) {
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation(windata->win, &allocation);
+ windata->width = allocation.width;
+ windata->height = allocation.height;
+ }
+
+ surface = cairo_surface_create_similar(cairo_get_target(cr),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ windata->width,
+ windata->height);
+
+ cr2 = cairo_create (surface);
+
+ fill_background_when_pointer_enter(widget, windata, cr2);
+ cairo_fill (cr2);
+
+ nodoka_rounded_rectangle (cr2, 0, 0, windata->width , windata->height, 8);
+ cairo_set_source_rgba (cr2, 40/255.0, 144/255.0, 216/255.0, 1.0);
+ cairo_set_line_width (cr2, 4.0);
+ cairo_stroke (cr2);
+
+ cairo_destroy (cr2);
+
+ cairo_save (cr);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+ cairo_restore (cr);
+
+ update_shape_region (surface, windata);
+
+ cairo_surface_destroy (surface);
+
+}
+
+/* Event handlers */
+/**
+ * @brief "draw"回调函数:根据窗体当前状态,判断绘制成鼠标移入样式
+ */
+static gboolean
+on_draw (GtkWidget *widget, cairo_t *cr, WindowData *windata)
+{
+ GtkStateFlags flags = gtk_widget_get_state_flags(windata->win);
+ if (flags & GTK_STATE_FLAG_PRELIGHT)
+ {
+ paint_window_when_pointer_enter(widget , cr , windata);
+ }
+ else
+ {
+ paint_window (widget, cr, windata);
+ }
+ return FALSE;
+}
+
+static gboolean
+configure_event_cb(GtkWidget *nw,
+ GdkEventConfigure *event,
+ WindowData *windata)
+{
+ windata->width = event->width;
+ windata->height = event->height;
+
+ gtk_widget_queue_draw(nw);
+
+ return FALSE;
+}
+
+static gboolean
+countdown_expose_cb(GtkWidget *pie,
+ cairo_t *cr,
+ WindowData *windata)
+{
+ cairo_t *cr2;
+ cairo_surface_t *surface;
+ GtkAllocation alloc;
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+
+ gtk_widget_get_allocation (pie, &alloc);
+
+ surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ alloc.width,
+ alloc.height);
+
+ cr2 = cairo_create (surface);
+
+ cairo_translate (cr2, -alloc.x, -alloc.y);
+
+ GtkStateFlags flags = gtk_widget_get_state_flags(windata->win);
+ if (flags & GTK_STATE_FLAG_PRELIGHT)
+ {
+ fill_background_when_pointer_enter(pie, windata ,cr2);
+ }
+ else
+ {
+ fill_background (pie, windata, cr2);
+ }
+ cairo_translate (cr2, alloc.x, alloc.y);
+ draw_pie (pie, windata, cr2);
+ cairo_fill (cr2);
+
+ cairo_destroy (cr2);
+
+ cairo_save (cr);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+ cairo_restore (cr);
+
+ cairo_surface_destroy (surface);
+ return TRUE;
+}
+
+static gboolean on_configure_event (GtkWidget* widget, GdkEventConfigure* event, WindowData* windata)
+{
+ windata->width = event->width;
+ windata->height = event->height;
+
+ gtk_widget_queue_draw (widget);
+
+ return FALSE;
+}
+
+static void on_composited_changed (GtkWidget* window, WindowData* windata)
+{
+ windata->composited = gdk_screen_is_composited (gtk_widget_get_screen(window));
+
+ gtk_widget_queue_draw (window);
+}
+
+
+/**
+ * @brief 事件过滤:当鼠标移入或者离开消息框,绘制相应的消息框状态
+ */
+GdkFilterReturn event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer userdata)
+{
+ XEvent *x_event = (XEvent*)xevent;
+ XGenericEvent *general_event = (XGenericEvent*)x_event;
+ GtkWidget *window = GTK_WIDGET(userdata);
+
+ switch(x_event->type) {
+ case EnterNotify:
+ gtk_widget_set_state_flags(window, GTK_STATE_FLAG_PRELIGHT, FALSE);
+ gtk_widget_queue_draw(window);
+ break;
+ case LeaveNotify:
+ gtk_widget_set_state_flags(window, gtk_widget_get_state_flags(window) & ~GTK_STATE_FLAG_PRELIGHT, TRUE);
+ gtk_widget_queue_draw(window);
+ break;
+ case GenericEvent:
+ do
+ {
+ if (general_event->evtype == EnterNotify) {
+ gtk_widget_set_state_flags(window, GTK_STATE_FLAG_PRELIGHT, FALSE);
+ gtk_widget_queue_draw(window);
+ }
+
+ if (general_event->evtype == LeaveNotify) {
+ gtk_widget_set_state_flags(window, gtk_widget_get_state_flags(window) & ~GTK_STATE_FLAG_PRELIGHT, TRUE);
+ gtk_widget_queue_draw(window);
+ }
+ }while(0);
+ break;
+ default:
+ break;
+ }
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+on_realize(GtkWidget *widget , gpointer userdata )
+{
+ GdkWindow *window = gtk_widget_get_window(widget);
+ gdk_window_add_filter(window, event_filter, widget);
+}
+
+
+static void
+action_clicked_cb(GtkWidget *w, GdkEventButton *event,
+ ActionInvokedCb action_cb)
+{
+ GtkWindow *nw = g_object_get_data(G_OBJECT(w), "_nw");
+ const char *key = g_object_get_data(G_OBJECT(w), "_action_key");
+
+ action_cb(nw, key);
+}
+
+/* Required functions */
+
+/* Checking if we support this notification daemon version */
+gboolean
+theme_check_init(unsigned int major_ver, unsigned int minor_ver,
+ unsigned int micro_ver)
+{
+ return major_ver == NOTIFICATION_DAEMON_MAJOR_VERSION && minor_ver == NOTIFICATION_DAEMON_MINOR_VERSION && micro_ver == NOTIFICATION_DAEMON_MICRO_VERSION;
+}
+
+/* Sending theme info to the notification daemon */
+void
+get_theme_info(char **theme_name,
+ char **theme_ver,
+ char **author,
+ char **homepage)
+{
+ *theme_name = g_strdup("Kiran");
+ *theme_ver = g_strdup_printf("%d.%d.%d", NOTIFICATION_DAEMON_MAJOR_VERSION,
+ NOTIFICATION_DAEMON_MINOR_VERSION,
+ NOTIFICATION_DAEMON_MICRO_VERSION);
+ *author = g_strdup("Eduardo Grajeda");
+ *homepage = g_strdup("http://github.com/tatofoo/");
+}
+
+/* set css*/
+static void
+set_css(GtkWidget* widget)
+{
+ GtkCssProvider *provider = gtk_css_provider_new ();
+
+ gtk_css_provider_load_from_resource (provider, "/kiran/themes/kiran.css");
+ gtk_style_context_add_provider_for_screen (gtk_widget_get_screen(widget),
+ GTK_STYLE_PROVIDER(provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+ gtk_style_context_reset_widgets(gtk_widget_get_screen(widget));
+
+ g_object_unref (provider);
+}
+
+
+/* Create new notification */
+GtkWindow *
+create_notification(UrlClickedCb url_clicked)
+{
+ GtkWidget *win;
+ GtkWidget *main_vbox;
+ GtkWidget* close_button;
+ GtkWidget* action_vbox;
+ GtkWidget *vbox;
+ AtkObject *atkobj;
+ WindowData *windata;
+ GdkVisual *visual;
+ GdkScreen *screen;
+ GResource *resource;
+
+ windata = g_new0(WindowData, 1);
+ windata->urgency = URGENCY_NORMAL;
+ windata->url_clicked = url_clicked;
+
+ win = gtk_window_new(GTK_WINDOW_POPUP);
+ gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
+ gtk_window_set_decorated (GTK_WINDOW(win), TRUE);
+ windata->win = win;
+
+ //register resource
+ resource = kiran_get_resource();
+ g_resources_register (resource);
+
+ set_css(windata->win);
+ gtk_widget_set_name(windata->win , "notification_window");
+ windata->rtl = gtk_widget_get_default_direction();
+ windata->composited = FALSE;
+ screen = gtk_window_get_screen(GTK_WINDOW(win));
+ visual = gdk_screen_get_rgba_visual(screen);
+
+ if (visual != NULL)
+ {
+ gtk_widget_set_visual(win, visual);
+ if (gdk_screen_is_composited(screen))
+ windata->composited = TRUE;
+ }
+ gtk_window_set_title(GTK_WINDOW(win), "Notification");
+ gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_NOTIFICATION);
+ gtk_widget_add_events(win, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+
+ g_signal_connect(G_OBJECT(win), "realize" , G_CALLBACK(on_realize) , NULL);
+
+ gtk_widget_realize(win);
+
+ g_object_set_data_full(G_OBJECT(win), "windata", windata,
+ (GDestroyNotify)destroy_windata);
+ atk_object_set_role(gtk_widget_get_accessible(win), ATK_ROLE_ALERT);
+
+ g_signal_connect(G_OBJECT(win), "configure_event",
+ G_CALLBACK(configure_event_cb), windata);
+
+ main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_widget_set_name(main_vbox , "main_vbox");
+ gtk_widget_show(main_vbox);
+ gtk_container_add (GTK_CONTAINER (win), main_vbox);
+
+ g_signal_connect (G_OBJECT (main_vbox), "draw",
+ G_CALLBACK (on_draw), windata);
+
+ g_signal_connect (G_OBJECT (win), "configure-event", G_CALLBACK (on_configure_event), windata);
+
+ g_signal_connect (G_OBJECT (win), "composited-changed", G_CALLBACK (on_composited_changed), windata);
+
+ windata->main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_widget_set_name(windata->main_hbox , "main_hbox");
+ gtk_widget_set_halign (windata->main_hbox, GTK_ALIGN_START);
+ gtk_widget_set_valign (windata->main_hbox, GTK_ALIGN_START);
+ gtk_widget_show (windata->main_hbox);
+ gtk_box_pack_start (GTK_BOX(main_vbox), windata->main_hbox, FALSE, FALSE, 0);
+
+ /* The icon goes at the left */
+ windata->iconbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_widget_set_name(windata->iconbox , "icon_box");
+ gtk_widget_show(windata->iconbox);
+ gtk_box_pack_start(GTK_BOX(windata->main_hbox), windata->iconbox,
+ FALSE, FALSE, 0);
+ gtk_widget_set_valign (GTK_WIDGET(windata->iconbox),GTK_ALIGN_START);
+
+ windata->icon = gtk_image_new();
+ gtk_box_pack_start(GTK_BOX(windata->iconbox), windata->icon,
+ FALSE, FALSE, 0);
+
+ /* The title and the text at the right */
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_widget_set_name(vbox , "text_vbox");
+ gtk_widget_set_halign (vbox, GTK_ALIGN_START);
+ gtk_widget_show (vbox);
+ gtk_box_pack_start (GTK_BOX (windata->main_hbox), vbox, FALSE, FALSE, 0);
+
+
+ /* Add action_vbox*/
+ action_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL , 0);
+ gtk_widget_set_name(action_vbox , "action_vbox");
+ gtk_widget_show(action_vbox);
+ gtk_box_pack_end(GTK_BOX(windata->main_hbox), action_vbox , FALSE , FALSE ,0);
+ gtk_widget_set_halign (action_vbox, GTK_ALIGN_END);
+
+ /* Add the close button */
+ close_button = gtk_button_new();
+ gtk_widget_set_name(GTK_WIDGET(close_button) ,"close_button" );
+ gtk_widget_set_size_request(GTK_WIDGET(close_button) , 16 , 16);
+ gtk_widget_set_valign (close_button, GTK_ALIGN_START);
+ gtk_widget_set_halign (close_button, GTK_ALIGN_END);
+ gtk_widget_set_vexpand (close_button,FALSE);
+ gtk_widget_set_hexpand(close_button , FALSE);
+ gtk_widget_show(close_button);
+
+ windata->close_button = close_button;
+ gtk_box_pack_start (GTK_BOX (action_vbox),
+ windata->close_button,
+ FALSE, FALSE, 0);
+
+ gtk_button_set_relief(GTK_BUTTON(close_button), GTK_RELIEF_NONE);
+ gtk_container_set_border_width(GTK_CONTAINER(close_button), 0);
+ g_signal_connect_swapped(G_OBJECT(close_button), "clicked", G_CALLBACK(gtk_widget_destroy), win);
+
+ atkobj = gtk_widget_get_accessible(close_button);
+ atk_action_set_description(ATK_ACTION(atkobj), 0,
+ _("Closes the notification."));
+ atk_object_set_name(atkobj, "");
+ atk_object_set_description (atkobj, _("Closes the notification."));
+
+ windata->actions_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,10);
+ gtk_widget_set_name(windata->actions_box , "actions_box");
+ gtk_widget_set_halign(windata->actions_box, GTK_ALIGN_END);
+ gtk_widget_show(windata->actions_box);
+ gtk_box_pack_end(GTK_BOX(action_vbox), windata->actions_box, FALSE, FALSE, 0);
+ gtk_widget_set_vexpand (windata->actions_box,FALSE);
+ gtk_widget_set_hexpand (windata->actions_box,FALSE);
+
+ windata->summary_label = gtk_label_new(NULL);
+ gtk_widget_set_name(windata->summary_label, "summary_label");
+ gtk_widget_show(windata->summary_label);
+ gtk_box_pack_start(GTK_BOX(vbox), windata->summary_label, FALSE, FALSE, 0);
+ gtk_label_set_xalign (GTK_LABEL (windata->summary_label), 0.0);
+ gtk_label_set_yalign (GTK_LABEL (windata->summary_label), 0.0);
+ gtk_label_set_line_wrap(GTK_LABEL(windata->summary_label), TRUE);
+ gtk_label_set_line_wrap_mode (GTK_LABEL (windata->summary_label), PANGO_WRAP_WORD_CHAR);
+
+ atkobj = gtk_widget_get_accessible(windata->summary_label);
+ atk_object_set_description (atkobj, _("Notification summary text."));
+
+ windata->body_label = gtk_label_new(NULL);
+ gtk_widget_set_name(windata->body_label , "body_label");
+ gtk_box_pack_start(GTK_BOX(vbox), windata->body_label, FALSE, FALSE, 0);
+ gtk_label_set_xalign (GTK_LABEL (windata->body_label), 0.0);
+ gtk_label_set_yalign (GTK_LABEL (windata->body_label), 0.0);
+ gtk_label_set_line_wrap(GTK_LABEL(windata->body_label), TRUE);
+ gtk_label_set_line_wrap_mode (GTK_LABEL (windata->body_label), PANGO_WRAP_WORD_CHAR);
+ gtk_label_set_max_width_chars (GTK_LABEL (windata->body_label), 50);
+ gtk_widget_set_vexpand (windata->body_label, FALSE);
+
+ g_signal_connect(G_OBJECT(windata->body_label), "activate-link",
+ G_CALLBACK(activate_link), windata);
+
+ atkobj = gtk_widget_get_accessible(windata->body_label);
+ atk_object_set_description (atkobj, _("Notification body text."));
+
+ g_resources_unregister (resource);
+ return GTK_WINDOW(win);
+}
+
+/* Set the notification text */
+void
+set_notification_text(GtkWindow *nw, const char *summary, const char *body)
+{
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
+ g_assert(windata != NULL);
+
+ if(summary == NULL || *summary == '\0')
+ {
+ if(windata->urgency == URGENCY_CRITICAL)
+ {
+ summary = _("Normal Notification");
+ }
+ else if(windata->urgency == URGENCY_LOW)
+ {
+ summary = _("Low Notification");
+ }
+ else if(windata->urgency == URGENCY_CRITICAL)
+ {
+ summary = _("Critical Notification");
+ }
+ }
+
+ gtk_label_set_text(GTK_LABEL(windata->summary_label) , summary);
+ gtk_label_set_text (GTK_LABEL (windata->body_label), body);
+
+ if (body == NULL || *body == '\0')
+ gtk_widget_hide(windata->body_label);
+ else
+ gtk_widget_show(windata->body_label);
+
+ gtk_widget_set_size_request(
+ ((body != NULL && *body != '\0')
+ ? windata->body_label : windata->summary_label),
+ WIDTH - (IMAGE_SIZE + IMAGE_PADDING) - 10,
+ -1);
+}
+
+/* Set notification icon */
+void
+set_notification_icon(GtkWindow *nw, GdkPixbuf *pixbuf)
+{
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
+ g_assert(windata != NULL);
+ gtk_image_set_from_pixbuf(GTK_IMAGE(windata->icon), pixbuf);
+
+ if (pixbuf != NULL)
+ {
+ int pixbuf_width = gdk_pixbuf_get_width(pixbuf);
+
+ gtk_widget_show(windata->icon);
+ gtk_widget_set_size_request(windata->iconbox,
+ MAX(BODY_X_OFFSET, pixbuf_width), -1);
+ }
+ else
+ {
+ gtk_widget_hide(windata->icon);
+ gtk_widget_set_size_request(windata->iconbox, BODY_X_OFFSET, -1);
+ }
+}
+
+/* Set notification arrow */
+void
+set_notification_arrow(GtkWidget *nw, gboolean visible, int x, int y)
+{
+ /* nothing */
+}
+
+/* Add notification action */
+void
+add_notification_action(GtkWindow *nw, const char *text, const char *key,
+ ActionInvokedCb cb)
+{
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
+ GtkWidget *label;
+ GtkWidget *button;
+ GtkWidget *hbox;
+ GdkPixbuf *pixbuf;
+ char *buf;
+
+ g_assert(windata != NULL);
+
+ if (gtk_widget_get_visible(windata->actions_box))
+ {
+ gtk_widget_show(windata->actions_box);
+ /* Don't try to re-add a pie_countdown */
+ if (!windata->pie_countdown) {
+ windata->pie_countdown = gtk_drawing_area_new();
+ gtk_widget_set_halign (windata->pie_countdown, GTK_ALIGN_END);
+ gtk_widget_set_valign (windata->pie_countdown, GTK_ALIGN_END);
+ gtk_widget_show(windata->pie_countdown);
+
+ gtk_box_pack_end (GTK_BOX (windata->actions_box), windata->pie_countdown, FALSE, FALSE, 0);
+ gtk_widget_set_size_request(windata->pie_countdown,
+ PIE_WIDTH, PIE_HEIGHT);
+ g_signal_connect(G_OBJECT(windata->pie_countdown), "draw",
+ G_CALLBACK(countdown_expose_cb), windata);
+ }
+ }
+
+ if (windata->action_icons) {
+ button = gtk_button_new_from_icon_name(key, GTK_ICON_SIZE_BUTTON);
+ goto add_button;
+ }
+
+ button = gtk_button_new();
+ gtk_widget_show(button);
+ hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_widget_set_name(GTK_WIDGET(hbox) , "actions_hbox");
+ gtk_widget_set_valign(GTK_WIDGET(hbox), GTK_ALIGN_END);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
+ gtk_widget_show(hbox);
+ gtk_container_add(GTK_CONTAINER(button), hbox);
+
+ /* Try to be smart and find a suitable icon. */
+ buf = g_strdup_printf("stock_%s", key);
+ pixbuf = gtk_icon_theme_load_icon(
+ gtk_icon_theme_get_for_screen(
+ gdk_window_get_screen(gtk_widget_get_window(GTK_WIDGET(nw)))),
+ buf, 16, GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
+ g_free(buf);
+
+ if (pixbuf != NULL)
+ {
+ GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf);
+ gtk_widget_show(image);
+ gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
+ gtk_widget_set_halign (image, GTK_ALIGN_END);
+ gtk_widget_set_valign (image, GTK_ALIGN_END);
+ }
+
+ label = gtk_label_new(NULL);
+ gtk_widget_set_name(GTK_WIDGET(label) , "actions_label");
+ gtk_widget_show(label);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_label_set_yalign (GTK_LABEL (label), 1.0);
+ gtk_widget_set_valign(GTK_WIDGET(label), GTK_ALIGN_END);
+ gtk_label_set_text(GTK_LABEL(label) , text);
+
+add_button:
+ gtk_widget_set_valign(GTK_WIDGET(button), GTK_ALIGN_END);
+ gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
+
+ gtk_widget_set_name(GTK_WIDGET(button) , "actions_button");
+ gtk_box_pack_start(GTK_BOX(windata->actions_box), button, FALSE, FALSE, 0);
+
+ g_object_set_data(G_OBJECT(button), "_nw", nw);
+ g_object_set_data_full(G_OBJECT(button),
+ "_action_key", g_strdup(key), g_free);
+ g_signal_connect(G_OBJECT(button), "button-release-event",
+ G_CALLBACK(action_clicked_cb), cb);
+
+ gtk_widget_show_all(windata->actions_box);
+}
+
+/* Clear notification actions */
+void
+clear_notification_actions(GtkWindow *nw)
+{
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
+
+ windata->pie_countdown = NULL;
+
+ gtk_widget_hide(windata->actions_box);
+ gtk_container_foreach(GTK_CONTAINER(windata->actions_box),
+ (GtkCallback)gtk_widget_destroy, NULL);
+}
+
+/* Move notification window */
+void
+move_notification(GtkWidget *nw, int x, int y)
+{
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
+ g_assert(windata != NULL);
+
+ gtk_window_move(GTK_WINDOW(nw), x, y);
+}
+
+
+/* Optional Functions */
+
+/* Destroy notification */
+
+/* Show notification */
+
+/* Hide notification */
+
+/* Set notification timeout */
+void
+set_notification_timeout(GtkWindow *nw, glong timeout)
+{
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
+ g_assert(windata != NULL);
+
+ windata->timeout = timeout;
+}
+
+/* Set notification hints */
+void set_notification_hints(GtkWindow *nw, GVariant *hints)
+{
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
+ GVariant *value = NULL, *icon_value = NULL;
+
+ g_assert(windata != NULL);
+
+ g_variant_lookup(hints, "urgency", "v", &value);
+ g_variant_lookup(hints, "action-icons", "v", &icon_value);
+
+ if (value != NULL && g_variant_get_type(value) == G_VARIANT_TYPE_BYTE)
+ {
+ windata->urgency = g_variant_get_byte(value);
+
+ if (windata->urgency == URGENCY_CRITICAL) {
+ gtk_window_set_title(GTK_WINDOW(nw), "Critical Notification");
+ } else {
+ gtk_window_set_title(GTK_WINDOW(nw), "Notification");
+ }
+ }
+
+ /* Determine if action-icons have been requested */
+ if (icon_value != NULL && g_variant_get_type(icon_value) == G_VARIANT_TYPE_BOOLEAN)
+ {
+ windata->action_icons = g_variant_get_boolean(icon_value);
+ }
+}
+
+/* Notification tick */
+void
+notification_tick(GtkWindow *nw, glong remaining)
+{
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
+ windata->remaining = remaining;
+
+ if (windata->pie_countdown != NULL)
+ {
+ gtk_widget_queue_draw_area(windata->pie_countdown, 0, 0,
+ PIE_WIDTH, PIE_HEIGHT);
+ }
+}
diff --git a/src/themes/kiran/kiran.gresource.xml b/src/themes/kiran/kiran.gresource.xml
new file mode 100644
index 0000000..d177863
--- /dev/null
+++ b/src/themes/kiran/kiran.gresource.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/kiran/themes">
+ <file alias="kiran.css">data/kiran.css</file>
+ <file alias="close_hover">data/icons/close_hover.svg</file>
+ <file alias="close_normal">data/icons/close_normal.svg</file>
+ <file alias="close_press">data/icons/close_press.svg</file>
+ </gresource>
+</gresources>
--
2.27.0