ede/eworkpanel/mainmenu.cpp
2007-03-15 01:06:18 +00:00

482 lines
12 KiB
C++

#include "mainmenu.h"
#include "menu.h"
#include <edeconf.h>
#include <unistd.h>
#include <pwd.h>
#include <locale.h>
#include <icons/ede-small.xpm>
#include <icons/find.xpm>
#include <icons/run.xpm>
#include <icons/programs.xpm>
fltk::Pixmap ede_pix((const char **)ede_small2_xpm);
fltk::Pixmap programs_pix((const char **)programs_xpm);
fltk::Pixmap find_pix((const char **)find_xpm);
fltk::Pixmap run_pix((const char **)run_xpm);
// strdupcat() - it's cool to strcat with implied realloc
// -- NOTE: due to use of realloc *always* use strdupcat return value:
// dest = strdupcat(dest,src);
// and *never* use it like:
// strdupcat(dest,src);
char *strdupcat(char *dest, const char *src)
{
if (!dest) {
dest=(char*)malloc(strlen(src));
} else {
dest=(char*)realloc (dest, strlen(dest)+strlen(src)+1);
}
strcat(dest,src);
return dest;
}
///////////////////////////
extern EDE_Config pGlobalConfig;
MainMenu::MainMenu()
: fltk::Menu_Button(0,0,0,0, "Start")
{
layout_align(fltk::ALIGN_LEFT);
label_font(label_font()->bold());
label_size(label_size()+2);
m_modified = 0;
e_image = 0;
m_open = false;
bool showusername;
pGlobalConfig.get("Panel", "ShowUsernameOnMenu", showusername, false);
struct passwd *PWD;
/* Search for an entry with a matching user ID. */
PWD = getpwuid(getuid());
if(showusername && PWD && PWD->pw_name && *PWD->pw_name) {
label(PWD->pw_name);
} else {
label("EDE");
}
tooltip(_("Welcome to the Equinox Desktop Environment."));
}
MainMenu::~MainMenu()
{
if(e_image)
delete e_image;
}
int MainMenu::calculate_height() const
{
fltk::Style *s = fltk::Style::find("Menu");
int menuheight = s->box->dh();
for(int n=0; n<children(); n++)
{
fltk::Widget *i = child(n);
if(!i) break;
if(!i->visible()) continue;
fltk::font(i->label_font(), i->label_size());
menuheight += i->height()+s->leading;
}
return menuheight;
}
void MainMenu::draw()
{
fltk::Boxtype box = this->box();
fltk::Flags flags;
fltk::Color color = this->color();
fltk::Color lcolor = label_color();
if (!active_r())
{
flags = fltk::INACTIVE;
}
else if (belowmouse()) {
flags = fltk::HIGHLIGHT;
color = fltk::lighter(color);
lcolor = fltk::lighter(label_color());
if(!color) color = this->color();
if(!lcolor) color = this->label_color();
}
else if (m_open) {
flags = fltk::HIGHLIGHT|fltk::VALUE;
color = fltk::lighter(color);
lcolor = fltk::lighter(label_color());
if(!color) color = this->color();
if(!lcolor) color = this->label_color();
} else {
flags = 0;
}
box->draw(0, 0, this->w(), this->h(), color, flags);
int X=0, Y=0, W=w(), H=h();
box->inset(X,Y,W,H);
if(image()) {
int imY = (h()/2)-(image()->height()/2);
image()->draw(6, imY, image()->width(), image()->height(), flags);
X+=image()->width()+6;
} else {
X += 4;
W -= 4;
}
fltk::font(label_font(), label_size());
label_type()->draw(label(), X, Y, W-X, H, lcolor, flags|fltk::ALIGN_LEFT);
}
void MainMenu::layout()
{
fltk::font(label_font(), label_size());
int W = int(fltk::width(label())) + 12;
int H = h();
int im_size = H-6;
if(!e_image || (e_image && e_image->height()!=im_size)) {
if(e_image) delete e_image;
if(ede_pix.height()==im_size) {
e_image=0;
image(ede_pix);
}
else {
e_image = ede_pix.scale(im_size, im_size);
image(e_image);
}
}
if(image()) W+=image()->width();
w(W);
fltk::Menu_Button::layout();
}
void MainMenu::clear_favourites()
{
static char* favourites;
if(!favourites || strcmp(favourites,"")==0) {
favourites = strdupcat(favourites,fltk::homedir());
favourites = strdupcat(favourites,"/.ede/favourites/");
if(!fltk::file_exists(favourites)) {
mkdir( favourites, 0777 );
}
}
dirent **files;
int pNumFiles = fltk::filename_list(favourites, &files);
if (pNumFiles > 10)
{
for (int i=0; i<(pNumFiles-10); i++) {
if (strcmp(files[i]->d_name, ".") != 0 && strcmp(files[i]->d_name, "..") != 0 ) {
char* filename = strdup(favourites);
filename = strdupcat(filename,files[i]->d_name);
unlink(filename);
free(filename);
}
}
}
for(int i = 0; i < pNumFiles; i++)
free(files[i]);
if(pNumFiles && files)
free(files);
}
/*
%f a single file name, even if multiple files are selected.
The system reading the Desktop Entry should recognize that
the program in question cannot handle multiple file arguments,
and it should should probably spawn and execute multiple copies
of a program for each selected file if the program is not
able to handle additional file arguments. If files are not on
the local file system (i.e. HTTP or FTP locations), the files will
be copied to the local file system and %f will be expanded to point
at the temporary file. Used for programs that do not understand URL syntax.
%F a list of files. Use for apps that can open several local files at once.
%u a single URL.
%U a list of URLs.
%d the directory of the file to open.
%D a list of directories
%n a single filename (without path)
%N a list of filenames (without path)
%i the icon associated with the desktop entry
%m the mini-icon associated with the desktop entry
%c the comment associated with the desktop entry
%k the name of the desktop file
%v the name of the Device entry in the desktop file
*/
// This function is now implemented in elauncher
void MainMenu::resolve_program(char* cmd)
{
char pRun[FL_PATH_MAX];
snprintf(pRun, sizeof(pRun)-1, "elauncher \"%s\"", cmd);
fltk::start_child_process(pRun, false);
}
fltk::Image *MainMenu::find_image(const char* icon) const
{
char* iconpath = strdup(fltk::file_expand(icon));
fltk::Image *im=0;
if(fltk::file_exists(iconpath))
im = fltk::Image::read(iconpath);
if(!im) {
free(iconpath);
iconpath = strdup(PREFIX"/share/ede/icons/16x16/");
iconpath = strdupcat(icon);
im = fltk::Image::read(iconpath);
}
free(iconpath);
if(im && (im->width()!=16 || im->height()!=16)) {
fltk::Image *scaled = im->scale(16, 16);
if(scaled) {
delete im;
im = scaled;
}
}
return im;
}
/*
g->dir(PREFIX"/share/ede/programs");
i->exec("ehelpbook "PREFIX"/share/ede/doc/index.html");
*/
enum {
ITEM_NONE = 0,
ITEM_EXEC,
ITEM_APPDIR,
ITEM_SUBDIR,
ITEM_FILEBROWSER,
ITEM_DIVIDER
};
int str_to_type(char* str)
{
if(strcmp(str,"Exec")==0) return ITEM_EXEC;
else if(strcmp(str,"AppDir")==0) return ITEM_APPDIR;
else if(strcmp(str,"SubDir")==0) return ITEM_SUBDIR;
else if(strcmp(str,"FileBrowser")==0) return ITEM_FILEBROWSER;
else if(strcmp(str,"Divider")==0) return ITEM_DIVIDER;
return ITEM_NONE;
}
bool is_group_item(int t) { return (t==ITEM_APPDIR || t==ITEM_SUBDIR || t==ITEM_FILEBROWSER); }
char* MainMenu::get_item_name(Fl_XmlNode *node)
{
char* name = strdup("");
for(int n=0; n<node->children(); n++) {
fltk::XmlNode *np = node->child(n);
if(np->is_element() && np->name()=="Name") {
char* lang = strdup(np->get_attribute("Lang"));
if(strcmp(lang,"")==0 && (strlen(name)==0)) {
free(name);
name=strdup("");
np->text(name);
} else if(strcmp(lang,locale())==0) {
free(name);
name=strdup("");
np->text(name);
break;
}
}
}
return name;
}
char* MainMenu::get_item_dir(Fl_XmlNode *node)
{
char* dir = strdup(node->get_attribute("Dir"));
if(strcmp(dir,"$DEFAULT_PROGRAMS_DIR")==0) {
free(dir);
dir = strdup(PREFIX"/share/ede/programs");
}
return fltk::file_expand(dir);
}
// THIS MUST BE CHANGED ASAP!
#include "logoutdialog.h"
#include "aboutdialog.h"
void MainMenu::set_exec(EItem *i, const char* exec)
{
if(strcmp(exec,"$LOGOUT")==0)
i->callback((fltk::Callback*)LogoutDialog);
else if(strcmp(exec,"$ABOUT")==0)
i->callback((fltk::Callback *)AboutDialog);
else
i->exec(exec);
}
void MainMenu::build_menu_item(fltk::XmlNode *node)
{
if(!node) return;
int type = str_to_type(node->get_attribute("Type"));
if(type==ITEM_NONE) return;
fltk::Widget *w=0;
EItemGroup *g=0;
EItem *i=0;
switch(type) {
case ITEM_EXEC:
i = new EItem(this);
i->callback((fltk::Callback*)cb_exec_item);
set_exec(i, node->get_attribute("Exec"));
i->image(run_pix);
w = (fltk::Widget *)i;
break;
case ITEM_APPDIR:
g = new EItemGroup(this, APP_GROUP);
g->image(programs_pix);
g->dir(get_item_dir(node));
break;
case ITEM_SUBDIR:
g = new EItemGroup(this, APP_GROUP);
g->image(programs_pix);
break;
case ITEM_FILEBROWSER:
g = new EItemGroup(this, BROWSER_GROUP);
g->dir(get_item_dir(node));
g->image(find_pix);
break;
case ITEM_DIVIDER:
w = (fltk::Widget *)new fltk::Menu_Divider();
break;
}
if(g) {
g->begin();
w = (fltk::Widget*)g;
}
fltk::Image *im=0;
if(node->has_attribute("Icon")) {
im = find_image(node->get_attribute("Icon"));
} else {
char* im_path = strdup(node->get_attribute("Exec"));
im_path = strdupcat(im_path,".png");
im = find_image(im_path);
}
if(im) w->image(im);
char* label = strdup(get_item_name(node));
w->label(label);
for(int n=0; n<node->children(); n++) {
fltk::XmlNode *np = node->child(n);
if((np->is_element() || np->is_leaf()) && np->name()=="Item")
build_menu_item(np);
}
if(w->is_group())
((fltk::Group*)w)->end();
}
void MainMenu::init_entries()
{
// Update locale
m_locale = setlocale(LC_ALL, NULL);
int pos = m_locale.rpos('_');
if(pos>0) m_locale.sub_delete(pos, m_locale.length()-pos);
if(m_locale=="C" || m_locale=="POSIX") m_locale.clear();
const char *file = find_config_file("ede_mainmenu.xml", true);
struct stat s;
if(lstat(file, &s) == 0) {
if(!m_modified) m_modified = s.st_mtime;
if(m_modified != s.st_mtime) {
//file has changed..
m_modified = s.st_mtime;
clear();
}
}
if(children()>0) return;
FILE *fp = fopen(file, "r");
if(!fp) {
fltk::warning("Menu not found, creating default..");
try {
fltk::Buffer buf;
buf.append(default_menu, strlen(default_menu));
buf.save_file(file);
} catch(fltk::Exception &e) {
fltk::warning(e.text());
}
fp = fopen(file, "r");
if(!fp) fltk::fatal("Cannot write default menu.");
}
fltk::XmlLocator locator;
fltk::XmlDoc *doc=0;
if(fp) {
try {
doc = fltk::XmlParser::create_dom(fp, &locator, false);
} catch(fltk::XmlException &exp) {
char* error = strdup(exp.text());
error = strdupcat(error,"\n\n");
error = strdupcat(error,fltk::XmlLocator::error_line(file, *exp.locator()));
error = strdupcat(error,"\n");
fltk::warning(error);
}
}
if(!doc) {
// One more try!
try {
fltk::Buffer buf;
buf.append(default_menu, strlen(default_menu));
doc = fltk::XmlParser::create_dom(buf.data(), buf.bytes(), &locator, false);
} catch(fltk::Exception &e) {
fltk::fatal("Cannot open menu! [%s]", e.text().c_str());
}
}
if(doc) {
begin();
fltk::XmlNode *node = doc->root_node();
if(node) {
for(int n=0; n<node->children(); n++) {
fltk::XmlNode *np = node->child(n);
if((np->is_element() || np->is_leaf()) && np->name()=="Item")
build_menu_item(np);
}
}
end();
}
}
int MainMenu::popup(int X, int Y, int W, int H)
{
if(fltk::event_button()==1) {
m_open = true;
init_entries();
int ret = fltk::Menu_::popup(X, Y-calculate_height()-h()-1, W, H);
clear();
m_open = false;
return ret;
}
return 0;
}