GTK+中文社区(gtk.awaysoft.com)

 找回密码
 马上加入

QQ登录

只需一步,快速开始

查看: 5158|回复: 4

gtk窗口边界阴影效果实现

[复制链接]
  • TA的每日心情
    无聊
    2012-11-4 09:32
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2013-8-25 22:35:07 | 显示全部楼层 |阅读模式
      gtk默认窗口管理器是带阴影效果的,但是当我们自定义界面去除窗口管理器的修饰后阴影效果就消失了。学习了下deepin-ui关于窗口阴影效果处理,改用gtk3完美实现阴影效果,发个demo分享下,具体步骤就不细说了,看代码你懂的。下图是效果:

    // 编译命令 gcc *.c `pkg-config --cflags --libs gtk+-3.0`
    #include <gtk/gtk.h>

    gint frame_radius = 3; // 2
    gint shadow_radius = 10;// 6
    gint shadow_padding = 0;

    void draw_round_rectangle(cairo_t *cr, gint x, gint y, gint width, gint height, gint r);
    void draw_radial_round(cairo_t *cr, gint x, gint y, gint r);
    void draw_hlinear(cairo_t *cr, gint x, gint y, gint w, gint h, gboolean left_to_right);
    void draw_vlinear(cairo_t *cr, gint x, gint y, gint w, gint h, gboolean top_to_bottom);

    void draw_window_shadow(cairo_t *cr, gint x, gint y, gint w, gint h, gint r, gint p)
    {
        cairo_save(cr);
        cairo_rectangle(cr, x, y, r - 1, r - 1);
        cairo_rectangle(cr, x + r - 1, y, 1, r - 2);
        cairo_rectangle(cr, x, y + r - 1, r - 2, 1);
       
        cairo_rectangle(cr, x + w - r + 1, y, r - 1, r - 1);
        cairo_rectangle(cr, x + w - r, y, 1, r - 2);
        cairo_rectangle(cr, x + w - r + 2, y + r - 1, r - 2, 1);
       
        cairo_rectangle(cr, x, y + h - r + 1, r - 1, r - 1);
        cairo_rectangle(cr, x + r - 1, y + h - r + 2, 1, r - 2);
        cairo_rectangle(cr, x, y + h - r, r - 2, 1);
       
        cairo_rectangle(cr, x + w - r + 1, y + h - r + 1, r - 1, r - 1);
        cairo_rectangle(cr, x + w - r, y + h - r + 2, 1, r - 2);
        cairo_rectangle(cr, x + w - r + 2, y + h - r, r - 2, 1);
        cairo_clip(cr);
       
        // Draw four round.
        draw_radial_round(cr, x + r, y + r, r);
        draw_radial_round(cr, x + r, y + h - r, r);
        draw_radial_round(cr, x + w - r, y + r, r);
        draw_radial_round(cr, x + w - r, y + h - r, r);
        cairo_restore(cr);
       
        cairo_save(cr);
        // Clip four side.
        cairo_rectangle(cr, x, y + r, p, h - r * 2);
        cairo_rectangle(cr, x + w - p, y + r, p, h - r * 2);
        cairo_rectangle(cr, x + r, y, w - r * 2, p);
        cairo_rectangle(cr, x + r, y + h - p, w - r * 2, p);
        cairo_clip(cr);
       
        // Draw four side.
        draw_vlinear(
            cr,
            x + r, y,
            w - r * 2, r, TRUE);
        draw_vlinear(
            cr,
            x + r, y + h - r,
            w - r * 2, r, FALSE);
        draw_hlinear(
            cr,
            x, y + r,
            r, h - r * 2, TRUE);
        draw_hlinear(
            cr,
            x + w - r, y + r,
            r, h - r * 2, FALSE);
        cairo_restore(cr);
    }

    void draw_radial_round(cairo_t *cr, gint x, gint y, gint r)
    {
        cairo_pattern_t *radial = cairo_pattern_create_radial(x, y, r, x, y, 0);
        cairo_pattern_add_color_stop_rgba(radial, 0, 0, 0, 0, 0);
        cairo_pattern_add_color_stop_rgba(radial, 0.66, 0, 0, 0, 0.2);
        cairo_pattern_add_color_stop_rgba(radial, 1, 0, 0, 0, 0.33);
        cairo_arc(cr, x, y, r, 0, 2 * G_PI);
        cairo_set_source(cr, radial);
        cairo_fill(cr);

        cairo_pattern_destroy(radial);
    }

    void draw_vlinear(cairo_t *cr, gint x, gint y, gint w, gint h, gboolean top_to_buttom)
    {
        gint r = 0;
        cairo_save(cr);
        // Translate y coordinate, otherwise y is too big for LinearGradient cause render bug.
        cairo_translate(cr, 0, y);
        cairo_pattern_t *linear = NULL;
        if(top_to_buttom)
            linear = cairo_pattern_create_linear(0, 0, 0, h);
        else
            linear = cairo_pattern_create_linear(0, h, 0, 0);

        cairo_pattern_add_color_stop_rgba(linear, 0, 0, 0, 0, 0);
        cairo_pattern_add_color_stop_rgba(linear, 0.66, 0, 0, 0, 0.2);
        cairo_pattern_add_color_stop_rgba(linear, 1, 0, 0, 0, 0.33);
            
        cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
        cairo_set_source(cr, linear);
        draw_round_rectangle(cr, x, 0, w, h, r);
        cairo_fill(cr);
        cairo_restore(cr);
        cairo_pattern_destroy(linear);
    }

    void draw_hlinear(cairo_t *cr, gint x, gint y, gint w, gint h, gboolean left_to_right)
    {
        gint r = 0;
        cairo_save(cr);
        // Translate x coordinate, otherwise x is too big for LinearGradient cause render bug.
        cairo_pattern_t *linear;
        cairo_translate(cr, x, 0);
        if(left_to_right)   
            linear = cairo_pattern_create_linear(0, 0, w, 0);
        else
            linear = cairo_pattern_create_linear(w, 0, 0, 0);

        cairo_pattern_add_color_stop_rgba(linear, 0, 0, 0, 0, 0);
        cairo_pattern_add_color_stop_rgba(linear, 0.66, 0, 0, 0, 0.2);
        cairo_pattern_add_color_stop_rgba(linear, 1, 0, 0, 0, 0.33);

        cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
        cairo_set_source(cr, linear);
        draw_round_rectangle(cr, 0, y, w, h, r);
        cairo_fill(cr);
        cairo_restore(cr);

        cairo_pattern_destroy(linear);
    }

    void draw_round_rectangle(cairo_t *cr, gint x, gint y, gint width, gint height, gint r)
    {
        // Adjust coordinate when width and height is negative.
        if(width < 0)
        {
            x = x + width;
            width = -width;
        }

        if(height < 0)
        {
            y = y + height;
            height = -height;
        }
       
        // Top side.
        cairo_move_to(cr, x + r, y);
        cairo_line_to(cr, x + width - r, y);
        // Top-right corner.
        cairo_arc(cr, x + width - r, y + r, r, G_PI * 3 / 2, G_PI * 2);
        // Right side.
        cairo_line_to(cr, x + width, y + height - r);
        // Bottom-right corner.
        cairo_arc(cr, x + width - r, y + height - r, r, 0, G_PI / 2);
        // Bottom side.
        cairo_line_to(cr, x + r, y + height);
       
        // Bottom-left corner.
        cairo_arc(cr, x + r, y + height - r, r, G_PI / 2, G_PI);
       
        // Left side.
        cairo_line_to(cr, x, y + r);
        // Top-left corner.
        cairo_arc(cr, x + r, y + r, r, G_PI, G_PI * 3 / 2);

        // Close path.
        cairo_close_path(cr);
    }

    gboolean on_draw_shadow(GtkWidget *widget, cairo_t *cr, gpointer data)
    {
        cr = gdk_cairo_create(gtk_widget_get_window(widget));

        GtkAllocation alloc;
        gtk_widget_get_allocation(widget, &alloc);
        draw_window_shadow(cr, alloc.x, alloc.y, alloc.width, alloc.height, shadow_radius, shadow_padding);
    }

    gboolean on_draw(GtkWidget *widget, gpointer data)
    {
        GtkAllocation alloc;
        gint x, y, width, height, r;
        gtk_widget_get_allocation(widget, &alloc);
        x = alloc.x;
        y = alloc.y;
        width = alloc.width;
        height = alloc.height;
        r = 5;

        cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget));

        cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 200, 200);
        cairo_t *cr2 = cairo_create(surface);

        cairo_move_to(cr2, r, 0);
        cairo_line_to(cr2, width-r, 0);

        cairo_move_to(cr2, width, r);
        cairo_line_to(cr2, width, height-r);

        cairo_move_to(cr2, width-r, height);
        cairo_move_to(cr2, r, height);

        cairo_move_to(cr2, 0, height-r);
        cairo_line_to(cr2, 0, r);

        cairo_arc(cr2, r, r, r, G_PI, 3 * G_PI / 2.0 );
        cairo_arc(cr2, width-r, r, r, 3 * G_PI /2.0, 2 * G_PI);
        cairo_arc(cr2, width-r, height-r, r, 0, G_PI / 2);
        cairo_arc(cr2, r, height-r, r, G_PI / 2, G_PI);
        cairo_fill(cr2);

        cairo_set_source_rgba(cr, 0, 0, 0, 0);
        cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
        cairo_paint(cr);

        cairo_region_t *region = gdk_cairo_region_create_from_surface(surface);
        gtk_widget_shape_combine_region(widget, region);

        cairo_destroy(cr2);
        cairo_destroy(cr);
        cairo_region_destroy(region);
        cairo_surface_destroy(surface);

        return FALSE;
    }

    int main(int argc, char *argv[])
    {
        GtkWidget *window;

        gtk_init(&argc, &argv);

        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
        gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
        gtk_widget_set_app_paintable(window, TRUE);
        g_signal_connect(G_OBJECT(window), "draw", G_CALLBACK(on_draw), NULL);
        g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

        shadow_padding = shadow_radius - frame_radius;
        GtkWidget *window_shadow = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
        gtk_alignment_set_padding(GTK_ALIGNMENT(window_shadow), shadow_padding, shadow_padding, shadow_padding, shadow_padding);
        g_signal_connect(G_OBJECT(window_shadow), "draw", G_CALLBACK(on_draw_shadow), NULL);

        /*GtkWidget *button = gtk_button_new_with_label("Hello Gtk");*/
        /*gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE);*/
        /*gtk_container_add(GTK_CONTAINER(window_shadow), button);*/

        gtk_container_add(GTK_CONTAINER(window), window_shadow);

        GdkScreen *screen;
        GdkVisual *visual;
        screen = gdk_screen_get_default();
        visual = gdk_screen_get_rgba_visual(screen);
        gtk_widget_set_visual(window, visual);

        gtk_widget_show_all(window);
        gtk_main();
        return 0;
    }


    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?马上加入

    x

    该用户从未签到

    发表于 2013-12-19 13:03:31 | 显示全部楼层
    你的代码会挂
  • TA的每日心情
    奋斗
    2014-7-2 07:20
  • 签到天数: 13 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    发表于 2013-12-31 10:18:01 | 显示全部楼层
    请教一下,这个必须用gtk3才能编译通过吗?我用gtk2提示“undefined reference to `gdk_cairo_region_create_from_surface”。。。
    ttttt 该用户已被删除
    发表于 2014-10-29 23:05:26 | 显示全部楼层
    提示: 作者被禁止或删除 内容自动屏蔽
    *滑块验证:
    您需要登录后才可以回帖 登录 | 马上加入

    本版积分规则

    申请友链|Archiver|小黑屋|手机版|GTK+中文社区 ( 粤ICP备13080851号 )

    我要啦免费统计

    GMT+8, 2024-11-21 17:00 , Processed in 0.024989 second(s), 9 queries , Redis On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表