2006-08-20 22:43:09 +04:00
|
|
|
/*
|
|
|
|
* $Id$
|
|
|
|
*
|
2007-05-22 18:53:17 +04:00
|
|
|
* Eiconman, desktop and icon manager
|
2006-08-20 22:43:09 +04:00
|
|
|
* Part of Equinox Desktop Environment (EDE).
|
2007-05-22 18:53:17 +04:00
|
|
|
* Copyright (c) 2000-2007 EDE Authors.
|
2006-08-20 22:43:09 +04:00
|
|
|
*
|
2007-05-22 18:53:17 +04:00
|
|
|
* This program is licensed under terms of the
|
|
|
|
* GNU General Public License version 2 or newer.
|
2006-08-20 22:43:09 +04:00
|
|
|
* See COPYING for details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "eiconman.h"
|
2007-05-22 18:53:17 +04:00
|
|
|
#include "DesktopIcon.h"
|
|
|
|
#include "Utils.h"
|
2007-06-18 18:18:35 +04:00
|
|
|
#include "Wallpaper.h"
|
2007-06-18 20:46:27 +04:00
|
|
|
#include "NotifyBox.h"
|
2007-05-22 18:53:17 +04:00
|
|
|
|
|
|
|
#include <edelib/Debug.h>
|
2007-06-18 18:18:35 +04:00
|
|
|
#include <edelib/File.h>
|
2007-05-22 18:53:17 +04:00
|
|
|
#include <edelib/Directory.h>
|
2007-06-18 18:18:35 +04:00
|
|
|
#include <edelib/MimeType.h>
|
2007-05-22 18:53:17 +04:00
|
|
|
#include <edelib/StrUtil.h>
|
|
|
|
#include <edelib/IconTheme.h>
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
#include <FL/Fl.h>
|
|
|
|
#include <FL/Fl_Shared_Image.h>
|
|
|
|
#include <FL/x.h>
|
|
|
|
#include <FL/Fl_Box.h>
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
#include <signal.h>
|
|
|
|
#include <stdlib.h> // rand, srand
|
|
|
|
#include <time.h> // time
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
#define CONFIG_NAME "eiconman.conf"
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
#define SELECTION_SINGLE (Fl::event_button() == 1)
|
|
|
|
#define SELECTION_MULTI (Fl::event_button() == 1 && (Fl::event_key(FL_Shift_L) || Fl::event_key(FL_Shift_R)))
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-23 16:43:50 +04:00
|
|
|
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
|
|
|
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
|
|
|
|
2007-06-19 13:59:15 +04:00
|
|
|
/*
|
|
|
|
* Which widgets Fl::belowmouse() should skip. This should be updated
|
|
|
|
* when new non-icon child is added to Desktop window.
|
|
|
|
*/
|
|
|
|
#define NOT_SELECTABLE(widget) ((widget == this) || (widget == wallpaper) || (widget == notify))
|
2007-05-23 16:43:50 +04:00
|
|
|
|
2007-05-24 16:53:03 +04:00
|
|
|
Desktop* Desktop::pinstance = NULL;
|
2007-06-18 18:18:35 +04:00
|
|
|
bool running = false;
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
inline unsigned int random_pos(int max) {
|
|
|
|
return (rand() % max);
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-23 16:43:50 +04:00
|
|
|
inline bool intersects(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) {
|
|
|
|
return (MAX(x1, x2) <= MIN(w1, w2) &&
|
|
|
|
MAX(y1, y2) <= MIN(h1, h2));
|
|
|
|
}
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
// assume fl_open_display() is called before
|
2007-05-22 18:53:17 +04:00
|
|
|
inline void dpy_sizes(int& width, int& height) {
|
2007-06-18 18:18:35 +04:00
|
|
|
width = DisplayWidth(fl_display, fl_screen);
|
|
|
|
height = DisplayHeight(fl_display, fl_screen);
|
2007-05-22 18:53:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void exit_signal(int signum) {
|
|
|
|
EDEBUG(ESTRLOC ": Exiting (got signal %d)\n", signum);
|
|
|
|
running = false;
|
|
|
|
}
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
void restart_signal(int signum) {
|
|
|
|
EDEBUG(ESTRLOC ": Restarting (got signal %d)\n", signum);
|
2006-08-20 22:43:09 +04:00
|
|
|
}
|
|
|
|
|
2007-06-19 13:59:15 +04:00
|
|
|
int desktop_xmessage_handler(int event) {
|
|
|
|
if(fl_xevent->type == PropertyNotify) {
|
|
|
|
if(fl_xevent->xproperty.atom == _XA_NET_CURRENT_DESKTOP) {
|
|
|
|
Desktop::instance()->notify_desktop_changed();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(fl_xevent->xproperty.atom == _XA_EDE_DESKTOP_NOTIFY) {
|
|
|
|
char buff[256];
|
|
|
|
if(ede_get_desktop_notify(buff, 256) && buff[0] != '\0')
|
|
|
|
Desktop::instance()->notify_box(buff, true);
|
|
|
|
return 1;
|
|
|
|
}
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-06-20 14:58:07 +04:00
|
|
|
//if(fl_xevent->xclient.message_type == _XA_EDE_DESKTOP_NOTIFY_COLOR) {
|
|
|
|
if(fl_xevent->xproperty.atom == _XA_EDE_DESKTOP_NOTIFY_COLOR) {
|
2007-06-19 13:59:15 +04:00
|
|
|
Desktop::instance()->notify_box_color(ede_get_desktop_notify_color());
|
|
|
|
return 1;
|
|
|
|
}
|
2007-06-20 14:58:07 +04:00
|
|
|
|
|
|
|
if(fl_xevent->xproperty.atom == _XA_NET_WORKAREA) {
|
|
|
|
Desktop::instance()->update_workarea();
|
|
|
|
return 1;
|
|
|
|
}
|
2007-06-19 13:59:15 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2007-05-24 16:53:03 +04:00
|
|
|
|
2007-06-19 13:59:15 +04:00
|
|
|
Desktop::Desktop() : Fl_Window(0, 0, 100, 100, "") {
|
2007-06-18 18:18:35 +04:00
|
|
|
selection_x = selection_y = 0;
|
|
|
|
moving = false;
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-05-24 16:53:03 +04:00
|
|
|
dsett = new DesktopSettings;
|
2007-06-18 18:18:35 +04:00
|
|
|
dsett->color = FL_GRAY;
|
2007-05-24 16:53:03 +04:00
|
|
|
dsett->wp_use = false;
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-06-19 13:59:15 +04:00
|
|
|
init_atoms();
|
2007-05-22 18:53:17 +04:00
|
|
|
update_workarea();
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
/*
|
|
|
|
* NOTE: order how childs are added is important. First
|
|
|
|
* non iconable ones should be added (wallpaper, menu, ...)
|
|
|
|
* then icons, so they can be drawn at top of them.
|
|
|
|
*/
|
2007-05-22 18:53:17 +04:00
|
|
|
begin();
|
2007-06-18 18:18:35 +04:00
|
|
|
wallpaper = new Wallpaper(0, 0, w(), h());
|
2007-06-22 13:43:15 +04:00
|
|
|
wallpaper->set("/home/sanel/wallpapers/katebig.jpg");
|
2007-06-23 15:31:36 +04:00
|
|
|
//wallpaper->hide();
|
|
|
|
//wallpaper->set("/home/sanelz/walls/katebig.jpg");
|
2007-06-22 13:43:15 +04:00
|
|
|
//wallpaper->set("/home/sanelz/walls/nin/1024x768-04.jpg");
|
2007-06-20 14:58:07 +04:00
|
|
|
//wallpaper->set("/home/sanelz/walls/nin/1024x768-02.jpg");
|
2007-06-19 13:59:15 +04:00
|
|
|
notify = new NotifyBox(w(), h());
|
2007-06-18 20:46:27 +04:00
|
|
|
notify->hide();
|
2007-05-22 18:53:17 +04:00
|
|
|
end();
|
2007-05-24 16:53:03 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
read_config();
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
set_bg_color(dsett->color, false);
|
|
|
|
running = true;
|
|
|
|
}
|
2007-05-25 21:45:17 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
Desktop::~Desktop() {
|
|
|
|
EDEBUG("Desktop::~Desktop()\n");
|
2007-05-22 20:27:33 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
delete dsett;
|
2006-08-20 22:43:09 +04:00
|
|
|
}
|
|
|
|
|
2007-05-24 16:53:03 +04:00
|
|
|
void Desktop::init(void) {
|
|
|
|
if(Desktop::pinstance != NULL)
|
|
|
|
return;
|
|
|
|
Desktop::pinstance = new Desktop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Desktop::shutdown(void) {
|
|
|
|
if(Desktop::pinstance == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
delete Desktop::pinstance;
|
|
|
|
Desktop::pinstance = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Desktop* Desktop::instance(void) {
|
|
|
|
EASSERT(Desktop::pinstance != NULL && "Desktop::init() should be run first");
|
|
|
|
return Desktop::pinstance;
|
2006-08-20 22:43:09 +04:00
|
|
|
}
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
/*
|
|
|
|
* This function must be overriden so window can inform
|
|
|
|
* wm to see it as desktop. It will send data when window
|
|
|
|
* is created, but before is shown.
|
|
|
|
*/
|
|
|
|
void Desktop::show(void) {
|
|
|
|
if(!shown()) {
|
|
|
|
Fl_X::make_xid(this);
|
|
|
|
net_make_me_desktop(this);
|
|
|
|
}
|
2007-06-23 15:31:36 +04:00
|
|
|
|
|
|
|
//Fl::dnd_text_ops(1);
|
2007-05-22 18:53:17 +04:00
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
/*
|
|
|
|
* If someone intentionaly hide desktop
|
|
|
|
* then quit from it.
|
|
|
|
*/
|
|
|
|
void Desktop::hide(void) {
|
|
|
|
running = false;
|
2007-05-24 16:53:03 +04:00
|
|
|
}
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
void Desktop::update_workarea(void) {
|
|
|
|
int X, Y, W, H;
|
|
|
|
if(!net_get_workarea(X, Y, W, H)) {
|
|
|
|
EWARNING(ESTRLOC ": wm does not support _NET_WM_WORKAREA; using screen sizes...\n");
|
|
|
|
X = Y = 0;
|
|
|
|
dpy_sizes(W, H);
|
|
|
|
}
|
2007-05-24 16:53:03 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
resize(X, Y, W, H);
|
2007-05-24 16:53:03 +04:00
|
|
|
}
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
void Desktop::set_bg_color(int c, bool do_redraw) {
|
|
|
|
if(color() == c)
|
2007-05-24 16:53:03 +04:00
|
|
|
return;
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
dsett->color = c;
|
|
|
|
color(c);
|
2007-05-24 16:53:03 +04:00
|
|
|
if(do_redraw)
|
|
|
|
redraw();
|
|
|
|
}
|
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
void Desktop::read_config(void) {
|
|
|
|
edelib::Config conf;
|
|
|
|
if(!conf.load(CONFIG_NAME)) {
|
2007-06-18 18:18:35 +04:00
|
|
|
EWARNING(ESTRLOC ": Can't load %s, using default...\n", CONFIG_NAME);
|
2007-05-22 18:53:17 +04:00
|
|
|
return;
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
/*
|
|
|
|
* TODO:
|
|
|
|
* Add IconArea[X,Y,W,H] so icons can live
|
|
|
|
* inside that area only (aka margins).
|
|
|
|
*/
|
2007-06-18 18:18:35 +04:00
|
|
|
int default_bg_color = FL_BLUE;
|
2007-05-24 16:53:03 +04:00
|
|
|
int default_wp_use = false;
|
|
|
|
char wpath[256];
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
// read Desktop section
|
2007-05-24 16:53:03 +04:00
|
|
|
conf.get("Desktop", "Color", dsett->color, default_bg_color);
|
|
|
|
|
|
|
|
if(conf.error() != edelib::CONF_ERR_SECTION) {
|
|
|
|
conf.get("Desktop", "WallpaperUse", dsett->wp_use, default_wp_use);
|
|
|
|
conf.get("Desktop", "Wallpaper", wpath, sizeof(wpath));
|
|
|
|
|
2007-05-25 21:45:17 +04:00
|
|
|
// keep path but disable wallpaper if file does not exists
|
|
|
|
if(!edelib::file_exists(wpath)) {
|
|
|
|
EDEBUG(ESTRLOC ": %s as wallpaper does not exists\n", wpath);
|
|
|
|
dsett->wp_use = false;
|
|
|
|
}
|
2007-05-24 16:53:03 +04:00
|
|
|
} else {
|
|
|
|
// color is already filled
|
|
|
|
dsett->wp_use = default_wp_use;
|
2007-05-22 18:53:17 +04:00
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
// read Icons section
|
2007-06-18 18:18:35 +04:00
|
|
|
conf.get("Icons", "Label Background", gisett.label_background, FL_BLUE);
|
|
|
|
conf.get("Icons", "Label Foreground", gisett.label_foreground, FL_WHITE);
|
2007-05-22 18:53:17 +04:00
|
|
|
conf.get("Icons", "Label Fontsize", gisett.label_fontsize, 12);
|
|
|
|
conf.get("Icons", "Label Maxwidth", gisett.label_maxwidth, 75);
|
|
|
|
conf.get("Icons", "Label Transparent",gisett.label_transparent, false);
|
|
|
|
conf.get("Icons", "Label Visible", gisett.label_draw, true);
|
|
|
|
conf.get("Icons", "OneClickExec", gisett.one_click_exec, false);
|
2007-06-18 18:18:35 +04:00
|
|
|
conf.get("Icons", "AutoArrange", gisett.auto_arrange, true);
|
2007-05-22 18:53:17 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now try to load icons, first looking inside ~/Desktop directory
|
|
|
|
* then inside config since config could contain removed entries
|
|
|
|
* from $HOME/Desktop
|
|
|
|
*
|
|
|
|
* FIXME: dir_exists() can't handle '~/Desktop' ???
|
|
|
|
*/
|
|
|
|
edelib::String dd = edelib::dir_home();
|
2007-06-18 18:18:35 +04:00
|
|
|
if(dd.empty()) {
|
|
|
|
EWARNING(ESTRLOC ": Can't read home directory; icons will not be loaded\n");
|
|
|
|
return;
|
|
|
|
}
|
2007-05-22 18:53:17 +04:00
|
|
|
dd += "/Desktop";
|
|
|
|
load_icons(dd.c_str(), conf);
|
2007-06-18 18:18:35 +04:00
|
|
|
}
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
void Desktop::save_config(void) {
|
|
|
|
// TODO
|
2007-05-22 18:53:17 +04:00
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
void Desktop::load_icons(const char* path, edelib::Config& conf) {
|
|
|
|
EASSERT(path != NULL);
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
if(!edelib::dir_exists(path)) {
|
|
|
|
EDEBUG(ESTRLOC ": %s does not exists\n", path);
|
|
|
|
return;
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
edelib::vector<edelib::String> lst;
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
// list without full path, so we can use name as entry in config file
|
|
|
|
if(!dir_list(path, lst)) {
|
|
|
|
EDEBUG(ESTRLOC ": Can't read %s\n", path);
|
|
|
|
return;
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
const char* name = NULL;
|
|
|
|
int icon_x = 0;
|
|
|
|
int icon_y = 0;
|
|
|
|
edelib::String full_path;
|
|
|
|
full_path.reserve(256);
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-25 21:45:17 +04:00
|
|
|
bool can_add = false;
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-25 21:45:17 +04:00
|
|
|
edelib::MimeType mt;
|
|
|
|
|
|
|
|
unsigned int sz = lst.size();
|
|
|
|
for(unsigned int i = 0; i < sz; i++) {
|
|
|
|
name = lst[i].c_str();
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-25 21:45:17 +04:00
|
|
|
full_path = path;
|
|
|
|
full_path += '/';
|
|
|
|
full_path += name;
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-25 21:45:17 +04:00
|
|
|
can_add = false;
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-25 21:45:17 +04:00
|
|
|
IconSettings is;
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-25 21:45:17 +04:00
|
|
|
// see is possible .desktop file, icon, name fields are filled from read_desktop_file()
|
|
|
|
if(edelib::str_ends(name, ".desktop")) {
|
|
|
|
if(read_desktop_file(full_path.c_str(), is))
|
|
|
|
can_add = true;
|
|
|
|
} else {
|
|
|
|
// then try to figure out it's mime; if fails, ignore it
|
|
|
|
if(mt.set(full_path.c_str())) {
|
2007-06-23 15:31:36 +04:00
|
|
|
EDEBUG(ESTRLOC ": Loading icon as mime-type %s\n", mt.icon_name().c_str());
|
2007-06-18 18:18:35 +04:00
|
|
|
is.icon = mt.icon_name();
|
2007-05-25 21:45:17 +04:00
|
|
|
// icon label is name of file
|
|
|
|
is.name = name;
|
|
|
|
is.type = ICON_FILE;
|
|
|
|
|
|
|
|
can_add = true;
|
|
|
|
} else {
|
|
|
|
EDEBUG(ESTRLOC ": Failed mime-type for %s, ignoring...\n", name);
|
|
|
|
can_add = false;
|
|
|
|
}
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-25 21:45:17 +04:00
|
|
|
if(can_add) {
|
|
|
|
is.key_name = name;
|
|
|
|
// random_pos() is used if X/Y keys are not found
|
|
|
|
conf.get(name, "X", icon_x, random_pos(w() - 10));
|
|
|
|
conf.get(name, "Y", icon_y, random_pos(h() - 10));
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-25 21:45:17 +04:00
|
|
|
EDEBUG(ESTRLOC ": %s found with: %i %i\n", name, icon_x, icon_y);
|
|
|
|
is.x = icon_x;
|
|
|
|
is.y = icon_y;
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
DesktopIcon* dic = new DesktopIcon(&gisett, &is, dsett->color);
|
2007-05-25 21:45:17 +04:00
|
|
|
add_icon(dic);
|
2007-05-22 18:53:17 +04:00
|
|
|
}
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
}
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
// read .desktop files
|
2007-05-25 21:45:17 +04:00
|
|
|
bool Desktop::read_desktop_file(const char* path, IconSettings& is) {
|
2007-05-22 18:53:17 +04:00
|
|
|
EASSERT(path != NULL);
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
if(!edelib::file_exists(path)) {
|
|
|
|
EDEBUG(ESTRLOC ": %s don't exists\n");
|
|
|
|
return false;
|
2006-08-20 22:43:09 +04:00
|
|
|
}
|
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
edelib::Config dconf;
|
|
|
|
if(!dconf.load(path)) {
|
|
|
|
EDEBUG(ESTRLOC ": Can't read %s\n", path);
|
|
|
|
return false;
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
char buff[128];
|
|
|
|
int buffsz = sizeof(buff);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First check for 'EmptyIcon' key since via it is determined
|
|
|
|
* is icon trash type or not (in case of trash, 'Icon' key is used for full trash).
|
|
|
|
* FIXME: any other way to check for trash icons ???
|
|
|
|
*/
|
|
|
|
if(dconf.get("Desktop Entry", "EmptyIcon", buff, buffsz)) {
|
2007-05-25 21:45:17 +04:00
|
|
|
is.type = ICON_TRASH;
|
2007-05-22 18:53:17 +04:00
|
|
|
is.icon = buff;
|
2007-05-24 16:53:03 +04:00
|
|
|
} else
|
2007-05-25 21:45:17 +04:00
|
|
|
is.type = ICON_NORMAL;
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
if(dconf.error() == edelib::CONF_ERR_SECTION) {
|
|
|
|
EDEBUG(ESTRLOC ": %s is not valid .desktop file\n");
|
|
|
|
return false;
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
dconf.get("Desktop Entry", "Icon", buff, buffsz);
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-25 21:45:17 +04:00
|
|
|
if(is.type == ICON_TRASH)
|
2007-05-22 18:53:17 +04:00
|
|
|
is.icon2 = buff;
|
|
|
|
else {
|
|
|
|
is.icon = buff;
|
2007-05-25 21:45:17 +04:00
|
|
|
is.type = ICON_NORMAL;
|
2007-05-22 18:53:17 +04:00
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
EDEBUG(ESTRLOC ": Icon is: %s\n", is.icon.c_str());
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
char name[256];
|
|
|
|
// FIXME: UTF-8 safety
|
|
|
|
if(dconf.get_localized("Desktop Entry", "Name", name, sizeof(name))) {
|
|
|
|
EDEBUG(ESTRLOC ": Name is: %s\n", name);
|
|
|
|
is.name = name;
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
/*
|
|
|
|
* Specs (desktop entry file) said that Type=Link means there must
|
|
|
|
* be somewhere URL key. My thoughts is that in this case Exec key
|
|
|
|
* should be ignored, even if exists. Then I will follow my thoughts.
|
2007-05-25 21:45:17 +04:00
|
|
|
*
|
|
|
|
* FIXME: 'Type' should be seen as test for .desktop file; if key
|
|
|
|
* is not present, then file should not be considered as .desktop. This
|
|
|
|
* should be checked before all others.
|
2007-05-22 18:53:17 +04:00
|
|
|
*/
|
|
|
|
if(!dconf.get("Desktop Entry", "Type", buff, buffsz)) {
|
|
|
|
EDEBUG(ESTRLOC ": Missing mandatory Type key\n");
|
|
|
|
return false;
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
if(strncmp(buff, "Link", 4) == 0) {
|
|
|
|
is.cmd_is_url = true;
|
|
|
|
if(!dconf.get("Desktop Entry", "URL", buff, buffsz)) {
|
|
|
|
EDEBUG(ESTRLOC ": Missing expected URL key\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
is.cmd = buff;
|
|
|
|
} else if(strncmp(buff, "Application", 11) == 0) {
|
|
|
|
is.cmd_is_url = false;
|
|
|
|
if(!dconf.get("Desktop Entry", "Exec", buff, buffsz)) {
|
|
|
|
EDEBUG(ESTRLOC ": Missing expected Exec key\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
is.cmd = buff;
|
|
|
|
} else if(strncmp(buff, "Directory", 11) == 0) {
|
|
|
|
EDEBUG(ESTRLOC ": Type = Directory is not implemented yet\n");
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
EDEBUG(ESTRLOC ": Unknown %s type, ignoring...\n", buff);
|
|
|
|
return false;
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
return true;
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
void Desktop::add_icon(DesktopIcon* ic) {
|
|
|
|
EASSERT(ic != NULL);
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
icons.push_back(ic);
|
2007-06-18 18:18:35 +04:00
|
|
|
// FIXME: validate this
|
|
|
|
add((Fl_Widget*)ic);
|
2007-05-22 18:53:17 +04:00
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
void Desktop::unfocus_all(void) {
|
2007-05-22 18:53:17 +04:00
|
|
|
unsigned int sz = icons.size();
|
2007-06-18 18:18:35 +04:00
|
|
|
DesktopIcon* ic;
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
for(unsigned int i = 0; i < sz; i++) {
|
2007-06-18 18:18:35 +04:00
|
|
|
ic = icons[i];
|
|
|
|
if(ic->is_focused()) {
|
|
|
|
ic->do_unfocus();
|
|
|
|
ic->fast_redraw();
|
2007-05-22 18:53:17 +04:00
|
|
|
}
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
}
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
void Desktop::select(DesktopIcon* ic) {
|
2007-05-22 18:53:17 +04:00
|
|
|
EASSERT(ic != NULL);
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
if(in_selection(ic))
|
|
|
|
return;
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
selectionbuff.push_back(ic);
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
if(!ic->is_focused()) {
|
|
|
|
ic->do_focus();
|
2007-06-18 18:18:35 +04:00
|
|
|
ic->fast_redraw();
|
2007-05-22 18:53:17 +04:00
|
|
|
}
|
2007-05-23 16:43:50 +04:00
|
|
|
}
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
void Desktop::select_only(DesktopIcon* ic) {
|
2007-05-22 18:53:17 +04:00
|
|
|
EASSERT(ic != NULL);
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
unfocus_all();
|
|
|
|
selectionbuff.clear();
|
|
|
|
selectionbuff.push_back(ic);
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
ic->do_focus();
|
2007-06-18 18:18:35 +04:00
|
|
|
ic->fast_redraw();
|
|
|
|
}
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
bool Desktop::in_selection(const DesktopIcon* ic) {
|
|
|
|
EASSERT(ic != NULL);
|
|
|
|
|
|
|
|
unsigned int sz = selectionbuff.size();
|
|
|
|
for(unsigned int i = 0; i < sz; i++) {
|
|
|
|
if(ic == selectionbuff[i])
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2006-08-20 22:43:09 +04:00
|
|
|
}
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
void Desktop::move_selection(int x, int y, bool apply) {
|
|
|
|
unsigned int sz = selectionbuff.size();
|
|
|
|
if(sz == 0)
|
2007-05-23 16:43:50 +04:00
|
|
|
return;
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
int prev_x, prev_y, tmp_x, tmp_y;
|
|
|
|
DesktopIcon* ic;
|
2007-05-23 16:43:50 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
for(unsigned int i = 0; i < sz; i++) {
|
|
|
|
ic = selectionbuff[i];
|
2007-05-23 16:43:50 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
prev_x = ic->drag_icon_x();
|
|
|
|
prev_y = ic->drag_icon_y();
|
2007-05-23 16:43:50 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
tmp_x = x - selection_x;
|
|
|
|
tmp_y = y - selection_y;
|
2007-05-23 16:43:50 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
ic->drag(prev_x + tmp_x, prev_y + tmp_y, apply);
|
2007-05-23 16:43:50 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
// very slow if not checked
|
|
|
|
if(apply == true)
|
|
|
|
ic->fast_redraw();
|
2007-05-23 16:43:50 +04:00
|
|
|
}
|
2007-06-18 18:18:35 +04:00
|
|
|
|
|
|
|
selection_x = x;
|
|
|
|
selection_y = y;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Redraw whole screen so it reflects
|
|
|
|
* new icon position
|
|
|
|
*/
|
|
|
|
if(apply)
|
|
|
|
redraw();
|
2007-05-23 16:43:50 +04:00
|
|
|
}
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
#if 0
|
2007-05-23 16:43:50 +04:00
|
|
|
/*
|
2007-06-18 18:18:35 +04:00
|
|
|
* Tries to figure out icon below mouse. It is alternative to
|
|
|
|
* Fl::belowmouse() since with this we hunt only icons, not other
|
|
|
|
* childs (wallpaper, menu), which can be returned by Fl::belowmouse()
|
|
|
|
* and bad things be hapened.
|
2007-05-23 16:43:50 +04:00
|
|
|
*/
|
|
|
|
DesktopIcon* Desktop::below_mouse(int px, int py) {
|
|
|
|
unsigned int sz = icons.size();
|
|
|
|
|
|
|
|
DesktopIcon* ic = NULL;
|
|
|
|
for(unsigned int i = 0; i < sz; i++) {
|
|
|
|
ic = icons[i];
|
|
|
|
if(ic->x() < px && ic->y() < py && px < (ic->x() + ic->h()) && py < (ic->y() + ic->h()))
|
|
|
|
return ic;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-05-24 16:53:03 +04:00
|
|
|
#endif
|
|
|
|
|
2007-06-19 13:59:15 +04:00
|
|
|
void Desktop::notify_box(const char* msg, bool copy) {
|
|
|
|
if(!msg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(copy)
|
|
|
|
notify->copy_label(msg);
|
|
|
|
else
|
|
|
|
notify->label(msg);
|
|
|
|
|
2007-06-18 20:46:27 +04:00
|
|
|
notify->show();
|
|
|
|
}
|
|
|
|
|
2007-06-19 13:59:15 +04:00
|
|
|
void Desktop::notify_box_color(Fl_Color col) {
|
|
|
|
notify->color(col);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Desktop::notify_desktop_changed(void) {
|
|
|
|
int num = net_get_current_desktop();
|
|
|
|
if(num == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
char** names;
|
|
|
|
int ret = net_get_workspace_names(names);
|
|
|
|
if(num >= ret) {
|
|
|
|
XFreeStringList(names);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
notify_box(names[num], true);
|
|
|
|
XFreeStringList(names);
|
|
|
|
}
|
|
|
|
|
2007-06-23 15:31:36 +04:00
|
|
|
void Desktop::drop_source(const char* src, int x, int y) {
|
|
|
|
if(!src)
|
|
|
|
return;
|
|
|
|
IconSettings is;
|
|
|
|
is.x = x;
|
|
|
|
is.y = y;
|
|
|
|
|
|
|
|
// absolute path is (for now) seen as non-url
|
|
|
|
if(src[0] == '/')
|
|
|
|
is.cmd_is_url = false;
|
|
|
|
else
|
|
|
|
is.cmd_is_url = true;
|
|
|
|
|
|
|
|
is.name = get_basename(src);
|
|
|
|
is.cmd = "(none)";
|
|
|
|
is.type = ICON_NORMAL;
|
|
|
|
|
|
|
|
edelib::MimeType mt;
|
|
|
|
if(!mt.set(src)) {
|
|
|
|
EWARNING(ESTRLOC ": MimeType for %s failed, not dropping icon\n", src);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
is.icon = mt.icon_name();
|
|
|
|
DesktopIcon* dic = new DesktopIcon(&gisett, &is, color());
|
|
|
|
add_icon(dic);
|
|
|
|
}
|
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
int Desktop::handle(int event) {
|
|
|
|
switch(event) {
|
2007-06-18 18:18:35 +04:00
|
|
|
case FL_FOCUS:
|
|
|
|
case FL_UNFOCUS:
|
2007-06-19 14:10:42 +04:00
|
|
|
case FL_SHORTCUT:
|
2007-05-23 16:43:50 +04:00
|
|
|
return 1;
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
case FL_PUSH: {
|
2007-05-22 18:53:17 +04:00
|
|
|
/*
|
|
|
|
* First check where we clicked. If we do it on desktop
|
|
|
|
* unfocus any possible focused childs, and handle
|
|
|
|
* specific clicks. Otherwise, do rest for childs.
|
|
|
|
*/
|
2007-06-18 18:18:35 +04:00
|
|
|
Fl_Widget* clicked = Fl::belowmouse();
|
|
|
|
|
|
|
|
if(NOT_SELECTABLE(clicked)) {
|
2007-05-22 18:53:17 +04:00
|
|
|
EDEBUG(ESTRLOC ": DESKTOP CLICK !!!\n");
|
2007-06-18 18:18:35 +04:00
|
|
|
if(!selectionbuff.empty()) {
|
|
|
|
/*
|
|
|
|
* only focused are in selectionbuff, so this is
|
|
|
|
* fine to do; also will prevent full redraw when
|
|
|
|
* is clicked on desktop
|
|
|
|
*/
|
|
|
|
unfocus_all();
|
2007-05-22 18:53:17 +04:00
|
|
|
selectionbuff.clear();
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2007-05-24 16:53:03 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
// from here, all events are managed for icons
|
|
|
|
DesktopIcon* tmp_icon = (DesktopIcon*)clicked;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* do no use assertion on this, since
|
|
|
|
* fltk::belowmouse() can miss our icon
|
|
|
|
*/
|
|
|
|
if(!tmp_icon)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if(SELECTION_MULTI) {
|
2007-06-18 18:18:35 +04:00
|
|
|
Fl::event_is_click(0);
|
2007-05-22 18:53:17 +04:00
|
|
|
select(tmp_icon);
|
|
|
|
return 1;
|
2007-06-18 18:18:35 +04:00
|
|
|
} else if(SELECTION_SINGLE) {
|
2007-06-18 20:46:27 +04:00
|
|
|
if(!in_selection(tmp_icon)) {
|
2007-06-19 13:59:15 +04:00
|
|
|
/*
|
|
|
|
* for testing
|
|
|
|
* notify_box(tmp_icon->label());
|
|
|
|
*/
|
2007-05-22 18:53:17 +04:00
|
|
|
select_only(tmp_icon);
|
2007-06-18 20:46:27 +04:00
|
|
|
}
|
|
|
|
} else if(Fl::event_button() == 3) {
|
2007-05-22 18:53:17 +04:00
|
|
|
select_only(tmp_icon);
|
2007-06-19 13:59:15 +04:00
|
|
|
/*
|
|
|
|
* for testing
|
|
|
|
* notify_box(tmp_icon->label());
|
|
|
|
*/
|
2007-06-18 20:46:27 +04:00
|
|
|
}
|
2007-05-22 18:53:17 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Let child handle the rest.
|
|
|
|
* Also prevent click on other mouse buttons during move.
|
|
|
|
*/
|
|
|
|
if(!moving)
|
2007-06-18 18:18:35 +04:00
|
|
|
tmp_icon->handle(FL_PUSH);
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
EDEBUG(ESTRLOC ": FL_PUSH from desktop\n");
|
|
|
|
selection_x = Fl::event_x_root();
|
|
|
|
selection_y = Fl::event_y_root();
|
2007-05-22 18:53:17 +04:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
case FL_DRAG:
|
2007-05-22 18:53:17 +04:00
|
|
|
moving = true;
|
|
|
|
if(!selectionbuff.empty()) {
|
|
|
|
EDEBUG(ESTRLOC ": DRAG icon from desktop\n");
|
2007-06-18 18:18:35 +04:00
|
|
|
move_selection(Fl::event_x_root(), Fl::event_y_root(), false);
|
2007-05-22 18:53:17 +04:00
|
|
|
} else {
|
|
|
|
EDEBUG(ESTRLOC ": DRAG from desktop\n");
|
|
|
|
}
|
2007-06-18 18:18:35 +04:00
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
return 1;
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
case FL_RELEASE:
|
2007-05-22 18:53:17 +04:00
|
|
|
EDEBUG(ESTRLOC ": RELEASE from desktop\n");
|
2007-06-18 18:18:35 +04:00
|
|
|
EDEBUG(ESTRLOC ": clicks: %i\n", Fl::event_is_click());
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-05-24 16:53:03 +04:00
|
|
|
if(!selectionbuff.empty() && moving)
|
2007-06-18 18:18:35 +04:00
|
|
|
move_selection(Fl::event_x_root(), Fl::event_y_root(), true);
|
2007-05-22 18:53:17 +04:00
|
|
|
|
|
|
|
/*
|
2007-06-18 18:18:35 +04:00
|
|
|
* Do not send FL_RELEASE during move
|
2007-05-22 18:53:17 +04:00
|
|
|
*
|
2007-06-18 18:18:35 +04:00
|
|
|
* TODO: should be alowed FL_RELEASE to multiple icons? (aka. run
|
2007-05-22 18:53:17 +04:00
|
|
|
* command for all selected icons ?
|
|
|
|
*/
|
|
|
|
if(selectionbuff.size() == 1 && !moving)
|
2007-06-18 18:18:35 +04:00
|
|
|
selectionbuff[0]->handle(FL_RELEASE);
|
2007-05-22 18:53:17 +04:00
|
|
|
|
|
|
|
moving = false;
|
|
|
|
return 1;
|
|
|
|
|
2007-06-23 15:31:36 +04:00
|
|
|
case FL_DND_ENTER:
|
|
|
|
case FL_DND_DRAG:
|
|
|
|
case FL_DND_LEAVE:
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
case FL_DND_RELEASE:
|
|
|
|
EDEBUG(ESTRLOC ": DND on desktop\n");
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
case FL_PASTE:
|
|
|
|
EDEBUG("================> PASTE: %s\n", Fl::event_text());
|
|
|
|
drop_source(Fl::event_text(), Fl::event_x_root(), Fl::event_y_root());
|
|
|
|
return 1;
|
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2006-08-20 22:43:09 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
return Fl_Window::handle(event);
|
2006-08-20 22:43:09 +04:00
|
|
|
}
|
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
int main() {
|
|
|
|
signal(SIGTERM, exit_signal);
|
|
|
|
signal(SIGKILL, exit_signal);
|
2007-06-18 18:18:35 +04:00
|
|
|
signal(SIGINT, exit_signal);
|
|
|
|
signal(SIGHUP, restart_signal);
|
2007-05-22 18:53:17 +04:00
|
|
|
|
|
|
|
srand(time(NULL));
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
// a lot of preparing code depends on this
|
|
|
|
fl_open_display();
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
fl_register_images();
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
edelib::IconTheme::init("edeneu");
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-05-24 16:53:03 +04:00
|
|
|
Desktop::init();
|
|
|
|
Desktop::instance()->show();
|
2007-05-22 18:53:17 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* XSelectInput will redirect PropertyNotify messages, which
|
2007-06-18 18:18:35 +04:00
|
|
|
* are listened for
|
2007-05-22 18:53:17 +04:00
|
|
|
*/
|
2007-06-19 13:59:15 +04:00
|
|
|
XSelectInput(fl_display, RootWindow(fl_display, fl_screen), PropertyChangeMask | StructureNotifyMask | ClientMessage);
|
|
|
|
|
2007-06-18 18:18:35 +04:00
|
|
|
Fl::add_handler(desktop_xmessage_handler);
|
2007-05-22 18:53:17 +04:00
|
|
|
|
|
|
|
while(running)
|
2007-06-18 18:18:35 +04:00
|
|
|
Fl::wait();
|
2007-05-22 18:53:17 +04:00
|
|
|
|
2007-05-24 16:53:03 +04:00
|
|
|
Desktop::shutdown();
|
|
|
|
edelib::IconTheme::shutdown();
|
|
|
|
|
2007-05-22 18:53:17 +04:00
|
|
|
return 0;
|
2006-08-20 22:43:09 +04:00
|
|
|
}
|