Все началось с того, что я поставил на свой нетбук Ubuntu. После сексуальных извращений с различными deb пакетами и попыток настроить её под себя я понял что ничего хорошего из этого не выйдет.
Первое что мне попалось в глаза это стандартный апплет погоды, который показывал белеберду.
А ведь я знаю, что на нашем местном университете установлены датчики температуры и текущая погода отображается на главной странице в виде картинки с замысловатым адресом
http://ito.osu.ru/termometr/curr_temp_graph.php?color=66,112,171&bgcolor=255,255,255
Я не знаю откуда скрипт берет данные, но на его выходе получается GIF с установленным цветом шрифта и фона.
Вот так и появилась идея написать собственный апплет.
Сказано, сделано!
Поковыряв гугл я выяснил что для написания апплетов в gnome используется библиотека gtk, а педевикия недвусмысленно вывела меня на страницу русского туториала.
Лениво пролистав его я попробовал скомпилировать первый Hell World
Для этого мне пришлось выкачать метров 40 библиотек и еще приблизительно метров 30 заняло NetBeans IDE (gedit, конечно рулит, но я уже как-то привык к автоформатированию и подсказанькам)
sudo apt-get install libgtk2.0-devСкомпилировав первую программу незамысловатой коммандой:
gcc test.c -o test `pkg-config --cflags --libs gtk+-2.0`я радостный лег спать, ибо было уже 4 часа ночи (если не пять).
Сегодня, как только выдалась свободная минутка я сел за ноут :)
Идея была такова:
- Получить картинку и сохранить ее во временный файл
Для этого нужно написать TCP клиента и отправить HTTP GET запрос на сервер ito.osu.ru, ну а потом отделить картинку от HTTP заголовка - Отобразить ее в трее в виде иконки
На этом этапе я основывался этой статьей
Вот что у меня получилось:
#include#include #include #include #include #include #include #include #include #include #include #include "eggtrayicon.h" typedef unsigned int SOCKET; #define SEND 0 #define RECV 1 int (*tcp_func)(SOCKET s, char* buf, int len, int flags); #define FILE_IMG "/tmp/garik_temp.gif" void destroy(GtkWidget *widget, gpointer data) { gtk_main_quit(); } SOCKET tcp_client(char *host, unsigned short port) { struct sockaddr_in dest_addr; struct hostent *hst; SOCKET s; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1; dest_addr.sin_family = AF_INET; dest_addr.sin_port = htons(port); if ((dest_addr.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) { if (hst = gethostbyname(host)) ((unsigned long *) & dest_addr.sin_addr)[0] = ((unsigned long **) hst->h_addr_list)[0][0]; else { close(s); return -1; } } if (connect(s, (struct sockaddr *) & dest_addr, sizeof (dest_addr))) return -1; return s; } // функция гарантирует нам получение данных размером len int tcp_rs(char type, SOCKET s, char *buf, int len, int flags) { int total = 0; int n; if (type == SEND) tcp_func = &send; else tcp_func = &recv; while (total < len) { n = tcp_func(s, buf + total, len - total, flags); if (n > 0) { total += n; } else if (n == 0) { //Reconnect(opt); close(s); return 0; } else { //n = WSAGetLastError(); close(s); return (!errno + 1); } } return total; } char get_new_image() { SOCKET sock; char buff[1024]; unsigned char search[] = {0x0D, 0x0A, 0x0D, 0x0A}; unsigned char *p = NULL; int len; FILE *f; if (!(sock = tcp_client("ito.osu.ru", 80))) return 0; len = sprintf(buff, "GET /termometr/curr_temp_graph.php?color=255,255,255&bgcolor=0,0,0 HTTP/1.0\r\n\ Host: ito.osu.ru\r\n\ User-agent: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6\r\n\ Accept: image/*;q=0.9\r\n\ Referer: http://osu.ru/\r\n\ Connection: close\r\n\r\n"); tcp_rs(SEND, sock, buff, len, 0); len = recv(sock, buff, sizeof (buff), MSG_PEEK); // балин хз tcp_rs(RECV, sock, buff, len, 0); close(sock); // самая волшебная часть ) // зная размер пакета мы находим окончание заголовка \r\n\r\n = 0x0D, 0x0A, 0x0D, 0x0A p = memmem(buff, len, search, sizeof (search)); if (p != NULL) { p += 4; len -= (int) p - (int) buff; // вычитаем заголовок из общей длины f = fopen(FILE_IMG, "w"); fwrite(p, 1, len, f); fclose(f); return 1; } return 0; } GtkWidget *image, *event_box; static EggTrayIcon *docklet = NULL; void replace_img(char r) { if (r) gtk_container_remove(GTK_CONTAINER(event_box), image); get_new_image(); image = gtk_image_new_from_file(FILE_IMG); gtk_container_add(GTK_CONTAINER(event_box), image); gtk_widget_show(GTK_WIDGET(image)); } int main(int argc, char** argv) { gtk_init(&argc, &argv); docklet = egg_tray_icon_new("Rigidus"); event_box = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(docklet), event_box); if (!gtk_check_version(2, 4, 0)) { g_object_set(G_OBJECT(event_box), "visible-window", FALSE, NULL); } g_signal_connect(G_OBJECT(event_box), "button-press-event", G_CALLBACK(destroy), NULL); replace_img(0); gtk_widget_show_all(GTK_WIDGET(docklet)); gtk_main(); return (EXIT_SUCCESS); }
Для того чтобы все это скомпилировать я написал небольшой скрипт
#! /bin/sh gcc `pkg-config --cflags --libs gtk+-2.0` -c main.c gcc `pkg-config --cflags --libs gtk+-2.0` -c eggtrayicon.c gcc `pkg-config --cflags --libs gtk+-2.0` main.o eggtrayicon.o -o main
Вот и все! Оказывается в этом нет ничего сложного. Пока мой апплет умеет показываться в трее и вырубаться по нажатию на нем, но я уже намудрил поток который обновляет картинку раз в 30 секунд (жаль только моргает при прорисовке).
Еще бы найти, как сделать картинку прямиком из буфера да еще с прозрачным фоном... Найти настройки gnome где хранятся системные цвета окошек, написать макросы для преобразования цветов 0x00ffffff в формат 255,255,255...
Но я думаю это того не стоит хех