From 9367618b5763897f9dbb347f2f5f1c71f9b67c28 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Sat, 8 Aug 2009 23:55:05 +0000 Subject: [PATCH] Added a memory and a tasks switcher applets (both not functional yet) --- Makefile | 3 + src/applets/Makefile | 50 ++++++- src/applets/memory.c | 127 ++++++++++++++++ src/applets/project.conf | 12 +- src/applets/tasks.c | 310 +++++++++++++++++++++++++++++++++++++++ src/panel.c | 2 +- 6 files changed, 500 insertions(+), 4 deletions(-) create mode 100644 src/applets/memory.c create mode 100644 src/applets/tasks.c diff --git a/Makefile b/Makefile index b1ec105..12ed15e 100644 --- a/Makefile +++ b/Makefile @@ -29,9 +29,12 @@ dist: $(PACKAGE)-$(VERSION)/src/panel.h \ $(PACKAGE)-$(VERSION)/src/project.conf \ $(PACKAGE)-$(VERSION)/src/applets/clock.c \ + $(PACKAGE)-$(VERSION)/src/applets/cpu.c \ $(PACKAGE)-$(VERSION)/src/applets/lock.c \ $(PACKAGE)-$(VERSION)/src/applets/logout.c \ $(PACKAGE)-$(VERSION)/src/applets/main.c \ + $(PACKAGE)-$(VERSION)/src/applets/memory.c \ + $(PACKAGE)-$(VERSION)/src/applets/tasks.c \ $(PACKAGE)-$(VERSION)/src/applets/project.conf \ $(PACKAGE)-$(VERSION)/Makefile \ $(PACKAGE)-$(VERSION)/project.conf diff --git a/src/applets/Makefile b/src/applets/Makefile index abfa6bc..1d50c42 100644 --- a/src/applets/Makefile +++ b/src/applets/Makefile @@ -1,4 +1,4 @@ -TARGETS = clock.a clock.so cpu.a cpu.so lock.a lock.so logout.a logout.so main.a main.so +TARGETS = clock.a clock.so cpu.a cpu.so lock.a lock.so logout.a logout.so main.a main.so memory.a memory.so tasks.a tasks.so PREFIX = /usr/local DESTDIR = LIBDIR = $(PREFIX)/lib @@ -73,6 +73,28 @@ main.a: $(main_OBJS) main.so: $(main_OBJS) $(LD) -o main.so -Wl,-soname,main.so.0 $(main_OBJS) +memory_OBJS = memory.o +memory_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) +memory_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) + +memory.a: $(memory_OBJS) + $(AR) memory.a $(memory_OBJS) + $(RANLIB) memory.a + +memory.so: $(memory_OBJS) + $(LD) -o memory.so -Wl,-soname,memory.so.0 $(memory_OBJS) + +tasks_OBJS = tasks.o +tasks_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) +tasks_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) + +tasks.a: $(tasks_OBJS) + $(AR) tasks.a $(tasks_OBJS) + $(RANLIB) tasks.a + +tasks.so: $(tasks_OBJS) + $(LD) -o tasks.so -Wl,-soname,tasks.so.0 $(tasks_OBJS) + clock.o: clock.c $(CC) $(clock_CFLAGS) -c clock.c @@ -88,8 +110,14 @@ logout.o: logout.c main.o: main.c $(CC) $(main_CFLAGS) -c main.c +memory.o: memory.c + $(CC) $(memory_CFLAGS) -c memory.c + +tasks.o: tasks.c + $(CC) $(tasks_CFLAGS) -c tasks.c + clean: - $(RM) $(clock_OBJS) $(cpu_OBJS) $(lock_OBJS) $(logout_OBJS) $(main_OBJS) + $(RM) $(clock_OBJS) $(cpu_OBJS) $(lock_OBJS) $(logout_OBJS) $(main_OBJS) $(memory_OBJS) $(tasks_OBJS) distclean: clean $(RM) $(TARGETS) @@ -120,6 +148,16 @@ install: all $(INSTALL) -m 0755 main.so $(DESTDIR)$(LIBDIR)/Panel/applets/main.so.0.0 $(LN) -s main.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/main.so.0 $(LN) -s main.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/main.so + $(MKDIR) $(DESTDIR)$(LIBDIR)/Panel/applets + $(INSTALL) -m 0644 memory.a $(DESTDIR)$(LIBDIR)/Panel/applets/memory.a + $(INSTALL) -m 0755 memory.so $(DESTDIR)$(LIBDIR)/Panel/applets/memory.so.0.0 + $(LN) -s memory.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/memory.so.0 + $(LN) -s memory.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/memory.so + $(MKDIR) $(DESTDIR)$(LIBDIR)/Panel/applets + $(INSTALL) -m 0644 tasks.a $(DESTDIR)$(LIBDIR)/Panel/applets/tasks.a + $(INSTALL) -m 0755 tasks.so $(DESTDIR)$(LIBDIR)/Panel/applets/tasks.so.0.0 + $(LN) -s tasks.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/tasks.so.0 + $(LN) -s tasks.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/tasks.so uninstall: $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/clock.a @@ -142,5 +180,13 @@ uninstall: $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/main.so.0.0 $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/main.so.0 $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/main.so + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/memory.a + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/memory.so.0.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/memory.so.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/memory.so + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/tasks.a + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/tasks.so.0.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/tasks.so.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/tasks.so .PHONY: all clean distclean install uninstall diff --git a/src/applets/memory.c b/src/applets/memory.c new file mode 100644 index 0000000..e90c977 --- /dev/null +++ b/src/applets/memory.c @@ -0,0 +1,127 @@ +/* $Id$ */ +/* Copyright (c) 2009 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Panel */ +/* This program 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, version 3 of the License. + * + * This program 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 this program. If not, see . */ + + + +#include +#include +#include +#include +#ifdef __NetBSD__ +# include +#endif +#include "panel.h" +#include "../../config.h" + + +/* Memory */ +/* private */ +/* types */ +typedef struct _Memory +{ + GtkWidget * scale; + guint timeout; +} Memory; + + +/* prototypes */ +static GtkWidget * _memory_init(PanelApplet * applet); +static void _memory_destroy(PanelApplet * applet); + +/* callbacks */ +static gboolean _on_timeout(gpointer data); + + +/* public */ +/* variables */ +PanelApplet applet = +{ + NULL, + _memory_init, + _memory_destroy, + PANEL_APPLET_POSITION_END, + NULL +}; + + +/* private */ +/* functions */ +/* memory_init */ +static GtkWidget * _memory_init(PanelApplet * applet) +{ + GtkWidget * ret; + Memory * memory; + PangoFontDescription * desc; + GtkWidget * widget; + + if((memory = malloc(sizeof(*memory))) == NULL) + return NULL; + applet->priv = memory; + ret = gtk_hbox_new(FALSE, 0); + desc = pango_font_description_new(); + pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); + widget = gtk_label_new("RAM:"); + gtk_widget_modify_font(widget, desc); + gtk_box_pack_start(GTK_BOX(ret), widget, FALSE, FALSE, 0); + memory->scale = gtk_vscale_new_with_range(0, 100, 1); + gtk_widget_set_sensitive(memory->scale, FALSE); + gtk_range_set_inverted(GTK_RANGE(memory->scale), TRUE); + gtk_scale_set_value_pos(GTK_SCALE(memory->scale), GTK_POS_RIGHT); + gtk_box_pack_start(GTK_BOX(ret), memory->scale, FALSE, FALSE, 0); + memory->timeout = g_timeout_add(500, _on_timeout, memory); + _on_timeout(memory); + pango_font_description_free(desc); + return ret; +} + + +/* memory_destroy */ +static void _memory_destroy(PanelApplet * applet) +{ + Memory * memory = applet->priv; + + g_source_remove(memory->timeout); + free(memory); +} + + +/* callbacks */ +/* on_timeout */ +static gboolean _on_timeout(gpointer data) +{ +#if 0 /* def __NetBSD__ */ + Memory * memory = data; + int mib[] = { CTL_KERN, KERN_CP_TIME }; + uint64_t memory_time[CPUSTATES]; + size_t size = sizeof(memory_time); + int used; + int total; + gdouble value; + + if(sysctl(mib, 2, &memory_time, &size, NULL, 0) < 0) + return TRUE; + used = memory_time[CP_USER] + memory_time[CP_SYS] + memory_time[CP_NICE] + + memory_time[CP_INTR]; + total = used + memory_time[CP_IDLE]; + if(memory->used == 0) + value = 0; + else + value = 100 * (used - memory->used) / (total - memory->total); + memory->used = used; + memory->total = total; + gtk_range_set_value(GTK_RANGE(memory->scale), value); +#endif + return TRUE; +} diff --git a/src/applets/project.conf b/src/applets/project.conf index 4bee846..182285b 100644 --- a/src/applets/project.conf +++ b/src/applets/project.conf @@ -1,4 +1,4 @@ -targets=clock,cpu,lock,logout,main +targets=clock,cpu,lock,logout,main,memory,tasks cppflags_force=-I ../../include cflags_force=`pkg-config --cflags gtk+-2.0` -fPIC cflags=-Wall -g -O2 -pedantic @@ -29,3 +29,13 @@ type=library sources=main.c #cppflags=-D PREFIX=\"$(PREFIX)\" install=$(LIBDIR)/Panel/applets + +[memory] +type=library +sources=memory.c +install=$(LIBDIR)/Panel/applets + +[tasks] +type=library +sources=tasks.c +install=$(LIBDIR)/Panel/applets diff --git a/src/applets/tasks.c b/src/applets/tasks.c new file mode 100644 index 0000000..020d5a6 --- /dev/null +++ b/src/applets/tasks.c @@ -0,0 +1,310 @@ +/* $Id$ */ +/* Copyright (c) 2009 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Panel */ +/* This program 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, version 3 of the License. + * + * This program 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 this program. If not, see . */ + + + +#include +#include +#include +#include +#include +#include +#include "panel.h" +#include "../../config.h" + + +/* Tasks */ +/* private */ +/* types */ +typedef enum _TasksAtom +{ + TASKS_ATOM_NET_CLIENT_LIST = 0, + TASKS_ATOM_NET_WM_VISIBLE_NAME, + TASKS_ATOM_NET_WM_NAME, + TASKS_ATOM_UTF8_STRING +} TasksAtom; +#define TASKS_ATOM_LAST TASKS_ATOM_UTF8_STRING +#define TASKS_ATOM_COUNT (TASKS_ATOM_LAST + 1) + +typedef struct _Tasks +{ + GtkWidget * hbox; + + Atom atom[TASKS_ATOM_COUNT]; + GdkDisplay * display; + GdkScreen * screen; + GdkWindow * root; +} Tasks; + + +/* constants */ +static const char * _tasks_atom[TASKS_ATOM_COUNT] = +{ + "_NET_CLIENT_LIST", + "_NET_WM_VISIBLE_NAME", + "_NET_WM_NAME", + "UTF8_STRING" +}; + + +/* prototypes */ +static GtkWidget * _tasks_init(PanelApplet * applet); +static void _tasks_destroy(PanelApplet * applet); + +/* accessors */ +static int _tasks_get_text_property(Tasks * tasks, Window window, Atom property, + char ** ret); +static int _tasks_get_window_property(Tasks * tasks, Window window, + TasksAtom property, Atom atom, unsigned long * cnt, + unsigned char ** ret); + +/* useful */ +static void _tasks_do(Tasks * tasks); + +/* callbacks */ +static GdkFilterReturn _on_filter(GdkXEvent * xevent, GdkEvent * event, + gpointer data); +void _on_screen_changed(GtkWidget * widget, GdkScreen * previous, + gpointer data); + + +/* public */ +/* variables */ +PanelApplet applet = +{ + NULL, + _tasks_init, + _tasks_destroy, + PANEL_APPLET_POSITION_START, + NULL +}; + + +/* private */ +/* functions */ +/* tasks_init */ +static GtkWidget * _tasks_init(PanelApplet * applet) +{ + Tasks * tasks; + + if((tasks = malloc(sizeof(*tasks))) == NULL) + return NULL; + applet->priv = tasks; + tasks->hbox = gtk_hbox_new(FALSE, 0); + g_signal_connect(G_OBJECT(tasks->hbox), "screen-changed", G_CALLBACK( + _on_screen_changed), tasks); + tasks->display = NULL; + tasks->screen = NULL; + tasks->root = NULL; + return tasks->hbox; +} + + +/* tasks_destroy */ +static void _tasks_destroy(PanelApplet * applet) +{ + Tasks * tasks = applet->priv; + + free(tasks); +} + + +/* accessors */ +/* tasks_get_text_property */ +static int _tasks_get_text_property(Tasks * tasks, Window window, + Atom property, char ** ret) +{ + int res; + XTextProperty text; + int cnt; + char ** list; + int i; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(tasks, window, %lu)\n", __func__, property); +#endif + res = XGetTextProperty(GDK_DISPLAY_XDISPLAY(tasks->display), window, + &text, property); + if(res != True) /* XXX why is it not Success? */ + return 1; + cnt = gdk_text_property_to_utf8_list(gdk_x11_xatom_to_atom( + text.encoding), text.format, text.value, + text.nitems, &list); + if(cnt > 0) + { + *ret = list[0]; + for(i = 1; i < cnt; i++) + g_free(list[i]); + g_free(list); + } + else + *ret = NULL; + if(text.value != NULL) + XFree(text.value); + return 0; +} + + +/* tasks_get_window_property */ +static int _tasks_get_window_property(Tasks * tasks, Window window, + TasksAtom property, Atom atom, unsigned long * cnt, + unsigned char ** ret) +{ + int res; + Atom type; + int format; + unsigned long bytes; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(tasks, window, %s, %lu)\n", __func__, + _tasks_atom[property], atom); +#endif + res = XGetWindowProperty(GDK_DISPLAY_XDISPLAY(tasks->display), window, + tasks->atom[property], 0, G_MAXLONG, False, atom, + &type, &format, cnt, &bytes, ret); + if(res != Success) + return 1; + if(type != atom) + { + if(*ret != NULL) + XFree(*ret); + *ret = NULL; + return 1; + } + return 0; +} + + +/* tasks_do */ +static char * _do_name(Tasks * tasks, Window window); +static char * _do_name_text(Tasks * tasks, Window window, Atom property); +static char * _do_name_utf8(Tasks * tasks, Window window, Atom property); + +static void _tasks_do(Tasks * tasks) +{ + unsigned long cnt = 0; + Window * windows = NULL; + unsigned long i; + GdkWindow * window; + char * name; + GtkWidget * widget; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s()\n", __func__); +#endif + if(_tasks_get_window_property(tasks, GDK_WINDOW_XWINDOW(tasks->root), + TASKS_ATOM_NET_CLIENT_LIST, + XA_WINDOW, &cnt, (void*)&windows) + != 0) + return; + for(i = 0; i < cnt; i++) + { + if((window = gdk_window_foreign_new_for_display(tasks->display, + windows[i])) == NULL) + continue; + if(gdk_window_get_type_hint(window) + != GDK_WINDOW_TYPE_HINT_NORMAL) + continue; + if((name = _do_name(tasks, windows[i])) == NULL) + continue; + widget = gtk_button_new_with_label(name); + gtk_widget_set_size_request(widget, 100, -1); + gtk_box_pack_start(GTK_BOX(tasks->hbox), widget, FALSE, TRUE, + 2); + g_free(name); + } +} + +static char * _do_name(Tasks * tasks, Window window) +{ + char * ret; + + if((ret = _do_name_utf8(tasks, window, TASKS_ATOM_NET_WM_VISIBLE_NAME)) + != NULL) + return ret; + if((ret = _do_name_utf8(tasks, window, TASKS_ATOM_NET_WM_NAME)) != NULL) + return ret; + if((ret = _do_name_text(tasks, window, XA_WM_NAME)) != NULL) + return ret; + return g_strdup("(Untitled)"); +} + +static char * _do_name_text(Tasks * tasks, Window window, Atom property) +{ + char * ret = NULL; + + if(_tasks_get_text_property(tasks, window, property, (void*)&ret) != 0) + return NULL; + /* FIXME convert to UTF-8 */ + return ret; +} + +static char * _do_name_utf8(Tasks * tasks, Window window, Atom property) +{ + char * ret = NULL; + char * str = NULL; + unsigned long cnt = 0; + + if(_tasks_get_window_property(tasks, window, property, + tasks->atom[TASKS_ATOM_UTF8_STRING], &cnt, + (void*)&str) != 0) + return NULL; + if(g_utf8_validate(str, cnt, NULL)) + ret = g_strndup(str, cnt); + XFree(str); + return ret; +} + + +/* callbacks */ +/* on_filter */ +static GdkFilterReturn _on_filter(GdkXEvent * xevent, GdkEvent * event, + gpointer data) +{ + Tasks * tasks = data; + XEvent * xev = xevent; + + if(xev->type != PropertyNotify) + return GDK_FILTER_CONTINUE; + if(xev->xproperty.atom != tasks->atom[TASKS_ATOM_NET_CLIENT_LIST]) + return GDK_FILTER_CONTINUE; + _tasks_do(tasks); + return GDK_FILTER_CONTINUE; +} + + +/* on_screen_changed */ +void _on_screen_changed(GtkWidget * widget, GdkScreen * previous, gpointer data) +{ + Tasks * tasks = data; + GdkEventMask events; + size_t i; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s()\n", __func__); +#endif + tasks->screen = gtk_widget_get_screen(widget); + tasks->display = gdk_screen_get_display(tasks->screen); + tasks->root = gdk_screen_get_root_window(tasks->screen); + events = gdk_window_get_events(tasks->root); + gdk_window_set_events(tasks->root, events + | GDK_PROPERTY_CHANGE_MASK); + gdk_window_add_filter(tasks->root, _on_filter, tasks); + /* atoms */ + for(i = 0; i < TASKS_ATOM_COUNT; i++) + tasks->atom[i] = gdk_x11_get_xatom_by_name_for_display( + tasks->display, _tasks_atom[i]); + _tasks_do(tasks); +} diff --git a/src/panel.c b/src/panel.c index b4155f0..75c3e59 100644 --- a/src/panel.c +++ b/src/panel.c @@ -119,7 +119,7 @@ static gboolean _on_idle(gpointer data) Panel * panel = data; /* FIXME load all plugins, a configuration file or ask the user */ const char * plugins[] = { "cpu", "clock", "lock", "logout", "main", - NULL }; + "memory", "tasks", NULL }; size_t i; Plugin * plugin; PanelApplet * applet;