美文网首页C语言我用 Linux
使用Gtk写一个360网速指示器

使用Gtk写一个360网速指示器

作者: 霡霂976447044 | 来源:发表于2019-05-29 15:49 被阅读2次

效果如下:


Peek 2019-05-29 14-57.gif

使用Linux Mint很久了,其实在这,之前写了一个比较丑的网速指示器。


image

刚开始使用pygtk写,后来使用c语言写,Gtk资料少。其实也就写了不到两天,很多地方代码还没有优化,因为自己在实习,上班也没有什么事干,于是就想实现下比较好看的效果。总的来说,GTK+资料少,写起来还是比较费劲。下面说下思路。

1. 实现悬浮窗

实现悬浮窗的是使用GTK的GTK_WINDOW_POPUP类型,它可以实现没有任务窗口栏显示。

window = gtk_window_new(GTK_WINDOW_POPUP);

2. 获取网络、内存信息

主要是读取/proc/net/dev/proc/meminfo

int getMemPercentage() {

    FILE *fd_men = fopen("/proc/meminfo", "r");
    if(fd_men == NULL) {
        perror("open file /proc/meminfo error");
        exit(-1);
    }

    char tmp[255];
    fgets(tmp, 255, fd_men);
    unsigned long men = 0;
    unsigned long free = 0;
    sscanf(tmp, "MemTotal: %ld KB", &men);
    fgets(tmp, 255, fd_men);
    fgets(tmp, 255, fd_men);
    sscanf(tmp, "MemAvailable: %ld KB", &free);

    unsigned long use = men - free;
    int percent = ((float)use / (float)men) * 100;


    fclose(fd_men);
    return percent;
}

// 获取网速
void getNetworkBandWidth(unsigned long long int *receiveBytes, unsigned long long int *sendBytes) {
    char *buf;
    const int bufSize = 255;
    FILE *devfd;

    buf = (char *) calloc(bufSize, 1);

    devfd = fopen("/proc/net/dev", "r");
    if (devfd == NULL) {
        perror("open file /proc/net/dev failure.");
        exit(-1);
    }

    // Ignore the first and second lines of the file.
    fgets(buf, bufSize, devfd); // fgets will return if reading a newline.
    fgets(buf, bufSize, devfd);
    *receiveBytes = 0;
    *sendBytes = 0;

    while (fgets(buf, bufSize, devfd)) {
        unsigned long long int rBytes, sBytes;
        char *line = strdup(buf);

        char *dev;
        dev = strtok(line, ":");
        gchar *is_lo = g_strrstr(dev, "lo");
        if (is_lo != NULL) { // if end with lo
            continue;
        }
        sscanf(buf + strlen(dev) + 2, "%llu %*d %*d %*d %*d %*d %*d %*d %llu", &rBytes, &sBytes);
        *receiveBytes += rBytes;
        *sendBytes += sBytes;
        free(line);
    }

    fclose(devfd);
    free(buf);
}

网速的逻辑参照deepin的任务管理器的网速获取。

3. 设置透明

需要桌面系统支持。

// 配置透明
static void tran_setup(GtkWidget *win) {
    GdkScreen *screen;
    GdkVisual *visual;

    gtk_widget_set_app_paintable(win, TRUE);
    screen = gdk_screen_get_default();
    visual = gdk_screen_get_rgba_visual(screen);

    if (visual != NULL && gdk_screen_is_composited(screen)) {
        gtk_widget_set_visual(win, visual);
        g_print("ok");
    }
}

4. 绘制界面

绘制界面是使用的是cairo

