Root/
Source at commit 36c4205 created 10 years 8 months ago. By Paul Cercueil, Don't try to read OPKs in /media/./apps and /media/../apps | |
---|---|
1 | /*************************************************************************** |
2 | * Copyright (C) 2006 by Massimiliano Torromeo * |
3 | * massimiliano.torromeo@gmail.com * |
4 | * * |
5 | * This program is free software; you can redistribute it and/or modify * |
6 | * it under the terms of the GNU General Public License as published by * |
7 | * the Free Software Foundation; either version 2 of the License, or * |
8 | * (at your option) any later version. * |
9 | * * |
10 | * This program is distributed in the hope that it will be useful, * |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
13 | * GNU General Public License for more details. * |
14 | * * |
15 | * You should have received a copy of the GNU General Public License * |
16 | * along with this program; if not, write to the * |
17 | * Free Software Foundation, Inc., * |
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
19 | ***************************************************************************/ |
20 | |
21 | #include <sstream> |
22 | #include <sys/stat.h> |
23 | #include <sys/types.h> |
24 | #include <dirent.h> |
25 | #include <algorithm> |
26 | #include <math.h> |
27 | #include <fstream> |
28 | #include <unistd.h> |
29 | |
30 | #ifdef HAVE_LIBOPK |
31 | #include <opk.h> |
32 | #endif |
33 | |
34 | #include "gmenu2x.h" |
35 | #include "linkapp.h" |
36 | #include "menu.h" |
37 | #include "monitor.h" |
38 | #include "filelister.h" |
39 | #include "utilities.h" |
40 | #include "debug.h" |
41 | |
42 | using namespace std; |
43 | |
44 | Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) |
45 | : gmenu2x(gmenu2x) |
46 | , ts(ts) |
47 | { |
48 | iFirstDispSection = 0; |
49 | |
50 | readSections(GMENU2X_SYSTEM_DIR "/sections"); |
51 | readSections(GMenu2X::getHome() + "/sections"); |
52 | |
53 | sort(sections.begin(),sections.end(),case_less()); |
54 | setSectionIndex(0); |
55 | readLinks(); |
56 | |
57 | #ifdef HAVE_LIBOPK |
58 | { |
59 | struct dirent *dptr; |
60 | DIR *dirp = opendir(CARD_ROOT); |
61 | if (dirp) { |
62 | while ((dptr = readdir(dirp))) { |
63 | if (dptr->d_type != DT_DIR) |
64 | continue; |
65 | |
66 | if (!strcmp(dptr->d_name, ".") || !strcmp(dptr->d_name, "..")) |
67 | continue; |
68 | |
69 | string path = (string) CARD_ROOT + "/" + dptr->d_name + "/apps"; |
70 | if (access(path.c_str(), F_OK)) |
71 | continue; |
72 | |
73 | readPackages(path); |
74 | #ifdef ENABLE_INOTIFY |
75 | monitors.push_back(new Monitor(path.c_str())); |
76 | #endif |
77 | } |
78 | closedir(dirp); |
79 | } |
80 | } |
81 | #endif |
82 | |
83 | orderLinks(); |
84 | } |
85 | |
86 | Menu::~Menu() { |
87 | freeLinks(); |
88 | } |
89 | |
90 | uint Menu::firstDispRow() { |
91 | return iFirstDispRow; |
92 | } |
93 | |
94 | void Menu::readSections(std::string parentDir) |
95 | { |
96 | DIR *dirp; |
97 | struct dirent *dptr; |
98 | |
99 | dirp = opendir(parentDir.c_str()); |
100 | if (!dirp) return; |
101 | |
102 | while ((dptr = readdir(dirp))) { |
103 | if (dptr->d_name[0] == '.' || dptr->d_type != DT_DIR) |
104 | continue; |
105 | |
106 | string filepath = parentDir + "/" + dptr->d_name; |
107 | |
108 | if (find(sections.begin(), sections.end(), (string)dptr->d_name) == sections.end()) { |
109 | sections.push_back((string)dptr->d_name); |
110 | vector<Link*> ll; |
111 | links.push_back(ll); |
112 | } |
113 | } |
114 | |
115 | closedir(dirp); |
116 | } |
117 | |
118 | void Menu::loadIcons() { |
119 | //reload section icons |
120 | for (uint i=0; i<sections.size(); i++) { |
121 | string sectionIcon = "sections/"+sections[i]+".png"; |
122 | if (!gmenu2x->sc.getSkinFilePath(sectionIcon).empty()) |
123 | gmenu2x->sc.add("skin:"+sectionIcon); |
124 | |
125 | //check link's icons |
126 | string linkIcon; |
127 | for (uint x=0; x<sectionLinks(i)->size(); x++) { |
128 | linkIcon = sectionLinks(i)->at(x)->getIcon(); |
129 | LinkApp *linkapp = dynamic_cast<LinkApp*>(sectionLinks(i)->at(x)); |
130 | |
131 | if (linkIcon.substr(0,5)=="skin:") { |
132 | linkIcon = gmenu2x->sc.getSkinFilePath(linkIcon.substr(5,linkIcon.length())); |
133 | if (linkapp != NULL && !fileExists(linkIcon)) |
134 | linkapp->searchIcon(); |
135 | else |
136 | sectionLinks(i)->at(x)->setIconPath(linkIcon); |
137 | |
138 | } else if (!fileExists(linkIcon)) { |
139 | if (linkapp != NULL) linkapp->searchIcon(); |
140 | } |
141 | } |
142 | } |
143 | } |
144 | |
145 | /*==================================== |
146 | SECTION MANAGEMENT |
147 | ====================================*/ |
148 | void Menu::freeLinks() { |
149 | for (vector< vector<Link*> >::iterator section = links.begin(); section<links.end(); section++) |
150 | for (vector<Link*>::iterator link = section->begin(); link<section->end(); link++) |
151 | delete *link; |
152 | } |
153 | |
154 | vector<Link*> *Menu::sectionLinks(int i) { |
155 | if (i<0 || i>(int)links.size()) |
156 | i = selSectionIndex(); |
157 | |
158 | if (i<0 || i>(int)links.size()) |
159 | return NULL; |
160 | |
161 | return &links[i]; |
162 | } |
163 | |
164 | void Menu::decSectionIndex() { |
165 | setSectionIndex(iSection-1); |
166 | } |
167 | |
168 | void Menu::incSectionIndex() { |
169 | setSectionIndex(iSection+1); |
170 | } |
171 | |
172 | uint Menu::firstDispSection() { |
173 | return iFirstDispSection; |
174 | } |
175 | |
176 | int Menu::selSectionIndex() { |
177 | return iSection; |
178 | } |
179 | |
180 | const string &Menu::selSection() { |
181 | return sections[iSection]; |
182 | } |
183 | |
184 | void Menu::setSectionIndex(int i) { |
185 | if (i<0) |
186 | i=sections.size()-1; |
187 | else if (i>=(int)sections.size()) |
188 | i=0; |
189 | iSection = i; |
190 | |
191 | if (i>(int)iFirstDispSection+2) |
192 | iFirstDispSection = i-2; |
193 | else if (i<(int)iFirstDispSection) |
194 | iFirstDispSection = i; |
195 | |
196 | iLink = 0; |
197 | iFirstDispRow = 0; |
198 | } |
199 | |
200 | /*==================================== |
201 | LINKS MANAGEMENT |
202 | ====================================*/ |
203 | bool Menu::addActionLink(uint section, const string &title, LinkRunAction action, const string &description, const string &icon) { |
204 | if (section>=sections.size()) return false; |
205 | |
206 | Link *link = new Link(gmenu2x, ts, action); |
207 | link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); |
208 | link->setTitle(title); |
209 | link->setDescription(description); |
210 | if (gmenu2x->sc.exists(icon) || (icon.substr(0,5)=="skin:" && !gmenu2x->sc.getSkinFilePath(icon.substr(5,icon.length())).empty()) || fileExists(icon)) |
211 | link->setIcon(icon); |
212 | |
213 | sectionLinks(section)->push_back(link); |
214 | return true; |
215 | } |
216 | |
217 | bool Menu::addLink(string path, string file, string section) { |
218 | if (section=="") |
219 | section = selSection(); |
220 | else if (find(sections.begin(),sections.end(),section)==sections.end()) { |
221 | //section directory doesn't exists |
222 | if (!addSection(section)) |
223 | return false; |
224 | } |
225 | |
226 | //strip the extension from the filename |
227 | string title = file; |
228 | string::size_type pos = title.rfind("."); |
229 | if (pos!=string::npos && pos>0) { |
230 | string ext = title.substr(pos, title.length()); |
231 | transform(ext.begin(), ext.end(), ext.begin(), ::tolower); |
232 | title = title.substr(0, pos); |
233 | } |
234 | |
235 | string linkpath = GMenu2X::getHome() + "/sections"; |
236 | if (!fileExists(linkpath)) |
237 | mkdir(linkpath.c_str(), 0755); |
238 | |
239 | linkpath = GMenu2X::getHome() + "/sections/" + section; |
240 | if (!fileExists(linkpath)) |
241 | mkdir(linkpath.c_str(), 0755); |
242 | |
243 | linkpath += "/" + title; |
244 | int x=2; |
245 | while (fileExists(linkpath)) { |
246 | stringstream ss; |
247 | linkpath = ""; |
248 | ss << x; |
249 | ss >> linkpath; |
250 | linkpath = GMenu2X::getHome()+"/sections/"+section+"/"+title+linkpath; |
251 | x++; |
252 | } |
253 | |
254 | INFO("Adding link: '%s'\n", linkpath.c_str()); |
255 | |
256 | if (path[path.length()-1]!='/') path += "/"; |
257 | //search for a manual |
258 | pos = file.rfind("."); |
259 | string exename = path+file.substr(0,pos); |
260 | string manual = ""; |
261 | if (fileExists(exename+".man.png")) { |
262 | manual = exename+".man.png"; |
263 | } else if (fileExists(exename+".man.jpg")) { |
264 | manual = exename+".man.jpg"; |
265 | } else if (fileExists(exename+".man.jpeg")) { |
266 | manual = exename+".man.jpeg"; |
267 | } else if (fileExists(exename+".man.bmp")) { |
268 | manual = exename+".man.bmp"; |
269 | } else if (fileExists(exename+".man.txt")) { |
270 | manual = exename+".man.txt"; |
271 | } else { |
272 | //scan directory for a file like *readme* |
273 | FileLister fl(path, false); |
274 | fl.setFilter(".txt"); |
275 | fl.browse(); |
276 | bool found = false; |
277 | for (uint x=0; x<fl.size() && !found; x++) { |
278 | string lcfilename = fl[x]; |
279 | |
280 | if (lcfilename.find("readme") != string::npos) { |
281 | found = true; |
282 | manual = path+fl.getFiles()[x]; |
283 | } |
284 | } |
285 | } |
286 | |
287 | INFO("Manual: '%s'\n", manual.c_str()); |
288 | |
289 | string shorttitle=title, description="", exec=path+file, icon=""; |
290 | if (fileExists(exename+".png")) icon = exename+".png"; |
291 | |
292 | //Reduce title lenght to fit the link width |
293 | if (gmenu2x->font->getTextWidth(shorttitle)>gmenu2x->skinConfInt["linkWidth"]) { |
294 | while (gmenu2x->font->getTextWidth(shorttitle+"..")>gmenu2x->skinConfInt["linkWidth"]) |
295 | shorttitle = shorttitle.substr(0,shorttitle.length()-1); |
296 | shorttitle += ".."; |
297 | } |
298 | |
299 | ofstream f(linkpath.c_str()); |
300 | if (f.is_open()) { |
301 | f << "title=" << shorttitle << endl; |
302 | f << "exec=" << exec << endl; |
303 | if (!description.empty()) f << "description=" << description << endl; |
304 | if (!icon.empty()) f << "icon=" << icon << endl; |
305 | if (!manual.empty()) f << "manual=" << manual << endl; |
306 | f.close(); |
307 | sync(); |
308 | int isection = find(sections.begin(),sections.end(),section) - sections.begin(); |
309 | if (isection>=0 && isection<(int)sections.size()) { |
310 | |
311 | INFO("Section: '%s(%i)'\n", sections[isection].c_str(), isection); |
312 | |
313 | LinkApp* link = new LinkApp(gmenu2x, ts, gmenu2x->input, linkpath.c_str()); |
314 | link->setSize(gmenu2x->skinConfInt["linkWidth"],gmenu2x->skinConfInt["linkHeight"]); |
315 | links[isection].push_back( link ); |
316 | } |
317 | } else { |
318 | |
319 | ERROR("Error while opening the file '%s' for write.\n", linkpath.c_str()); |
320 | |
321 | return false; |
322 | } |
323 | |
324 | return true; |
325 | } |
326 | |
327 | bool Menu::addSection(const string §ionName) { |
328 | string sectiondir = GMenu2X::getHome() + "/sections"; |
329 | if (!fileExists(sectiondir)) |
330 | mkdir(sectiondir.c_str(), 0755); |
331 | |
332 | sectiondir = sectiondir + "/" + sectionName; |
333 | if (mkdir(sectiondir.c_str(), 0755) == 0) { |
334 | sections.push_back(sectionName); |
335 | vector<Link*> ll; |
336 | links.push_back(ll); |
337 | return true; |
338 | } |
339 | return false; |
340 | } |
341 | |
342 | void Menu::deleteSelectedLink() |
343 | { |
344 | bool icon_used = false; |
345 | string iconpath = selLink()->getIconPath(); |
346 | |
347 | INFO("Deleting link '%s'\n", selLink()->getTitle().c_str()); |
348 | |
349 | if (selLinkApp()!=NULL) |
350 | unlink(selLinkApp()->getFile().c_str()); |
351 | sectionLinks()->erase( sectionLinks()->begin() + selLinkIndex() ); |
352 | setLinkIndex(selLinkIndex()); |
353 | |
354 | for (vector< vector<Link*> >::iterator section = links.begin(); |
355 | !icon_used && section<links.end(); section++) |
356 | for (vector<Link*>::iterator link = section->begin(); |
357 | !icon_used && link<section->end(); link++) |
358 | icon_used = !iconpath.compare((*link)->getIconPath()); |
359 | |
360 | if (!icon_used) |
361 | gmenu2x->sc.del(iconpath); |
362 | } |
363 | |
364 | void Menu::deleteSelectedSection() { |
365 | INFO("Deleting section '%s'\n", selSection().c_str()); |
366 | |
367 | gmenu2x->sc.del("sections/"+selSection()+".png"); |
368 | links.erase( links.begin()+selSectionIndex() ); |
369 | sections.erase( sections.begin()+selSectionIndex() ); |
370 | setSectionIndex(0); //reload sections |
371 | } |
372 | |
373 | bool Menu::linkChangeSection(uint linkIndex, uint oldSectionIndex, uint newSectionIndex) { |
374 | if (oldSectionIndex<sections.size() && newSectionIndex<sections.size() && linkIndex<sectionLinks(oldSectionIndex)->size()) { |
375 | sectionLinks(newSectionIndex)->push_back( sectionLinks(oldSectionIndex)->at(linkIndex) ); |
376 | sectionLinks(oldSectionIndex)->erase( sectionLinks(oldSectionIndex)->begin()+linkIndex ); |
377 | //Select the same link in the new position |
378 | setSectionIndex(newSectionIndex); |
379 | setLinkIndex(sectionLinks(newSectionIndex)->size()-1); |
380 | return true; |
381 | } |
382 | return false; |
383 | } |
384 | |
385 | void Menu::linkLeft() { |
386 | if (iLink%gmenu2x->linkColumns == 0) |
387 | setLinkIndex( sectionLinks()->size()>iLink+gmenu2x->linkColumns-1 ? iLink+gmenu2x->linkColumns-1 : sectionLinks()->size()-1 ); |
388 | else |
389 | setLinkIndex(iLink-1); |
390 | } |
391 | |
392 | void Menu::linkRight() { |
393 | if (iLink%gmenu2x->linkColumns == (gmenu2x->linkColumns-1) || iLink == (int)sectionLinks()->size()-1) |
394 | setLinkIndex(iLink-iLink%gmenu2x->linkColumns); |
395 | else |
396 | setLinkIndex(iLink+1); |
397 | } |
398 | |
399 | #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) |
400 | |
401 | void Menu::linkUp() { |
402 | int l = iLink-gmenu2x->linkColumns; |
403 | if (l<0) { |
404 | unsigned int rows; |
405 | rows = DIV_ROUND_UP(sectionLinks()->size(), gmenu2x->linkColumns); |
406 | l = (rows*gmenu2x->linkColumns)+l; |
407 | if (l >= (int)sectionLinks()->size()) |
408 | l -= gmenu2x->linkColumns; |
409 | } |
410 | setLinkIndex(l); |
411 | } |
412 | |
413 | void Menu::linkDown() { |
414 | uint l = iLink+gmenu2x->linkColumns; |
415 | if (l >= sectionLinks()->size()) { |
416 | unsigned int rows, curCol; |
417 | rows = DIV_ROUND_UP(sectionLinks()->size(), gmenu2x->linkColumns); |
418 | curCol = DIV_ROUND_UP(iLink + 1, gmenu2x->linkColumns); |
419 | if (rows > curCol) |
420 | l = sectionLinks()->size()-1; |
421 | else |
422 | l %= gmenu2x->linkColumns; |
423 | } |
424 | setLinkIndex(l); |
425 | } |
426 | |
427 | int Menu::selLinkIndex() { |
428 | return iLink; |
429 | } |
430 | |
431 | Link *Menu::selLink() { |
432 | if (sectionLinks()->size()==0) return NULL; |
433 | return sectionLinks()->at(iLink); |
434 | } |
435 | |
436 | LinkApp *Menu::selLinkApp() { |
437 | return dynamic_cast<LinkApp*>(selLink()); |
438 | } |
439 | |
440 | void Menu::setLinkIndex(int i) { |
441 | if (i<0) |
442 | i=sectionLinks()->size()-1; |
443 | else if (i>=(int)sectionLinks()->size()) |
444 | i=0; |
445 | |
446 | if (i>=(int)(iFirstDispRow*gmenu2x->linkColumns+gmenu2x->linkColumns*gmenu2x->linkRows)) |
447 | iFirstDispRow = i/gmenu2x->linkColumns-gmenu2x->linkRows+1; |
448 | else if (i<(int)(iFirstDispRow*gmenu2x->linkColumns)) |
449 | iFirstDispRow = i/gmenu2x->linkColumns; |
450 | |
451 | iLink = i; |
452 | } |
453 | |
454 | #ifdef HAVE_LIBOPK |
455 | void Menu::openPackage(std::string path) |
456 | { |
457 | /* First try to remove existing links of the same OPK |
458 | * (needed for instance when an OPK is modified) */ |
459 | removePackageLink(path); |
460 | |
461 | struct OPK *opk = opk_open(path.c_str()); |
462 | if (!opk) { |
463 | ERROR("Unable to open OPK %s\n", path.c_str()); |
464 | return; |
465 | } |
466 | |
467 | for (;;) { |
468 | unsigned int i; |
469 | bool has_metadata = false; |
470 | LinkApp *link; |
471 | |
472 | for (;;) { |
473 | string::size_type pos; |
474 | const char *name; |
475 | int ret = opk_open_metadata(opk, &name); |
476 | if (ret < 0) { |
477 | ERROR("Error while loading meta-data\n"); |
478 | break; |
479 | } else if (!ret) |
480 | break; |
481 | |
482 | /* Strip .desktop */ |
483 | string metadata(name); |
484 | pos = metadata.rfind('.'); |
485 | metadata = metadata.substr(0, pos); |
486 | |
487 | /* Keep only the platform name */ |
488 | pos = metadata.rfind('.'); |
489 | metadata = metadata.substr(pos + 1); |
490 | |
491 | if (metadata.compare(PLATFORM) == 0) { |
492 | has_metadata = true; |
493 | break; |
494 | } |
495 | } |
496 | |
497 | if (!has_metadata) |
498 | break; |
499 | |
500 | link = new LinkApp(gmenu2x, ts, gmenu2x->input, path.c_str(), opk); |
501 | link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); |
502 | |
503 | addSection(link->getCategory()); |
504 | for (i = 0; i < sections.size(); i++) { |
505 | if (sections[i] == link->getCategory()) { |
506 | links[i].push_back(link); |
507 | break; |
508 | } |
509 | } |
510 | } |
511 | |
512 | opk_close(opk); |
513 | orderLinks(); |
514 | } |
515 | |
516 | void Menu::readPackages(std::string parentDir) |
517 | { |
518 | DIR *dirp; |
519 | struct dirent *dptr; |
520 | vector<string> linkfiles; |
521 | |
522 | dirp = opendir(parentDir.c_str()); |
523 | if (!dirp) |
524 | return; |
525 | |
526 | while ((dptr = readdir(dirp))) { |
527 | char *c; |
528 | |
529 | if (dptr->d_type != DT_REG) |
530 | continue; |
531 | |
532 | c = strrchr(dptr->d_name, '.'); |
533 | if (!c) /* File without extension */ |
534 | continue; |
535 | |
536 | if (strcasecmp(c + 1, "opk")) |
537 | continue; |
538 | |
539 | if (dptr->d_name[0] == '.') { |
540 | // Ignore hidden files. |
541 | // Mac OS X places these on SD cards, probably to store metadata. |
542 | continue; |
543 | } |
544 | |
545 | openPackage(parentDir + '/' + dptr->d_name); |
546 | } |
547 | |
548 | closedir(dirp); |
549 | } |
550 | |
551 | #ifdef ENABLE_INOTIFY |
552 | /* Remove all links that correspond to the given path. |
553 | * If "path" is a directory, it will remove all links that |
554 | * correspond to an OPK present in the directory. */ |
555 | void Menu::removePackageLink(std::string path) |
556 | { |
557 | for (vector< vector<Link*> >::iterator section = links.begin(); |
558 | section < links.end(); section++) { |
559 | for (vector<Link*>::iterator link = section->begin(); |
560 | link < section->end(); link++) { |
561 | LinkApp *app = dynamic_cast<LinkApp *> (*link); |
562 | if (!app || !app->isOpk() || app->getOpkFile().empty()) |
563 | continue; |
564 | |
565 | if (app->getOpkFile().compare(0, path.size(), path) == 0) { |
566 | DEBUG("Removing link corresponding to package %s\n", |
567 | app->getOpkFile().c_str()); |
568 | section->erase(link); |
569 | if (section - links.begin() == iSection |
570 | && iLink == (int) section->size()) |
571 | setLinkIndex(iLink - 1); |
572 | link--; |
573 | } |
574 | } |
575 | } |
576 | } |
577 | #endif |
578 | #endif |
579 | |
580 | void Menu::readLinksOfSection(std::string path, std::vector<std::string> &linkfiles) |
581 | { |
582 | DIR *dirp; |
583 | struct dirent *dptr; |
584 | |
585 | if ((dirp = opendir(path.c_str())) == NULL) return; |
586 | |
587 | while ((dptr = readdir(dirp))) { |
588 | if (dptr->d_type != DT_REG) continue; |
589 | string filepath = path + "/" + dptr->d_name; |
590 | linkfiles.push_back(filepath); |
591 | } |
592 | |
593 | closedir(dirp); |
594 | } |
595 | |
596 | static bool compare_links(Link *a, Link *b) |
597 | { |
598 | return a->getTitle().compare(b->getTitle()) <= 0; |
599 | } |
600 | |
601 | void Menu::orderLinks() |
602 | { |
603 | for (std::vector< std::vector<Link *> >::iterator section = links.begin(); |
604 | section < links.end(); section++) |
605 | std::sort(section->begin(), section->end(), compare_links); |
606 | } |
607 | |
608 | void Menu::readLinks() { |
609 | vector<string> linkfiles; |
610 | |
611 | iLink = 0; |
612 | iFirstDispRow = 0; |
613 | string filepath; |
614 | |
615 | for (uint i=0; i<links.size(); i++) { |
616 | links[i].clear(); |
617 | linkfiles.clear(); |
618 | |
619 | int correct = (i>sections.size() ? iSection : i); |
620 | |
621 | readLinksOfSection(GMENU2X_SYSTEM_DIR "/sections/" |
622 | + sections[correct], linkfiles); |
623 | |
624 | readLinksOfSection(GMenu2X::getHome() + "/sections/" |
625 | + sections[correct], linkfiles); |
626 | |
627 | sort(linkfiles.begin(), linkfiles.end(),case_less()); |
628 | for (uint x=0; x<linkfiles.size(); x++) { |
629 | LinkApp *link = new LinkApp(gmenu2x, ts, gmenu2x->input, linkfiles[x].c_str()); |
630 | link->setSize(gmenu2x->skinConfInt["linkWidth"], gmenu2x->skinConfInt["linkHeight"]); |
631 | if (link->targetExists()) |
632 | links[i].push_back(link); |
633 | else |
634 | delete link; |
635 | } |
636 | } |
637 | } |
638 | |
639 | void Menu::renameSection(int index, const string &name) { |
640 | sections[index] = name; |
641 | } |
642 |
Branches:
install_locations
master
opkrun
packages