diff --git a/Makefile b/Makefile index 9acbd63..b1ec105 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ PACKAGE = Panel VERSION = 0.0.0 -SUBDIRS = src +SUBDIRS = include src RM = rm -f LN = ln -f TAR = tar -czvf @@ -21,11 +21,18 @@ dist: $(RM) -r $(PACKAGE)-$(VERSION) $(LN) -s . $(PACKAGE)-$(VERSION) @$(TAR) $(PACKAGE)-$(VERSION).tar.gz \ + $(PACKAGE)-$(VERSION)/include/panel.h \ + $(PACKAGE)-$(VERSION)/include/project.conf \ $(PACKAGE)-$(VERSION)/src/panel.c \ $(PACKAGE)-$(VERSION)/src/main.c \ $(PACKAGE)-$(VERSION)/src/Makefile \ $(PACKAGE)-$(VERSION)/src/panel.h \ $(PACKAGE)-$(VERSION)/src/project.conf \ + $(PACKAGE)-$(VERSION)/src/applets/clock.c \ + $(PACKAGE)-$(VERSION)/src/applets/lock.c \ + $(PACKAGE)-$(VERSION)/src/applets/logout.c \ + $(PACKAGE)-$(VERSION)/src/applets/main.c \ + $(PACKAGE)-$(VERSION)/src/applets/project.conf \ $(PACKAGE)-$(VERSION)/Makefile \ $(PACKAGE)-$(VERSION)/project.conf $(RM) $(PACKAGE)-$(VERSION) diff --git a/config.h b/config.h new file mode 100644 index 0000000..3f74f95 --- /dev/null +++ b/config.h @@ -0,0 +1,10 @@ +#define PACKAGE "Panel" +#define VERSION "0.0.0" + +#ifndef PREFIX +# define PREFIX "/usr/local" +#endif + +#ifndef LIBDIR +# define LIBDIR PREFIX "/lib" +#endif diff --git a/include/Makefile b/include/Makefile new file mode 100644 index 0000000..452bda5 --- /dev/null +++ b/include/Makefile @@ -0,0 +1,23 @@ +PREFIX = /usr/local +DESTDIR = +RM = rm -f +LN = ln -f +MKDIR = mkdir -p +INSTALL = install +INCLUDEDIR= $(PREFIX)/include + + +all: + +clean: + +distclean: clean + +install: all + $(MKDIR) $(DESTDIR)$(INCLUDEDIR) + $(INSTALL) -m 0644 panel.h $(DESTDIR)$(INCLUDEDIR)/panel.h + +uninstall: + $(RM) $(DESTDIR)$(INCLUDEDIR)/panel.h + +.PHONY: all clean distclean install uninstall diff --git a/include/panel.h b/include/panel.h new file mode 100644 index 0000000..744bd87 --- /dev/null +++ b/include/panel.h @@ -0,0 +1,57 @@ +/* $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 . */ + + + +#ifndef PANEL_PANEL_H +# define PANEL_PANEL_H + +# include +# include + + +/* PanelApplet */ +/* types */ +typedef struct _PanelApplet PanelApplet; + +typedef struct _PanelAppletHelper +{ + void * priv; + int (*logout_dialog)(void); + void (*position_menu)(GtkMenu * menu, gint * x, gint * y, + gboolean * push_in, gpointer data); +} PanelAppletHelper; + +typedef GtkWidget * (*PanelAppletInitFunc)(PanelApplet * applet); +typedef void (*PanelAppletDestroyFunc)(PanelApplet * applet); + +typedef enum _PanelAppletPosition +{ + PANEL_APPLET_POSITION_START = 0, + PANEL_APPLET_POSITION_END, + PANEL_APPLET_POSITION_FIRST, + PANEL_APPLET_POSITION_LAST +} PanelAppletPosition; + +struct _PanelApplet +{ + PanelAppletHelper * helper; + PanelAppletInitFunc init; + PanelAppletDestroyFunc destroy; + PanelAppletPosition position; + void * priv; +}; + +#endif /* !PANEL_PANEL_H */ diff --git a/include/project.conf b/include/project.conf new file mode 100644 index 0000000..5be9d55 --- /dev/null +++ b/include/project.conf @@ -0,0 +1 @@ +includes=panel.h diff --git a/project.conf b/project.conf index f0acc6c..174b1ff 100644 --- a/project.conf +++ b/project.conf @@ -1,5 +1,6 @@ package=Panel version=0.0.0 +config=h -subdirs=src +subdirs=include,src dist=Makefile diff --git a/src/Makefile b/src/Makefile index 43a9951..cec331a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,9 +1,10 @@ +SUBDIRS = applets TARGETS = panel PREFIX = /usr/local DESTDIR = BINDIR = $(PREFIX)/bin CC = cc -CPPFLAGSF= +CPPFLAGSF= -I ../include CPPFLAGS= CFLAGSF = -W `pkg-config gtk+-2.0 --cflags` CFLAGS = -Wall -g -O2 -pedantic @@ -14,7 +15,10 @@ MKDIR = mkdir -p INSTALL = install -all: $(TARGETS) +all: subdirs $(TARGETS) + +subdirs: + @for i in $(SUBDIRS); do (cd $$i && $(MAKE)) || exit; done panel_OBJS = panel.o main.o panel_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) -D PREFIX=\"$(PREFIX)\" $(CFLAGSF) $(CFLAGS) @@ -23,23 +27,28 @@ panel_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) panel: $(panel_OBJS) $(CC) -o panel $(panel_OBJS) $(panel_LDFLAGS) -panel.o: panel.c panel.h +panel.o: panel.c common.h ../include/panel.h $(CC) $(panel_CFLAGS) -c panel.c -main.o: main.c panel.h +main.o: main.c common.h $(CC) $(panel_CFLAGS) -c main.c clean: + @for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean) || exit; done $(RM) $(panel_OBJS) -distclean: clean +distclean: + @for i in $(SUBDIRS); do (cd $$i && $(MAKE) distclean) || exit; done + $(RM) $(panel_OBJS) $(RM) $(TARGETS) install: all + @for i in $(SUBDIRS); do (cd $$i && $(MAKE) install) || exit; done $(MKDIR) $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 panel $(DESTDIR)$(BINDIR)/panel uninstall: + @for i in $(SUBDIRS); do (cd $$i && $(MAKE) uninstall) || exit; done $(RM) $(DESTDIR)$(BINDIR)/panel -.PHONY: all clean distclean install uninstall +.PHONY: all subdirs clean distclean install uninstall diff --git a/src/applets/Makefile b/src/applets/Makefile new file mode 100644 index 0000000..3e706cd --- /dev/null +++ b/src/applets/Makefile @@ -0,0 +1,123 @@ +TARGETS = clock.a clock.so lock.a lock.so logout.a logout.so main.a main.so +PREFIX = /usr/local +DESTDIR = +LIBDIR = $(PREFIX)/lib +CC = cc +CPPFLAGSF= -I ../../include +CPPFLAGS= +CFLAGSF = `pkg-config --cflags gtk+-2.0` -fPIC +CFLAGS = -Wall -g -O2 -pedantic +AR = ar -rc +RANLIB = ranlib +LD = $(CC) -shared +RM = rm -f +LN = ln -f +MKDIR = mkdir -p +INSTALL = install + + +all: $(TARGETS) + +clock_OBJS = clock.o +clock_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) +clock_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) + +clock.a: $(clock_OBJS) + $(AR) clock.a $(clock_OBJS) + $(RANLIB) clock.a + +clock.so: $(clock_OBJS) + $(LD) -o clock.so -Wl,-soname,clock.so.0 $(clock_OBJS) + +lock_OBJS = lock.o +lock_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) +lock_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) + +lock.a: $(lock_OBJS) + $(AR) lock.a $(lock_OBJS) + $(RANLIB) lock.a + +lock.so: $(lock_OBJS) + $(LD) -o lock.so -Wl,-soname,lock.so.0 $(lock_OBJS) + +logout_OBJS = logout.o +logout_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) +logout_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) + +logout.a: $(logout_OBJS) + $(AR) logout.a $(logout_OBJS) + $(RANLIB) logout.a + +logout.so: $(logout_OBJS) + $(LD) -o logout.so -Wl,-soname,logout.so.0 $(logout_OBJS) + +main_OBJS = main.o +main_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) +main_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) + +main.a: $(main_OBJS) + $(AR) main.a $(main_OBJS) + $(RANLIB) main.a + +main.so: $(main_OBJS) + $(LD) -o main.so -Wl,-soname,main.so.0 $(main_OBJS) + +clock.o: clock.c + $(CC) $(clock_CFLAGS) -c clock.c + +lock.o: lock.c + $(CC) $(lock_CFLAGS) -c lock.c + +logout.o: logout.c + $(CC) $(logout_CFLAGS) -c logout.c + +main.o: main.c + $(CC) $(main_CFLAGS) -c main.c + +clean: + $(RM) $(clock_OBJS) $(lock_OBJS) $(logout_OBJS) $(main_OBJS) + +distclean: clean + $(RM) $(TARGETS) + +install: all + $(MKDIR) $(DESTDIR)$(LIBDIR)/Panel/applets + $(INSTALL) -m 0644 clock.a $(DESTDIR)$(LIBDIR)/Panel/applets/clock.a + $(INSTALL) -m 0755 clock.so $(DESTDIR)$(LIBDIR)/Panel/applets/clock.so.0.0 + $(LN) -s clock.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/clock.so.0 + $(LN) -s clock.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/clock.so + $(MKDIR) $(DESTDIR)$(LIBDIR)/Panel/applets + $(INSTALL) -m 0644 lock.a $(DESTDIR)$(LIBDIR)/Panel/applets/lock.a + $(INSTALL) -m 0755 lock.so $(DESTDIR)$(LIBDIR)/Panel/applets/lock.so.0.0 + $(LN) -s lock.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/lock.so.0 + $(LN) -s lock.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/lock.so + $(MKDIR) $(DESTDIR)$(LIBDIR)/Panel/applets + $(INSTALL) -m 0644 logout.a $(DESTDIR)$(LIBDIR)/Panel/applets/logout.a + $(INSTALL) -m 0755 logout.so $(DESTDIR)$(LIBDIR)/Panel/applets/logout.so.0.0 + $(LN) -s logout.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/logout.so.0 + $(LN) -s logout.so.0.0 $(DESTDIR)$(LIBDIR)/Panel/applets/logout.so + $(MKDIR) $(DESTDIR)$(LIBDIR)/Panel/applets + $(INSTALL) -m 0644 main.a $(DESTDIR)$(LIBDIR)/Panel/applets/main.a + $(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 + +uninstall: + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/clock.a + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/clock.so.0.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/clock.so.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/clock.so + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/lock.a + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/lock.so.0.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/lock.so.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/lock.so + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/logout.a + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/logout.so.0.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/logout.so.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/logout.so + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/main.a + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/main.so.0.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/main.so.0 + $(RM) $(DESTDIR)$(LIBDIR)/Panel/applets/main.so + +.PHONY: all clean distclean install uninstall diff --git a/src/applets/clock.c b/src/applets/clock.c new file mode 100644 index 0000000..e38545a --- /dev/null +++ b/src/applets/clock.c @@ -0,0 +1,107 @@ +/* $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 "panel.h" +#include "../../config.h" + + +/* Clock */ +/* private */ +/* types */ +typedef struct _Clock +{ + GtkWidget * label; + guint timeout; +} Clock; + + +/* prototypes */ +static GtkWidget * _clock_init(PanelApplet * applet); +static void _clock_destroy(PanelApplet * applet); + +/* callbacks */ +static gboolean _on_timeout(gpointer data); + + +/* public */ +/* variables */ +PanelApplet applet = +{ + NULL, + _clock_init, + _clock_destroy, + PANEL_APPLET_POSITION_END, + NULL +}; + + +/* private */ +/* functions */ +/* clock_init */ +static GtkWidget * _clock_init(PanelApplet * applet) +{ + GtkWidget * ret; + Clock * clock; + + if((clock = malloc(sizeof(*clock))) == NULL) + return NULL; + applet->priv = clock; + ret = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(ret), GTK_SHADOW_IN); + clock->label = gtk_label_new(" \n "); + gtk_label_set_justify(GTK_LABEL(clock->label), GTK_JUSTIFY_CENTER); + gtk_container_add(GTK_CONTAINER(ret), clock->label); + clock->timeout = g_timeout_add(1000, _on_timeout, clock); + _on_timeout(clock); + return ret; +} + + +/* clock_destroy */ +static void _clock_destroy(PanelApplet * applet) +{ + Clock * clock = applet->priv; + + g_source_remove(clock->timeout); + free(clock); +} + + +/* callbacks */ +/* on_timeout */ +static gboolean _on_timeout(gpointer data) +{ + Clock * clock = data; + struct timeval tv; + time_t t; + struct tm tm; + char buf[32]; + + if(gettimeofday(&tv, NULL) != 0) + return error_set_print(PACKAGE, TRUE, "%s: %s", "gettimeofday", + strerror(errno)); + t = tv.tv_sec; + localtime_r(&t, &tm); + strftime(buf, sizeof(buf), "%H:%M:%S\n%d/%m/%Y", &tm); + gtk_label_set_text(GTK_LABEL(clock->label), buf); + return TRUE; +} diff --git a/src/applets/lock.c b/src/applets/lock.c new file mode 100644 index 0000000..d977562 --- /dev/null +++ b/src/applets/lock.c @@ -0,0 +1,71 @@ +/* $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 "panel.h" + + +/* Lock */ +/* private */ +/* prototypes */ +static GtkWidget * _lock_init(PanelApplet * applet); + +/* callbacks */ +static void _on_clicked(GtkWidget * widget, gpointer data); + + +/* public */ +/* variables */ +PanelApplet applet = +{ + NULL, + _lock_init, + NULL, + PANEL_APPLET_POSITION_START, + NULL +}; + + +/* private */ +/* functions */ +/* lock_init */ +static GtkWidget * _lock_init(PanelApplet * applet) +{ + GtkWidget * ret; + GtkWidget * image; + + ret = gtk_button_new(); + image = gtk_image_new_from_icon_name("gnome-lockscreen", + GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_button_set_image(GTK_BUTTON(ret), image); + gtk_button_set_relief(GTK_BUTTON(ret), GTK_RELIEF_NONE); + g_signal_connect(G_OBJECT(ret), "clicked", G_CALLBACK(_on_clicked), + NULL); + return ret; +} + + +/* callbacks */ +/* on_clicked */ +static void _on_clicked(GtkWidget * widget, gpointer data) +{ + char * argv[] = { "xscreensaver-command", "-lock", NULL }; + GSpawnFlags flags = G_SPAWN_SEARCH_PATH + | G_SPAWN_STDOUT_TO_DEV_NULL + | G_SPAWN_STDERR_TO_DEV_NULL; + + g_spawn_async(NULL, argv, NULL, flags, NULL, NULL, NULL, NULL); +} diff --git a/src/applets/logout.c b/src/applets/logout.c new file mode 100644 index 0000000..074cdeb --- /dev/null +++ b/src/applets/logout.c @@ -0,0 +1,68 @@ +/* $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 "panel.h" + + +/* Lock */ +/* private */ +/* prototypes */ +static GtkWidget * _logout_init(PanelApplet * applet); + +/* callbacks */ +static void _on_clicked(GtkWidget * widget, gpointer data); + + +/* public */ +/* variables */ +PanelApplet applet = +{ + NULL, + _logout_init, + NULL, + PANEL_APPLET_POSITION_START, + NULL +}; + + +/* private */ +/* functions */ +/* logout_init */ +static GtkWidget * _logout_init(PanelApplet * applet) +{ + GtkWidget * ret; + GtkWidget * image; + + ret = gtk_button_new(); + image = gtk_image_new_from_icon_name("gnome-logout", + GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_button_set_image(GTK_BUTTON(ret), image); + gtk_button_set_relief(GTK_BUTTON(ret), GTK_RELIEF_NONE); + g_signal_connect(G_OBJECT(ret), "clicked", G_CALLBACK(_on_clicked), + applet); + return ret; +} + + +/* callbacks */ +/* on_clicked */ +static void _on_clicked(GtkWidget * widget, gpointer data) +{ + PanelApplet * applet = data; + + applet->helper->logout_dialog(); +} diff --git a/src/applets/main.c b/src/applets/main.c new file mode 100644 index 0000000..7064154 --- /dev/null +++ b/src/applets/main.c @@ -0,0 +1,438 @@ +/* $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 "panel.h" +#include "../common.h" + + +/* Main */ +/* private */ +/* types */ +typedef struct _Main +{ + PanelAppletHelper * helper; + GSList * apps; + guint idle; +} Main; + +typedef struct _MainMenu +{ + char const * category; + char const * label; + char const * stock; +} MainMenu; + + +/* constants */ +#ifndef PREFIX +# define PREFIX "/usr/local" +#endif + +static const MainMenu _main_menus[] = +{ + { "Audio;", "Audio", NULL, }, + { "Development;","Development", "applications-development", }, + { "Education;", "Education", NULL, }, + { "Game;", "Games", "applications-games", }, + { "Graphics;", "Graphics", "applications-graphics", }, + { "AudioVideo;","Multimedia", "applications-multimedia", }, + { "Network;", "Network", "applications-internet", }, + { "Office;", "Office", "applications-office", }, + { "Settings;", "Settings", "gnome-settings", }, + { "System;", "System", "applications-system", }, + { "Utility;", "Utilities", "applications-utilities", }, + { "Video;", "Video", "video", }, + { NULL, NULL, NULL, } +}; +#define MAIN_MENUS_CNT (sizeof(_main_menus) / sizeof(*_main_menus)) + + +/* prototypes */ +static GtkWidget * _main_init(PanelApplet * applet); +static void _main_destroy(PanelApplet * applet); + +/* helpers */ +static GtkWidget * _main_applications(Main * main); +static GtkWidget * _main_image(char const * name); +static GtkWidget * _main_menuitem(char const * label, char const * stock); + +/* callbacks */ +static void _on_clicked(GtkWidget * widget, gpointer data); +static gboolean _on_idle(gpointer data); +static void _on_lock(GtkWidget * widget, gpointer data); +static void _on_logout(GtkWidget * widget, gpointer data); +static void _on_run(GtkWidget * widget, gpointer data); + + +/* public */ +/* variables */ +PanelApplet applet = +{ + NULL, + _main_init, + _main_destroy, + PANEL_APPLET_POSITION_FIRST, + NULL +}; + + +/* private */ +/* functions */ +/* main_init */ +static GtkWidget * _main_init(PanelApplet * applet) +{ + GtkWidget * ret; + Main * main; + GtkWidget * image; + + if((main = malloc(sizeof(*main))) == NULL) + return NULL; + main->helper = applet->helper; + main->apps = NULL; + main->idle = g_idle_add(_on_idle, main); + applet->priv = main; + ret = gtk_button_new(); + image = gtk_image_new_from_icon_name("gnome-main-menu", + GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_button_set_image(GTK_BUTTON(ret), image); + gtk_button_set_relief(GTK_BUTTON(ret), GTK_RELIEF_NONE); + g_signal_connect(G_OBJECT(ret), "clicked", G_CALLBACK(_on_clicked), + main); + return ret; +} + + +/* main_destroy */ +static void _main_destroy(PanelApplet * applet) +{ + Main * main = applet->priv; + + if(main->idle != 0) + g_source_remove(main->idle); + /* FIXME free main->apps */ + free(main); +} + + +/* helpers */ +/* main_applications */ +static void _applications_on_activate(GtkWidget * widget, gpointer data); +static void _applications_categories(GtkWidget * menu, GtkWidget ** menus); + +static GtkWidget * _main_applications(Main * main) +{ + GtkWidget * menus[MAIN_MENUS_CNT]; + GSList * p; + GtkWidget * menu; + GtkWidget * menuitem; + Config * config; + const char section[] = "Desktop Entry"; + char const * q; + size_t i; + + _on_idle(main); /* just in case */ + memset(menus, 0, sizeof(menus)); + menu = gtk_menu_new(); + for(p = main->apps; p != NULL; p = p->next) + { + config = p->data; + q = config_get(config, section, "Name"); /* should not fail */ + menuitem = _main_menuitem(q, config_get(config, section, + "Icon")); + q = config_get(config, section, "Exec"); /* should not fail */ + g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK( + _applications_on_activate), + (gpointer)q); + if((q = config_get(config, section, "Categories")) == NULL) + { + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + continue; + } + for(i = 0; _main_menus[i].category != NULL && string_find(q, + _main_menus[i].category) == NULL; i++); + if(_main_menus[i].category == NULL) + { + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + continue; + } + if(menus[i] == NULL) + menus[i] = gtk_menu_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(menus[i]), menuitem); + } + _applications_categories(menu, menus); + return menu; +} + +static void _applications_on_activate(GtkWidget * widget, gpointer data) +{ + char const * program = data; + + if(program == NULL) + return; +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() \"%s\"", __func__, program); +#endif + g_spawn_command_line_async(program, NULL); +} + +static void _applications_categories(GtkWidget * menu, GtkWidget ** menus) +{ + size_t i; + MainMenu const * m; + GtkWidget * menuitem; + size_t pos = 0; + + for(i = 0; _main_menus[i].category != NULL; i++) + { + if(menus[i] == NULL) + continue; + m = &_main_menus[i]; + menuitem = _main_menuitem(m->label, m->stock); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menus[i]); + gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menuitem, pos++); + } +} + + +/* main_image */ +static GtkWidget * _main_image(char const * name) +{ + int width; + int height; + size_t len; + String * buf; + GError * error = NULL; + GdkPixbuf * pixbuf = NULL; + + if(gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height) == TRUE + && (name != NULL && (len = strlen(name)) > 4) + && (strcmp(&name[len - 4], ".png") == 0 + || strcmp(&name[len - 4], ".xpm") == 0) + && (buf = string_new_append(PREFIX, "/share/pixmaps/", + name, NULL)) != NULL) + { + pixbuf = gdk_pixbuf_new_from_file_at_size(buf, width, height, + &error); + string_delete(buf); + } + if(pixbuf != NULL) + return gtk_image_new_from_pixbuf(pixbuf); + return gtk_image_new_from_icon_name(name, GTK_ICON_SIZE_MENU); +} + + +/* main_menuitem */ +static GtkWidget * _main_menuitem(char const * label, char const * stock) +{ + GtkWidget * ret; + GtkWidget * image; + + ret = gtk_image_menu_item_new_with_label(label); + if(stock != NULL) + { + image = _main_image(stock); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(ret), image); + } + return ret; +} + + +/* callbacks */ +/* on_idle */ +static gint _idle_apps_compare(gconstpointer a, gconstpointer b); + +static gboolean _on_idle(gpointer data) +{ + Main * main = data; + const char path[] = PREFIX "/share/applications"; + DIR * dir; + struct dirent * de; + size_t len; + const char ext[] = ".desktop"; + const char section[] = "Desktop Entry"; + char * name = NULL; + char * p; + Config * config = NULL; + String const * q; + String const * r; + + if(main->apps != NULL) + return FALSE; + if((dir = opendir(path)) == NULL) + return error_set_print("panel", FALSE, "%s: %s", path, strerror( + errno)); + while((de = readdir(dir)) != NULL) + { + len = strlen(de->d_name); + if(len < sizeof(ext) || strncmp(&de->d_name[len - sizeof(ext) + + 1], ext, sizeof(ext)) != 0) + continue; + if((p = realloc(name, sizeof(path) + len + 1)) == NULL) + { + error_set_print("panel", 1, "%s: %s", "realloc", + strerror(errno)); + continue; + } + name = p; + snprintf(name, sizeof(path) + len + 1, "%s/%s", path, + de->d_name); +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, name); +#endif + if(config == NULL && (config = config_new()) == NULL) + continue; /* XXX report error */ + else + config_reset(config); + if(config_load(config, name) != 0) + { + error_print("panel"); + continue; + } + q = config_get(config, section, "Name"); + r = config_get(config, section, "Exec"); + if(q == NULL || r == NULL) + continue; + main->apps = g_slist_insert_sorted(main->apps, config, + _idle_apps_compare); + config = NULL; + } + free(name); + closedir(dir); + if(config != NULL) + config_delete(config); + return FALSE; +} + +static gint _idle_apps_compare(gconstpointer a, gconstpointer b) +{ + Config * ca = (Config *)a; + Config * cb = (Config *)b; + char const * cap; + char const * cbp; + const char section[] = "Desktop Entry"; + const char variable[] = "Name"; + + /* these should not fail */ + cap = config_get(ca, section, variable); + cbp = config_get(cb, section, variable); + return string_compare(cap, cbp); +} + + +/* on_clicked */ +#if 0 +static void _clicked_menu_position(GtkMenu * menu, gint * x, gint * y, + gboolean * push_in, gpointer data); +#endif + +static void _on_clicked(GtkWidget * widget, gpointer data) +{ + Main * main = data; + GtkWidget * menu; + GtkWidget * menuitem; + + menu = gtk_menu_new(); + menuitem = _main_menuitem("Applications", "gnome-applications"); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), _main_applications( + main)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + menuitem = gtk_separator_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + menuitem = _main_menuitem("Run...", GTK_STOCK_EXECUTE); + g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(_on_run), + data); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + menuitem = gtk_separator_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, + NULL); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + menuitem = gtk_separator_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + menuitem = _main_menuitem("Lock screen", "gnome-lockscreen"); + g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(_on_lock), + data); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + menuitem = _main_menuitem("Logout...", "gnome-logout"); + g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(_on_logout), + data); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + gtk_widget_show_all(menu); + gtk_menu_popup(GTK_MENU(menu), NULL, NULL, main->helper->position_menu, + main->helper->priv, 0, gtk_get_current_event_time()); +} + +#if 0 +static void _clicked_menu_position(GtkMenu * menu, gint * x, gint * y, + gboolean * push_in, gpointer data) +{ + Panel * panel = data; + GtkRequisition req; + + gtk_widget_size_request(GTK_WIDGET(menu), &req); +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() width=%d, height=%d\n", __func__, + req.width, req.height); +#endif + if(req.height <= 0) + return; + *x = PANEL_BORDER_WIDTH; +#if 0 /* FIXME figure a way for this */ + *y = panel->height - PANEL_BORDER_WIDTH - PANEL_ICON_SIZE - req.height; +#else + *y = 1024 - PANEL_BORDER_WIDTH - PANEL_ICON_SIZE - req.height; +#endif + *push_in = TRUE; +} +#endif + + +/* on_lock */ +static void _on_lock(GtkWidget * widget, gpointer data) +{ + char * argv[] = { "xscreensaver-command", "-lock", NULL }; + GSpawnFlags flags = G_SPAWN_SEARCH_PATH + | G_SPAWN_STDOUT_TO_DEV_NULL + | G_SPAWN_STDERR_TO_DEV_NULL; + + g_spawn_async(NULL, argv, NULL, flags, NULL, NULL, NULL, NULL); +} + + +/* on_logout */ +static void _on_logout(GtkWidget * widget, gpointer data) +{ + Main * main = data; + + main->helper->logout_dialog(); +} + + +/* on_run */ +static void _on_run(GtkWidget * widget, gpointer data) +{ + char * argv[] = { "run", NULL }; + GSpawnFlags flags = G_SPAWN_SEARCH_PATH + | G_SPAWN_STDOUT_TO_DEV_NULL + | G_SPAWN_STDERR_TO_DEV_NULL; + + g_spawn_async(NULL, argv, NULL, flags, NULL, NULL, NULL, NULL); +} diff --git a/src/applets/project.conf b/src/applets/project.conf new file mode 100644 index 0000000..582d7be --- /dev/null +++ b/src/applets/project.conf @@ -0,0 +1,25 @@ +targets=clock,lock,logout,main +cppflags_force=-I ../../include +cflags_force=`pkg-config --cflags gtk+-2.0` -fPIC +cflags=-Wall -g -O2 -pedantic + +[clock] +type=library +sources=clock.c +install=$(LIBDIR)/Panel/applets + +[lock] +type=library +sources=lock.c +install=$(LIBDIR)/Panel/applets + +[logout] +type=library +sources=logout.c +install=$(LIBDIR)/Panel/applets + +[main] +type=library +sources=main.c +#cppflags=-D PREFIX=\"$(PREFIX)\" +install=$(LIBDIR)/Panel/applets diff --git a/src/panel.h b/src/common.h similarity index 86% rename from src/panel.h rename to src/common.h index f6f7343..dfed977 100644 --- a/src/panel.h +++ b/src/common.h @@ -15,8 +15,8 @@ -#ifndef PANEL_PANEL_H -# define PANEL_PANEL_H +#ifndef PANEL_COMMON_H +# define PANEL_COMMON_H /* Panel */ @@ -24,6 +24,11 @@ typedef struct _Panel Panel; +/* constants */ +#define PANEL_BORDER_WIDTH 4 +#define PANEL_ICON_SIZE 48 + + /* functions */ Panel * panel_new(void); void panel_delete(Panel * panel); @@ -31,4 +36,4 @@ void panel_delete(Panel * panel); /* useful */ int panel_error(Panel * panel, char const * message, int ret); -# endif /* !PANEL_PANEL_H */ +# endif /* !PANEL_COMMON_H */ diff --git a/src/main.c b/src/main.c index e974a4a..6d4eb8b 100644 --- a/src/main.c +++ b/src/main.c @@ -20,7 +20,7 @@ #include #include #include -#include "panel.h" +#include "common.h" /* usage */ diff --git a/src/panel.c b/src/panel.c index 08c45c1..3f27aba 100644 --- a/src/panel.c +++ b/src/panel.c @@ -16,36 +16,26 @@ #include -#include -#include -#include #include #include #include #include -#include #include #include #include "panel.h" +#include "common.h" +#include "../config.h" /* Panel */ /* private */ /* types */ -typedef struct _PanelMenu -{ - char const * category; - char const * label; - char const * stock; -} PanelMenu; - struct _Panel { - GSList * apps; - + PanelAppletHelper helper; GdkWindow * root; GtkWidget * window; - GtkWidget * clock; + GtkWidget * hbox; gint width; /* width of the root window */ gint height; /* height of the root window */ @@ -56,55 +46,29 @@ struct _Panel #ifndef PREFIX # define PREFIX "/usr/local" #endif -#define PANEL_BORDER_WIDTH 4 -#define PANEL_ICON_SIZE 48 - -static const PanelMenu _panel_menus[] = -{ - { "Audio;", "Audio", NULL, }, - { "Development;","Development", "applications-development", }, - { "Education;", "Education", NULL, }, - { "Game;", "Games", "applications-games", }, - { "Graphics;", "Graphics", "applications-graphics", }, - { "AudioVideo;","Multimedia", "applications-multimedia", }, - { "Network;", "Network", "applications-internet", }, - { "Office;", "Office", "applications-office", }, - { "Settings;", "Settings", "gnome-settings", }, - { "System;", "System", "applications-system", }, - { "Utility;", "Utilities", "applications-utilities", }, - { "Video;", "Video", "video", }, - { NULL, NULL, NULL, } -}; -#define PANEL_MENUS_CNT (sizeof(_panel_menus) / sizeof(*_panel_menus)) +#ifndef LIBDIR +# define LIBDIR PREFIX "/lib" +#endif /* prototypes */ -static int _panel_exec(Panel * panel, char const * command); -static gboolean _panel_idle_apps(gpointer data); -static GtkWidget * _panel_image(char const * name); -static GtkWidget * _panel_menuitem(char const * label, char const * stock); +/* helpers */ +static int _panel_logout_dialog(void); +static void _panel_position_menu(GtkMenu * menu, gint * x, gint * y, + gboolean * push_in, gpointer data); /* public */ /* panel_new */ -static GtkWidget * _new_button(char const * stock); +static gboolean _on_idle(gpointer data); static gboolean _on_button_press(GtkWidget * widget, GdkEventButton * event, gpointer data); static gboolean _on_closex(GtkWidget * widget, GdkEvent * event, gpointer data); -static void _on_lock(GtkWidget * widget, gpointer data); -static void _on_logout(GtkWidget * widget, gpointer data); -static void _on_menu(GtkWidget * widget, gpointer data); -static void _on_menu_position(GtkMenu * menu, gint * x, gint * y, - gboolean * push_in, gpointer data); -static void _on_run(GtkWidget * widget, gpointer data); -static gboolean _on_timeout_clock(gpointer data); Panel * panel_new(void) { Panel * panel; GtkWidget * event; - GtkWidget * hbox; - GtkWidget * widget; gint x; gint y; gint depth; @@ -115,9 +79,9 @@ Panel * panel_new(void) panel_error(NULL, "malloc", 1); return NULL; } - /* applications */ - panel->apps = NULL; - g_idle_add(_panel_idle_apps, panel); + panel->helper.priv = panel; + panel->helper.logout_dialog = _panel_logout_dialog; + panel->helper.position_menu = _panel_position_menu; /* root window */ panel->root = gdk_screen_get_root_window( gdk_display_get_default_screen( @@ -129,6 +93,7 @@ Panel * panel_new(void) __func__, x, y, panel->width, panel->height, depth); #endif /* panel */ + g_idle_add(_on_idle, panel); panel->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(panel->window), panel->width, PANEL_ICON_SIZE + (PANEL_BORDER_WIDTH * 2)); @@ -141,48 +106,51 @@ Panel * panel_new(void) event = gtk_event_box_new(); g_signal_connect(G_OBJECT(event), "button-press-event", G_CALLBACK( _on_button_press), panel); - hbox = gtk_hbox_new(FALSE, 4); - /* main menu */ - widget = _new_button("gnome-main-menu"); - g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(_on_menu), - panel); - gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); - /* quick launch */ - widget = _new_button("gnome-lockscreen"); - g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(_on_lock), - panel); - gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); - widget = _new_button("gnome-logout"); - g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(_on_logout), - panel); - gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); - /* clock */ - widget = gtk_frame_new(NULL); - gtk_frame_set_shadow_type(GTK_FRAME(widget), GTK_SHADOW_IN); - panel->clock = gtk_label_new(" \n "); - gtk_label_set_justify(GTK_LABEL(panel->clock), GTK_JUSTIFY_CENTER); - g_timeout_add(1000, _on_timeout_clock, panel); - _on_timeout_clock(panel); - gtk_container_add(GTK_CONTAINER(widget), panel->clock); - gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 0); - gtk_container_add(GTK_CONTAINER(event), hbox); + panel->hbox = gtk_hbox_new(FALSE, 2); + gtk_container_add(GTK_CONTAINER(event), panel->hbox); gtk_container_add(GTK_CONTAINER(panel->window), event); gtk_container_set_border_width(GTK_CONTAINER(panel->window), 4); gtk_widget_show_all(panel->window); return panel; } -static GtkWidget * _new_button(char const * stock) +static gboolean _on_idle(gpointer data) { - GtkWidget * button; - GtkWidget * image; + Panel * panel = data; + /* FIXME load all plugins, a configuration file or ask the user */ + const char * plugins[] = { "main", "lock", "logout", "clock", NULL }; + size_t i; + Plugin * plugin; + PanelApplet * applet; + GtkWidget * widget; - button = gtk_button_new(); - image = gtk_image_new_from_icon_name(stock, - GTK_ICON_SIZE_LARGE_TOOLBAR); - gtk_button_set_image(GTK_BUTTON(button), image); - gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); - return button; + for(i = 0; plugins[i] != NULL; i++) + if((plugin = plugin_new(LIBDIR, PACKAGE, "applets", plugins[i])) + != NULL + && (applet = plugin_lookup(plugin, "applet")) + != NULL + && (applet->helper = &panel->helper) != NULL + && applet->init != NULL + && (widget = applet->init(applet)) != NULL) + { + switch(applet->position) + { + case PANEL_APPLET_POSITION_START: /* XXX */ + case PANEL_APPLET_POSITION_FIRST: + gtk_box_pack_start(GTK_BOX(panel->hbox), + widget, FALSE, TRUE, 2); + break; + case PANEL_APPLET_POSITION_END: /* XXX */ + case PANEL_APPLET_POSITION_LAST: + gtk_box_pack_end(GTK_BOX(panel->hbox), + widget, FALSE, TRUE, 2); + break; + } + gtk_widget_show_all(widget); + } + else + error_print(PACKAGE); + return FALSE; } static gboolean _on_button_press(GtkWidget * widget, GdkEventButton * event, @@ -214,197 +182,11 @@ static gboolean _on_closex(GtkWidget * widget, GdkEvent * event, gpointer data) return TRUE; } -static void _on_lock(GtkWidget * widget, gpointer data) -{ - Panel * panel = data; - - _panel_exec(panel, "xscreensaver-command -lock"); -} - -static void _on_logout(GtkWidget * widget, gpointer data) -{ - GtkWidget * dialog; - const char message[] = "This will log you out of the current session," - " therefore closing any application currently opened and losing" - " any unsaved data.\nDo you really want to proceed?"; - int res; - - dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_WARNING, - GTK_BUTTONS_NONE, "%s", message); - gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, "Logout", GTK_RESPONSE_ACCEPT, - NULL); - gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ALWAYS); - gtk_window_set_title(GTK_WINDOW(dialog), "Warning"); - res = gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - if(res != GTK_RESPONSE_ACCEPT) - return; - gtk_main_quit(); -} - -static GtkWidget * _menu_applications(Panel * panel); -static void _applications_on_activate(GtkWidget * widget, gpointer data); -static void _applications_categories(GtkWidget * menu, GtkWidget ** menus); -static void _on_menu(GtkWidget * widget, gpointer data) -{ - Panel * panel = data; - GtkWidget * menu; - GtkWidget * menuitem; - - menu = gtk_menu_new(); - menuitem = _panel_menuitem("Applications", "gnome-applications"); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), - _menu_applications(panel)); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - menuitem = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - menuitem = _panel_menuitem("Run...", GTK_STOCK_EXECUTE); - g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(_on_run), - data); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - menuitem = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, - NULL); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - menuitem = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - menuitem = _panel_menuitem("Lock screen", "gnome-lockscreen"); - g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(_on_lock), - data); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - menuitem = _panel_menuitem("Logout...", "gnome-logout"); - g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(_on_logout), - data); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - gtk_widget_show_all(menu); - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, _on_menu_position, data, 0, - gtk_get_current_event_time()); -} - -static GtkWidget * _menu_applications(Panel * panel) -{ - GtkWidget * menus[PANEL_MENUS_CNT]; - GSList * p; - GtkWidget * menu; - GtkWidget * menuitem; - Config * config; - const char section[] = "Desktop Entry"; - char const * q; - size_t i; - - _panel_idle_apps(panel); /* just in case */ - memset(menus, 0, sizeof(menus)); - menu = gtk_menu_new(); - for(p = panel->apps; p != NULL; p = p->next) - { - config = p->data; - q = config_get(config, section, "Name"); /* should not fail */ - menuitem = _panel_menuitem(q, config_get(config, section, - "Icon")); - q = config_get(config, section, "Exec"); /* should not fail */ - g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK( - _applications_on_activate), - (gpointer)q); - if((q = config_get(config, section, "Categories")) == NULL) - { - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - continue; - } - for(i = 0; _panel_menus[i].category != NULL && string_find(q, - _panel_menus[i].category) == NULL; i++); - if(_panel_menus[i].category == NULL) - { - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - continue; - } - if(menus[i] == NULL) - menus[i] = gtk_menu_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(menus[i]), menuitem); - } - _applications_categories(menu, menus); - return menu; -} - -static void _applications_on_activate(GtkWidget * widget, gpointer data) -{ - char const * program = data; - - if(program == NULL) - return; -#ifdef DEBUG - fprintf(stderr, "DEBUG: %s() \"%s\"", __func__, program); -#endif - _panel_exec(NULL, program); -} - -static void _applications_categories(GtkWidget * menu, GtkWidget ** menus) -{ - size_t i; - const PanelMenu * m; - GtkWidget * menuitem; - size_t pos = 0; - - for(i = 0; _panel_menus[i].category != NULL; i++) - { - if(menus[i] == NULL) - continue; - m = &_panel_menus[i]; - menuitem = _panel_menuitem(m->label, m->stock); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menus[i]); - gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menuitem, pos++); - } -} - -static void _on_menu_position(GtkMenu * menu, gint * x, gint * y, - gboolean * push_in, gpointer data) -{ - Panel * panel = data; - GtkRequisition req; - - gtk_widget_size_request(GTK_WIDGET(menu), &req); -#ifdef DEBUG - fprintf(stderr, "DEBUG: %s() width=%d, height=%d\n", __func__, - req.width, req.height); -#endif - if(req.height <= 0) - return; - *x = PANEL_BORDER_WIDTH; - *y = panel->height - PANEL_BORDER_WIDTH - PANEL_ICON_SIZE - req.height; - *push_in = TRUE; -} - -static void _on_run(GtkWidget * widget, gpointer data) -{ - Panel * panel = data; - - _panel_exec(panel, "run"); -} - -static gboolean _on_timeout_clock(gpointer data) -{ - Panel * panel = data; - struct timeval tv; - time_t t; - struct tm tm; - char buf[32]; - - if(gettimeofday(&tv, NULL) != 0) - return panel_error(panel, "gettimeofday", TRUE); - t = tv.tv_sec; - localtime_r(&t, &tm); - strftime(buf, sizeof(buf), "%H:%M:%S\n%d/%m/%Y", &tm); - gtk_label_set_text(GTK_LABEL(panel->clock), buf); - return TRUE; -} - /* panel_delete */ void panel_delete(Panel * panel) { - /* FIXME delete panel->apps */ + /* FIXME destroy plugins */ free(panel); } @@ -437,139 +219,48 @@ static int _error_text(char const * message, int ret) /* private */ /* functions */ -/* panel_exec */ -static int _panel_exec(Panel * panel, char const * command) +/* helpers */ +/* panel_logout_dialog */ +static int _panel_logout_dialog(void) { - pid_t pid; + GtkWidget * dialog; + const char message[] = "This will log you out of the current session," + " therefore closing any application currently opened and losing" + " any unsaved data.\nDo you really want to proceed?"; + int res; - if((pid = fork()) == -1) - return panel_error(panel, "fork", 1); - else if(pid != 0) /* the parent returns */ - return 0; - execlp("/bin/sh", "sh", "-c", command, NULL); - exit(panel_error(NULL, command, 2)); - return 1; + dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, "%s", message); + gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, "Logout", GTK_RESPONSE_ACCEPT, + NULL); + gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ALWAYS); + gtk_window_set_title(GTK_WINDOW(dialog), "Warning"); + res = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + if(res != GTK_RESPONSE_ACCEPT) + return 1; + gtk_main_quit(); + return 0; } -/* callbacks */ -/* panel_idle_apps */ -static gint _apps_compare(gconstpointer a, gconstpointer b); - -static gboolean _panel_idle_apps(gpointer data) +/* panel_position_menu */ +static void _panel_position_menu(GtkMenu * menu, gint * x, gint * y, + gboolean * push_in, gpointer data) { Panel * panel = data; - const char path[] = PREFIX "/share/applications"; - DIR * dir; - struct dirent * de; - size_t len; - const char ext[] = ".desktop"; - const char section[] = "Desktop Entry"; - char * name = NULL; - char * p; - Config * config = NULL; - String const * q; - String const * r; + GtkRequisition req; - if(panel->apps != NULL) - return FALSE; - if((dir = opendir(path)) == NULL) - return panel_error(panel, path, FALSE); - while((de = readdir(dir)) != NULL) - { - len = strlen(de->d_name); - if(len < sizeof(ext) || strncmp(&de->d_name[len - sizeof(ext) - + 1], ext, sizeof(ext)) != 0) - continue; - if((p = realloc(name, sizeof(path) + len + 1)) == NULL) - { - panel_error(panel, "realloc", 1); - continue; - } - name = p; - snprintf(name, sizeof(path) + len + 1, "%s/%s", path, - de->d_name); + gtk_widget_size_request(GTK_WIDGET(menu), &req); #ifdef DEBUG - fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, name); + fprintf(stderr, "DEBUG: %s() width=%d, height=%d\n", __func__, + req.width, req.height); #endif - if(config == NULL && (config = config_new()) == NULL) - continue; /* XXX report error */ - else - config_reset(config); - if(config_load(config, name) != 0) - { - error_print("panel"); - continue; - } - q = config_get(config, section, "Name"); - r = config_get(config, section, "Exec"); - if(q == NULL || r == NULL) - continue; - panel->apps = g_slist_insert_sorted(panel->apps, config, - _apps_compare); - config = NULL; - } - free(name); - closedir(dir); - if(config != NULL) - config_delete(config); - return FALSE; -} - -static gint _apps_compare(gconstpointer a, gconstpointer b) -{ - Config * ca = (Config *)a; - Config * cb = (Config *)b; - char const * cap; - char const * cbp; - const char section[] = "Desktop Entry"; - const char variable[] = "Name"; - - /* these should not fail */ - cap = config_get(ca, section, variable); - cbp = config_get(cb, section, variable); - return string_compare(cap, cbp); -} - - -/* panel_image */ -static GtkWidget * _panel_image(char const * name) -{ - int width; - int height; - size_t len; - String * buf; - GError * error = NULL; - GdkPixbuf * pixbuf = NULL; - - if(gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height) == TRUE - && (name != NULL && (len = strlen(name)) > 4) - && (strcmp(&name[len - 4], ".png") == 0 - || strcmp(&name[len - 4], ".xpm") == 0) - && (buf = string_new_append(PREFIX, "/share/pixmaps/", - name, NULL)) != NULL) - { - pixbuf = gdk_pixbuf_new_from_file_at_size(buf, width, height, - &error); - string_delete(buf); - } - if(pixbuf != NULL) - return gtk_image_new_from_pixbuf(pixbuf); - return gtk_image_new_from_icon_name(name, GTK_ICON_SIZE_MENU); -} - - -/* panel_menuitem */ -static GtkWidget * _panel_menuitem(char const * label, char const * stock) -{ - GtkWidget * ret; - GtkWidget * image; - - ret = gtk_image_menu_item_new_with_label(label); - if(stock != NULL) - { - image = _panel_image(stock); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(ret), image); - } - return ret; + if(req.height <= 0) + return; + *x = PANEL_BORDER_WIDTH; + *y = panel->height - PANEL_BORDER_WIDTH - PANEL_ICON_SIZE - req.height; + *push_in = TRUE; } diff --git a/src/project.conf b/src/project.conf index 80748a3..6f2f342 100644 --- a/src/project.conf +++ b/src/project.conf @@ -1,4 +1,6 @@ +subdirs=applets targets=panel +cppflags_force=-I ../include cflags_force=-W `pkg-config gtk+-2.0 --cflags` cflags=-Wall -g -O2 -pedantic ldflags_force=`pkg-config gtk+-2.0 --libs` -L$(PREFIX)/lib -Wl,-rpath,$(PREFIX)/lib -lSystem @@ -11,7 +13,7 @@ cppflags=-D PREFIX=\"$(PREFIX)\" install=$(BINDIR) [main.c] -depends=panel.h +depends=common.h [panel.c] -depends=panel.h +depends=common.h,../include/panel.h