static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
                              gpointer user_data) {
    GtkWidget *win = gtk_widget_get_toplevel(widget);

    cairo_t *first_cr, *second_cr;
    cairo_surface_t *first, *second;

    int width, height;
    char tmp[255];

    gtk_window_get_size(GTK_WINDOW(win), &width, &height);

    first = cairo_surface_create_similar(cairo_get_target(cr),
                                         CAIRO_CONTENT_COLOR_ALPHA, width, height);

    second = cairo_surface_create_similar(cairo_get_target(cr),
                                          CAIRO_CONTENT_COLOR_ALPHA, width, height);



    first_cr = cairo_create(first);
    second_cr = cairo_create(second);


    // 画左边的圆
    cairo_translate(first_cr, SIZE/2+6, height / 2); // 设置中心点

    cairo_set_line_width(first_cr, PEN_WIDTH); // 设置线条宽度
    cairo_set_source_rgb(first_cr, 0.9, 0.9, 0.9); // 设置圆的外边框颜色
    cairo_arc(first_cr, 0, 0, SIZE / 2, 0, 2 * M_PI);
    cairo_stroke_preserve(first_cr); // 画外边框

    cairo_set_source_rgb(first_cr, 0.85, 0.8, 0.8); // 设置圆的填充颜色(灰色)
    cairo_fill(first_cr); // 填充可用内存

    float start = 0.5 - ((float)memPercentage / 100);
    float end = 0.5 + ((float)memPercentage / 100);
    cairo_arc(first_cr, 0, 0, SIZE / 2, M_PI * start, M_PI * end);
//    cairo_close_path(first_cr);
    if(memPercentage <=50) {
        cairo_set_source_rgb(first_cr, 0.1, 0.7, 0.1); // 设置圆的填充颜色 绿色
    } else if(memPercentage <= 79) {
        cairo_set_source_rgb(first_cr, 1, 0.6, 0); // 设置圆的填充颜色 黄色
    } else {
        cairo_set_source_rgb(first_cr, 0.9, 0, 0); // 设置圆的填充颜色 红色
    }

    cairo_fill(first_cr); // 填充已经使用的内存

    cairo_set_source_rgb(first_cr, 0.1, 0.1, 0.1);
    cairo_select_font_face(first_cr, "Ubuntu Mono",
                           CAIRO_FONT_SLANT_NORMAL,
                           CAIRO_FONT_WEIGHT_BOLD);
    cairo_set_font_size(first_cr, 16);
    cairo_move_to(first_cr, -12, 4);
    sprintf(tmp, "%d%%", memPercentage);
    cairo_show_text(first_cr, tmp);


    // 矩形
    cairo_set_source_rgb(second_cr, 0.9, 0.9, 0.9); // 右边的颜色
    cairo_rectangle(second_cr, 0, 0, RIGHT_CIRCLE_WIDTH, RIGHT_CIRCLE_SIZE); // 矩形
    cairo_fill(second_cr);

    // 右边的半圆
    cairo_set_source_rgb(second_cr, 0.9, 0.9, 0.9); // 右边的颜色
    cairo_translate(second_cr, 100, 25);
    cairo_arc(second_cr, 0, 0, RIGHT_CIRCLE_SIZE / 2, 0, 2 * M_PI);
    cairo_fill(second_cr);
    cairo_set_source_rgb(second_cr, 0.1, 0.1, 0.1);
    cairo_select_font_face(second_cr, "Serif",
                           CAIRO_FONT_SLANT_NORMAL,
                           CAIRO_FONT_WEIGHT_BOLD);
    cairo_set_font_size(second_cr, 11);

    cairo_move_to(second_cr, -(RIGHT_CIRCLE_WIDTH-SIZE/2), -8);
    sprintf(tmp, " ↑ %lu kb/s", csD);
    cairo_show_text(second_cr, tmp);
    cairo_move_to(second_cr, -(RIGHT_CIRCLE_WIDTH-SIZE/2), 15);
    sprintf(tmp, " ↓ %lu kb/s", crD);
    cairo_show_text(second_cr, tmp);

    // 添加
    cairo_set_operator(first_cr, CAIRO_OPERATOR_DEST_OVER);
    cairo_set_source_surface(first_cr, second, 0, -SIZE/2+5);
    cairo_paint(first_cr);

    cairo_set_source_surface(cr, first, 0, 0);
    cairo_paint(cr);

    cairo_destroy(first_cr);
    cairo_destroy(second_cr);


    return FALSE;
}

比较麻烦的是内存占用的绘制,这里是使用的绘制圆弧实现的,圆的中心点是(0, 0), 下图是角度示意:

截图_2019-05-29_15-32-56.png
要绘制内存填充区域,需要知道内存占用比例,根据这个比例,计算圆弧的开始角度和结束角度。
假设内存占用50%,那么应该是 开始角度为:0 * M_PI,结束角度为 1 * M_PI, 等价于以下代码动态实现:
float start = 0.5 - ((float)memPercentage / 100);
float end = 0.5 + ((float)memPercentage / 100);

start为负数的时候,自然会逆时针绘制。

再者,绘制界面的时候,使用了两个surface,一个绘制圆+圆弧,一个绘制矩形+圆。这需要使用cairo的组合。

自启动

把二进制文件放到$PATH里面,加可执行权限。
在自启动管理软件里面执行这个二进制文件,如果发现会边框黑,加上sleep 20。等你的桌面完全启动好再启动。

下载

有空会上传到github,这里先给出下载链接

http://file.alonebo.top/360ball

相关文章

网友评论

    本文标题:使用Gtk写一个360网速指示器

    本文链接:https://www.haomeiwen.com/subject/tmnwzqtx.html