From ea32acf7faefe3bc34d85ca3d52b7e737dff8fac Mon Sep 17 00:00:00 2001 From: Sanel Zukan Date: Mon, 25 Jun 2007 09:20:49 +0000 Subject: [PATCH] .desktop files are read by DesktopFile Added selection box, but needs more work with redrawing DND mess; still not work as expected --- eiconman/DesktopIcon.cpp | 1 + eiconman/Utils.cpp | 2 +- eiconman/Wallpaper.cpp | 20 +-- eiconman/eiconman.cpp | 266 +++++++++++++++++++++++++++++---------- eiconman/eiconman.h | 17 ++- 5 files changed, 219 insertions(+), 87 deletions(-) diff --git a/eiconman/DesktopIcon.cpp b/eiconman/DesktopIcon.cpp index 9ec0869..45d08a7 100644 --- a/eiconman/DesktopIcon.cpp +++ b/eiconman/DesktopIcon.cpp @@ -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) { diff --git a/eiconman/Utils.cpp b/eiconman/Utils.cpp index 608c583..b3e75b5 100644 --- a/eiconman/Utils.cpp +++ b/eiconman/Utils.cpp @@ -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); diff --git a/eiconman/Wallpaper.cpp b/eiconman/Wallpaper.cpp index 24441c7..d45ff2f 100644 --- a/eiconman/Wallpaper.cpp +++ b/eiconman/Wallpaper.cpp @@ -430,7 +430,7 @@ void Wallpaper::draw(void) { #endif } -#include +//#include 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); diff --git a/eiconman/eiconman.cpp b/eiconman/eiconman.cpp index d1a390b..d3480ab 100644 --- a/eiconman/eiconman.cpp +++ b/eiconman/eiconman.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -31,9 +32,12 @@ #include #include // rand, srand #include // time +#include // 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() { diff --git a/eiconman/eiconman.h b/eiconman/eiconman.h index 8f33b1c..20c4f77 100644 --- a/eiconman/eiconman.h +++ b/eiconman/eiconman.h @@ -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 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);