mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
.desktop files are read by DesktopFile
Added selection box, but needs more work with redrawing DND mess; still not work as expected
This commit is contained in:
parent
c951b708ce
commit
ea32acf7fa
@ -189,6 +189,7 @@ void DesktopIcon::fast_redraw(void) {
|
||||
|
||||
// LABEL_OFFSET + 2 include selection box line height too
|
||||
parent()->damage(FL_DAMAGE_ALL, x(), y(), w(), h() + lheight + LABEL_OFFSET + 2);
|
||||
//parent()->damage(FL_DAMAGE_CHILD, x(), y(), w(), h() + lheight + LABEL_OFFSET + 2);
|
||||
}
|
||||
|
||||
void DesktopIcon::draw(void) {
|
||||
|
@ -234,7 +234,7 @@ void draw_overlay_rect(void) {
|
||||
return;
|
||||
|
||||
XSetDashes(fl_display, fl_gc, 0, dash_list, 1);
|
||||
XSetLineAttributes(fl_display, fl_gc, 1, LineOnOffDash, CapButt, JoinMiter);
|
||||
XSetLineAttributes(fl_display, fl_gc, 2, LineOnOffDash, CapButt, JoinMiter);
|
||||
|
||||
XSetFunction(fl_display, fl_gc, GXxor);
|
||||
XSetForeground(fl_display, fl_gc, 0xffffffff);
|
||||
|
@ -430,7 +430,7 @@ void Wallpaper::draw(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <FL/Fl.h>
|
||||
//#include <FL/Fl.h>
|
||||
|
||||
int Wallpaper::handle(int event) {
|
||||
switch(event) {
|
||||
@ -442,24 +442,8 @@ int Wallpaper::handle(int event) {
|
||||
case FL_DND_DRAG:
|
||||
case FL_DND_LEAVE:
|
||||
case FL_DND_RELEASE:
|
||||
return parent()->handle(event);
|
||||
|
||||
case FL_PASTE:
|
||||
/*
|
||||
* Since some stuff are in fltk unnedededly complicated, like
|
||||
* DND, this is needed to make it correctly work. After we got
|
||||
* FL_PASTE event (drag'n drop content released), that content
|
||||
* is routed to CLIPBOARD buffer of Desktop and in turn will trigger
|
||||
* FL_PASTE on Desktop.
|
||||
*
|
||||
* This is since fltk use XA_PRIMARY as default (or selection clipboard from X11)
|
||||
* not CLIPBOARD (as rest of normal world).
|
||||
*
|
||||
* Also, to make DND workable for Desktop, Wallpaper widget must be
|
||||
* always visible.
|
||||
*/
|
||||
Fl::paste(*parent(), 1);
|
||||
return 1;
|
||||
return parent()->handle(event);
|
||||
}
|
||||
|
||||
return Fl_Box::handle(event);
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include <edelib/Debug.h>
|
||||
#include <edelib/File.h>
|
||||
#include <edelib/DesktopFile.h>
|
||||
#include <edelib/Directory.h>
|
||||
#include <edelib/MimeType.h>
|
||||
#include <edelib/StrUtil.h>
|
||||
@ -31,9 +32,12 @@
|
||||
#include <signal.h>
|
||||
#include <stdlib.h> // rand, srand
|
||||
#include <time.h> // time
|
||||
#include <ctype.h> // isprint
|
||||
|
||||
#define CONFIG_NAME "eiconman.conf"
|
||||
|
||||
#define EDAMAGE_OVERLAY 0x20
|
||||
|
||||
#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)))
|
||||
|
||||
@ -102,10 +106,14 @@ int desktop_xmessage_handler(int event) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Desktop::Desktop() : Fl_Window(0, 0, 100, 100, "") {
|
||||
Desktop::Desktop() : DESKTOP_WINDOW(0, 0, 100, 100, "") {
|
||||
selection_x = selection_y = 0;
|
||||
moving = false;
|
||||
|
||||
selbox = new SelectionOverlay;
|
||||
selbox->x = selbox->y = selbox->w = selbox->h = 0;
|
||||
selbox->show = false;
|
||||
|
||||
dsett = new DesktopSettings;
|
||||
dsett->color = FL_GRAY;
|
||||
dsett->wp_use = false;
|
||||
@ -139,6 +147,7 @@ Desktop::~Desktop() {
|
||||
EDEBUG("Desktop::~Desktop()\n");
|
||||
|
||||
delete dsett;
|
||||
delete selbox;
|
||||
}
|
||||
|
||||
void Desktop::init(void) {
|
||||
@ -349,9 +358,9 @@ bool Desktop::read_desktop_file(const char* path, IconSettings& is) {
|
||||
return false;
|
||||
}
|
||||
|
||||
edelib::Config dconf;
|
||||
edelib::DesktopFile dconf;
|
||||
if(!dconf.load(path)) {
|
||||
EDEBUG(ESTRLOC ": Can't read %s\n", path);
|
||||
EWARNING(ESTRLOC ": Can't read %s\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -359,7 +368,7 @@ bool Desktop::read_desktop_file(const char* path, IconSettings& is) {
|
||||
int buffsz = sizeof(buff);
|
||||
|
||||
/*
|
||||
* First check for 'EmptyIcon' key since via it is determined
|
||||
* 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 ???
|
||||
*/
|
||||
@ -368,65 +377,34 @@ bool Desktop::read_desktop_file(const char* path, IconSettings& is) {
|
||||
is.icon = buff;
|
||||
} else
|
||||
is.type = ICON_NORMAL;
|
||||
|
||||
if(dconf.error() == edelib::CONF_ERR_SECTION) {
|
||||
EDEBUG(ESTRLOC ": %s is not valid .desktop file\n");
|
||||
|
||||
if(!dconf.icon(buff, buffsz)) {
|
||||
EWARNING(ESTRLOC ": No Icon key, balling out\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
dconf.get("Desktop Entry", "Icon", buff, buffsz);
|
||||
|
||||
if(is.type == ICON_TRASH)
|
||||
is.icon2 = buff;
|
||||
else {
|
||||
else
|
||||
is.icon = buff;
|
||||
is.type = ICON_NORMAL;
|
||||
}
|
||||
|
||||
EDEBUG(ESTRLOC ": Icon is: %s\n", is.icon.c_str());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
if(!dconf.get("Desktop Entry", "Type", buff, buffsz)) {
|
||||
EDEBUG(ESTRLOC ": Missing mandatory Type key\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(strncmp(buff, "Link", 4) == 0) {
|
||||
edelib::DesktopFileType dtype = dconf.type();
|
||||
if(dtype == edelib::DESK_FILE_TYPE_LINK) {
|
||||
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;
|
||||
dconf.url(buff, buffsz);
|
||||
}
|
||||
else {
|
||||
is.cmd_is_url = false;
|
||||
dconf.exec(buff, buffsz);
|
||||
}
|
||||
|
||||
is.cmd = buff;
|
||||
|
||||
if(!dconf.name(buff, buffsz)) {
|
||||
EDEBUG(ESTRLOC ": No Name key\n");
|
||||
is.name = "(none)";
|
||||
} else
|
||||
is.name = buff;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -545,6 +523,55 @@ DesktopIcon* Desktop::below_mouse(int px, int py) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void Desktop::select_in_area(void) {
|
||||
if(!selbox->show)
|
||||
return;
|
||||
|
||||
int ax = selbox->x;
|
||||
int ay = selbox->y;
|
||||
int aw = selbox->w;
|
||||
int ah = selbox->h;
|
||||
|
||||
if(aw < 0) {
|
||||
ax += aw;
|
||||
aw = -aw;
|
||||
} else if(!aw)
|
||||
aw = 1;
|
||||
|
||||
if(ah < 0) {
|
||||
ay += ah;
|
||||
ah = -ah;
|
||||
} else if(!ah)
|
||||
ah = 1;
|
||||
|
||||
/*
|
||||
* XXX: This function can fail since icon coordinates are absolute (event_x_root)
|
||||
* but selbox use relative (event_root). It will work as expected if desktop is at x=0 y=0.
|
||||
* This should be checked further.
|
||||
*/
|
||||
unsigned int sz = icons.size();
|
||||
DesktopIcon* ic = NULL;
|
||||
|
||||
for(unsigned int i = 0; i < sz; i++) {
|
||||
ic = icons[i];
|
||||
EASSERT(ic != NULL && "Impossible to happen");
|
||||
|
||||
if(intersects(ax, ay, ax+aw, ay+ah, ic->x(), ic->y(), ic->w()+ic->x(), ic->h()+ic->y())) {
|
||||
if(!ic->is_focused()) {
|
||||
ic->do_focus();
|
||||
//ic->fast_redraw();
|
||||
ic->redraw();
|
||||
}
|
||||
} else {
|
||||
if(ic->is_focused()) {
|
||||
ic->do_unfocus();
|
||||
//ic->fast_redraw();
|
||||
ic->redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Desktop::notify_box(const char* msg, bool copy) {
|
||||
if(!msg)
|
||||
return;
|
||||
@ -577,9 +604,27 @@ void Desktop::notify_desktop_changed(void) {
|
||||
XFreeStringList(names);
|
||||
}
|
||||
|
||||
void Desktop::drop_source(const char* src, int x, int y) {
|
||||
void Desktop::drop_source(const char* src, int src_len, int x, int y) {
|
||||
if(!src)
|
||||
return;
|
||||
/*
|
||||
* must copy clipboard content since with given size since
|
||||
* it could be null chars in the middle of it
|
||||
*/
|
||||
char* src_copy = new char[src_len+1];
|
||||
int i;
|
||||
for(i = 0; i < src_len; i+=2) {
|
||||
if(isascii(src[i]) && src[i] != '\0')
|
||||
src_copy[i] = src[i];
|
||||
}
|
||||
src_copy[i] = '\0';
|
||||
|
||||
EDEBUG(ESTRLOC ": DND, received %s\n", src_copy);
|
||||
|
||||
delete [] src_copy;
|
||||
|
||||
return;
|
||||
|
||||
IconSettings is;
|
||||
is.x = x;
|
||||
is.y = y;
|
||||
@ -605,6 +650,49 @@ void Desktop::drop_source(const char* src, int x, int y) {
|
||||
add_icon(dic);
|
||||
}
|
||||
|
||||
void Desktop::draw(void) {
|
||||
/*
|
||||
if(damage() & (FL_DAMAGE_ALL | FL_DAMAGE_EXPOSE)) {
|
||||
Fl_Group::draw();
|
||||
EDEBUG("REDRAW ALL\n");
|
||||
} */
|
||||
if(damage() & (~FL_DAMAGE_CHILD & ~EDAMAGE_OVERLAY)) {
|
||||
draw_box();
|
||||
draw_label();
|
||||
|
||||
Fl_Widget* const* a = array();
|
||||
for(int i = children(); i--; ) {
|
||||
Fl_Widget& o = **a++;
|
||||
draw_child(o);
|
||||
draw_outside_label(o);
|
||||
}
|
||||
} else if(damage() & FL_DAMAGE_CHILD) {
|
||||
Fl_Widget* const* a = array();
|
||||
for(int i = children(); i--; )
|
||||
update_child(**a++);
|
||||
}
|
||||
|
||||
|
||||
if(damage() & (FL_DAMAGE_ALL | EDAMAGE_OVERLAY)) {
|
||||
clear_xoverlay();
|
||||
|
||||
if(selbox->show) {
|
||||
draw_xoverlay(selbox->x, selbox->y, selbox->w, selbox->h);
|
||||
EDEBUG("DRAW OVERLAY\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* now scan all icons and see if they needs redraw, and if do
|
||||
* just update their label since it is indicator of selection
|
||||
*/
|
||||
for(int i = 0; i < children(); i++) {
|
||||
if(child(i)->damage() == FL_DAMAGE_ALL) {
|
||||
update_child(*child(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Desktop::handle(int event) {
|
||||
switch(event) {
|
||||
case FL_FOCUS:
|
||||
@ -624,13 +712,18 @@ int Desktop::handle(int event) {
|
||||
EDEBUG(ESTRLOC ": DESKTOP CLICK !!!\n");
|
||||
if(!selectionbuff.empty()) {
|
||||
/*
|
||||
* only focused are in selectionbuff, so this is
|
||||
* fine to do; also will prevent full redraw when
|
||||
* is clicked on desktop
|
||||
* Only focused are in selectionbuff, so this is
|
||||
* fine to do; also will prevent full redraw when is clicked on desktop
|
||||
*/
|
||||
unfocus_all();
|
||||
selectionbuff.clear();
|
||||
}
|
||||
|
||||
// track position so moving can be deduced
|
||||
if(Fl::event_button() == 1) {
|
||||
selbox->x = Fl::event_x();
|
||||
selbox->y = Fl::event_y();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -651,7 +744,7 @@ int Desktop::handle(int event) {
|
||||
} else if(SELECTION_SINGLE) {
|
||||
if(!in_selection(tmp_icon)) {
|
||||
/*
|
||||
* for testing
|
||||
* for testing:
|
||||
* notify_box(tmp_icon->label());
|
||||
*/
|
||||
select_only(tmp_icon);
|
||||
@ -659,7 +752,7 @@ int Desktop::handle(int event) {
|
||||
} else if(Fl::event_button() == 3) {
|
||||
select_only(tmp_icon);
|
||||
/*
|
||||
* for testing
|
||||
* for testing:
|
||||
* notify_box(tmp_icon->label());
|
||||
*/
|
||||
}
|
||||
@ -685,6 +778,22 @@ int Desktop::handle(int event) {
|
||||
move_selection(Fl::event_x_root(), Fl::event_y_root(), false);
|
||||
} else {
|
||||
EDEBUG(ESTRLOC ": DRAG from desktop\n");
|
||||
/*
|
||||
* Moving is started with pushed button.
|
||||
* From this point selection box is created and is rolled until release
|
||||
*/
|
||||
if(selbox->x != 0 || selbox->y != 0) {
|
||||
selbox->w = Fl::event_x() - selbox->x;
|
||||
selbox->h = Fl::event_y() - selbox->y;
|
||||
|
||||
selbox->show = true;
|
||||
|
||||
// see if there some icons inside selection area
|
||||
select_in_area();
|
||||
|
||||
// redraw selection box
|
||||
damage(EDAMAGE_OVERLAY);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -693,6 +802,31 @@ int Desktop::handle(int event) {
|
||||
EDEBUG(ESTRLOC ": RELEASE from desktop\n");
|
||||
EDEBUG(ESTRLOC ": clicks: %i\n", Fl::event_is_click());
|
||||
|
||||
if(selbox->show) {
|
||||
selbox->x = selbox->y = selbox->w = selbox->h = 0;
|
||||
selbox->show = false;
|
||||
damage(EDAMAGE_OVERLAY);
|
||||
|
||||
/*
|
||||
* Now pickup those who are in is_focused() state.
|
||||
* Here is not used select() since it will fill selectionbuff with
|
||||
* redrawing whole window each time. This is not what we want.
|
||||
*
|
||||
* Possible flickers due overlay will be later removed when is
|
||||
* called move_selection(), which will in turn redraw icons again
|
||||
* after position them.
|
||||
*/
|
||||
if(!selectionbuff.empty())
|
||||
selectionbuff.clear();
|
||||
|
||||
for(unsigned int i = 0; i < icons.size(); i++) {
|
||||
if(icons[i]->is_focused())
|
||||
select(icons[i]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!selectionbuff.empty() && moving)
|
||||
move_selection(Fl::event_x_root(), Fl::event_y_root(), true);
|
||||
|
||||
@ -707,26 +841,26 @@ int Desktop::handle(int event) {
|
||||
|
||||
moving = false;
|
||||
return 1;
|
||||
|
||||
case FL_DND_ENTER:
|
||||
case FL_DND_DRAG:
|
||||
case FL_DND_LEAVE:
|
||||
EDEBUG("FL_DND_ENTER|FL_DND_DRAG|FL_DND_LEAVE\n");
|
||||
return 1;
|
||||
|
||||
case FL_DND_RELEASE:
|
||||
EDEBUG(ESTRLOC ": DND on desktop\n");
|
||||
//Fl::paste(*this);
|
||||
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());
|
||||
EDEBUG("=======> %s\n", Fl::event_text());
|
||||
EDEBUG("=======> %s\n", Fl::event_text());
|
||||
//drop_source(Fl::event_text(), Fl::event_length(), Fl::event_x_root(), Fl::event_y_root());
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Fl_Window::handle(event);
|
||||
return DESKTOP_WINDOW::handle(event);
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
@ -64,19 +64,29 @@ struct IconSettings {
|
||||
edelib::String key_name; // name used as key when storing positions
|
||||
};
|
||||
|
||||
// Selection overlay
|
||||
struct SelectionOverlay {
|
||||
int x, y, w, h;
|
||||
bool show;
|
||||
};
|
||||
|
||||
class Wallpaper;
|
||||
class DesktopIcon;
|
||||
class NotifyBox;
|
||||
|
||||
typedef edelib::vector<DesktopIcon*> DesktopIconList;
|
||||
|
||||
class Desktop : public Fl_Window {
|
||||
#define DESKTOP_WINDOW Fl_Window
|
||||
|
||||
class Desktop : public DESKTOP_WINDOW {
|
||||
private:
|
||||
static Desktop* pinstance;
|
||||
|
||||
int selection_x, selection_y;
|
||||
bool moving;
|
||||
|
||||
SelectionOverlay* selbox;
|
||||
|
||||
GlobalIconSettings gisett;
|
||||
DesktopSettings* dsett;
|
||||
|
||||
@ -98,7 +108,9 @@ class Desktop : public Fl_Window {
|
||||
bool in_selection(const DesktopIcon* ic);
|
||||
void move_selection(int x, int y, bool apply);
|
||||
|
||||
void drop_source(const char* src, int x, int y);
|
||||
void select_in_area(void);
|
||||
|
||||
void drop_source(const char* src, int src_len, int x, int y);
|
||||
|
||||
//DesktopIcon* below_mouse(int px, int py);
|
||||
|
||||
@ -108,6 +120,7 @@ class Desktop : public Fl_Window {
|
||||
|
||||
virtual void show(void);
|
||||
virtual void hide(void);
|
||||
virtual void draw(void);
|
||||
virtual int handle(int event);
|
||||
|
||||
static void init(void);
|
||||
|
Loading…
Reference in New Issue
Block a user