Ticket #4446: patch2

File patch2, 33.9 KB (added by stpere, 11 years ago)
Line 
1diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage
2index 84af617..74dac03 100644
3--- a/build/jam/HaikuImage
4+++ b/build/jam/HaikuImage
5@@ -648,14 +648,14 @@ AddFilesToHaikuImage system add-ons media : $(SYSTEM_ADD_ONS_MEDIA) ;
6 AddFilesToHaikuImage system add-ons media plugins
7 : $(SYSTEM_ADD_ONS_MEDIA_PLUGINS) ;
8 AddFilesToHaikuImage system add-ons Tracker
9- : FileType-F Mark\ as… Mark\ as\ Read-R Open\ Target\ Folder-O
10- Open\ Terminal-T ZipOMatic-Z ;
11+ : FileType Mark\ as… Mark\ as\ Read Open\ Target\ Folder
12+ Open\ Terminal ZipOMatic ;
13 AddSymlinkToHaikuImage system add-ons Tracker
14- : /boot/system/preferences/Backgrounds : Background-B ;
15+ : /boot/system/preferences/Backgrounds : Background ;
16 AddSymlinkToHaikuImage system add-ons Tracker
17- : /boot/system/apps/TextSearch : TextSearch-G ;
18+ : /boot/system/apps/TextSearch : TextSearch ;
19 AddSymlinkToHaikuImage system add-ons Tracker
20- : /boot/system/apps/DiskUsage : DiskUsage-I ;
21+ : /boot/system/apps/DiskUsage : DiskUsage ;
22 AddFilesToHaikuImage system add-ons input_server devices
23 : <input>keyboard <input>mouse <input>tablet <input>wacom ;
24 AddFilesToHaikuImage system add-ons input_server filters
25diff --git a/src/add-ons/input_server/filters/shortcut_catcher/Jamfile b/src/add-ons/input_server/filters/shortcut_catcher/Jamfile
26index 0182b9f..f80ca1d 100644
27--- a/src/add-ons/input_server/filters/shortcut_catcher/Jamfile
28+++ b/src/add-ons/input_server/filters/shortcut_catcher/Jamfile
29@@ -2,6 +2,8 @@ SubDir HAIKU_TOP src add-ons input_server filters shortcut_catcher ;
30
31 SetSubDirSupportedPlatformsBeOSCompatible ;
32
33+UsePrivateHeaders storage ;
34+
35 # Common files used here and in the app
36 StaticLibrary libshortcuts_shared.a :
37 BitFieldTesters.cpp
38diff --git a/src/add-ons/input_server/filters/shortcut_catcher/KeyCommandMap.cpp b/src/add-ons/input_server/filters/shortcut_catcher/KeyCommandMap.cpp
39index 40e6cae..9d2ad01 100644
40--- a/src/add-ons/input_server/filters/shortcut_catcher/KeyCommandMap.cpp
41+++ b/src/add-ons/input_server/filters/shortcut_catcher/KeyCommandMap.cpp
42@@ -14,9 +14,12 @@
43 #include <Beep.h>
44 #include <Entry.h>
45 #include <File.h>
46+#include <FindDirectory.h>
47 #include <MessageFilter.h>
48 #include <NodeMonitor.h>
49 #include <OS.h>
50+#include <Path.h>
51+#include <PathMonitor.h>
52 #include <WindowScreen.h>
53
54 #include "BitFieldTesters.h"
55@@ -71,20 +74,19 @@ KeyCommandMap::KeyCommandMap(const char* file)
56 strcpy(fFileName, file);
57
58 BEntry fileEntry(fFileName);
59- // TODO: Using a BPathMonitor would be preferable. See discussion linked off
60- // ticket #6278.
61- if (!fileEntry.Exists())
62- BFile file(fFileName, B_READ_ONLY | B_CREATE_FILE);
63-
64- if (fileEntry.InitCheck() == B_NO_ERROR) {
65- node_ref nref;
66
67- if (fileEntry.GetNodeRef(&nref) == B_NO_ERROR)
68- watch_node(&nref, B_WATCH_STAT, this);
69+ BEntry parent;
70+ BPath parentPath;
71+ if (fileEntry.GetParent(&parent) == B_OK
72+ && parent.GetPath(&parentPath) == B_OK) {
73+ BPrivate::BPathMonitor::StartWatching(parentPath.Path(),
74+ B_WATCH_STAT | B_WATCH_FILES_ONLY, this);
75 }
76
77- BMessage msg(FILE_UPDATED);
78- PostMessage(&msg);
79+ if (fileEntry.InitCheck() == B_NO_ERROR) {
80+ BMessage msg(FILE_UPDATED);
81+ PostMessage(&msg);
82+ }
83
84 fPort = create_port(1, SHORTCUTS_CATCHER_PORT_NAME);
85 _PutMessageToPort();
86@@ -100,7 +102,7 @@ KeyCommandMap::~KeyCommandMap()
87 for (int i = fInjects.CountItems() - 1; i >= 0; i--)
88 delete (BMessage*)fInjects.ItemAt(i);
89
90- stop_watching(this);
91+ BPrivate::BPathMonitor::StopWatching(BMessenger(this, this));
92 // don't know if this is necessary, but it can't hurt
93 _DeleteHKSList(fSpecs);
94 delete [] fFileName;
95@@ -219,7 +221,21 @@ KeyCommandMap::MessageReceived(BMessage* msg)
96 _PutMessageToPort();
97 break;
98
99- case B_NODE_MONITOR:
100+ case B_PATH_MONITOR:
101+ {
102+ const char* path = "";
103+ // only fall through for appropriate file
104+ if (!(msg->FindString("path", &path) == B_OK
105+ && strcmp(path, fFileName) == 0)) {
106+ dev_t device;
107+ ino_t node;
108+ if (msg->FindInt32("device", &device) != B_OK
109+ && msg->FindInt64("node", &node) != B_OK
110+ && device != fNodeRef.device
111+ && node != fNodeRef.node)
112+ break;
113+ }
114+ }
115 case FILE_UPDATED:
116 {
117 BMessage fileMsg;
118@@ -231,6 +247,7 @@ KeyCommandMap::MessageReceived(BMessage* msg)
119 // defaults to no deletion
120 BList* oldList = NULL;
121
122+ file.GetNodeRef(&fNodeRef);
123 int i = 0;
124 BMessage msg;
125 while (fileMsg.FindMessage("spec", i++, &msg) == B_OK) {
126@@ -241,6 +258,27 @@ KeyCommandMap::MessageReceived(BMessage* msg)
127 if (msg.FindInt32("key", (int32*) &key) == B_OK
128 && msg.FindMessage("act", &actMsg) == B_OK
129 && msg.FindMessage("modtester", &testerMsg) == B_OK) {
130+
131+ // Leave handling of add-ons shortcuts to Tracker
132+ BString command;
133+ if (actMsg.FindString("largv", &command) == B_OK) {
134+ BPath path;
135+ if (find_directory(B_SYSTEM_ADDONS_DIRECTORY, &path) == B_OK) {
136+ path.Append("Tracker/");
137+ if (command.FindFirst(path.Path()) != B_ERROR)
138+ continue;
139+ }
140+ if (find_directory(B_COMMON_ADDONS_DIRECTORY, &path) == B_OK) {
141+ path.Append("Tracker/");
142+ if (command.FindFirst(path.Path()) != B_ERROR)
143+ continue;
144+ }
145+ if (find_directory(B_USER_ADDONS_DIRECTORY, &path) == B_OK) {
146+ path.Append("Tracker/");
147+ if (command.FindFirst(path.Path()) != B_ERROR)
148+ continue;
149+ }
150+ }
151 BArchivable* archive = instantiate_object(&testerMsg);
152 if (BitFieldTester* tester
153 = dynamic_cast<BitFieldTester*>(archive)) {
154@@ -282,7 +320,7 @@ KeyCommandMap::_DeleteHKSList(BList* l)
155 if (l != NULL) {
156 int num = l->CountItems();
157 for (int i = 0; i < num; i++)
158- delete ((hks*) l->ItemAt(i));
159+ delete ((hks*) l->ItemAt(0));
160 delete l;
161 }
162 }
163diff --git a/src/add-ons/input_server/filters/shortcut_catcher/KeyCommandMap.h b/src/add-ons/input_server/filters/shortcut_catcher/KeyCommandMap.h
164index b70e7c6..9ade3d0 100644
165--- a/src/add-ons/input_server/filters/shortcut_catcher/KeyCommandMap.h
166+++ b/src/add-ons/input_server/filters/shortcut_catcher/KeyCommandMap.h
167@@ -18,6 +18,7 @@
168 #include <Messenger.h>
169 #include <Message.h>
170 #include <MessageFilter.h>
171+#include <Node.h>
172
173 // Maps BMessages to ShortcutsSpecs!
174 // The thread here gets file update messages, and updates
175@@ -49,6 +50,7 @@ private:
176
177 port_id fPort;
178 char* fFileName;
179+ node_ref fNodeRef;
180 BLocker fSyncSpecs; // locks the lists below
181 BList fInjects;
182 BList* fSpecs;
183diff --git a/src/add-ons/input_server/filters/shortcut_catcher/ParseCommandLine.cpp b/src/add-ons/input_server/filters/shortcut_catcher/ParseCommandLine.cpp
184index b7dbde0..c9dfc8c 100644
185--- a/src/add-ons/input_server/filters/shortcut_catcher/ParseCommandLine.cpp
186+++ b/src/add-ons/input_server/filters/shortcut_catcher/ParseCommandLine.cpp
187@@ -26,9 +26,10 @@
188 #include <SupportKit.h>
189
190
191+const char *kTrackerSignature = "application/x-vnd.Be-TRAK";
192+
193 // This char is used to hold words together into single words...
194 #define GUNK_CHAR 0x01
195-#define PATHTOTRACKER "/system/Tracker"
196
197 // Turn all spaces that are not-to-be-counted-as-spaces into GUNK_CHAR chars.
198 static void
199@@ -219,7 +220,6 @@ CloneArgv(char** argv)
200 }
201
202
203-
204 BString
205 ParseArgvZeroFromString(const char* command)
206 {
207@@ -299,24 +299,22 @@ LaunchCommand(char** argv, int32 argc)
208 // than launch.
209 BDirectory testDir(&entry);
210 if (testDir.InitCheck() == B_NO_ERROR) {
211- // Hack way to do this--really I should be able to do this by
212- // sending a BMessage. But how? When I finally get my copy of the
213- // BeOS Bible, maybe then I'll find out.
214- BPath trackerPath;
215- if (find_directory(B_SYSTEM_DIRECTORY, &trackerPath) != B_OK
216- || trackerPath.Append("Tracker") != B_OK) {
217- return B_ENTRY_NOT_FOUND;
218- }
219- BString cmd(trackerPath.Path());
220- cmd << " '" << argv[0] << "'";
221- system(cmd.String());
222- return B_NO_ERROR;
223+ entry_ref ref;
224+ status_t status = entry.GetRef(&ref);
225+ if (status < B_OK)
226+ return status;
227+
228+ BMessenger target(kTrackerSignature);
229+ BMessage message(B_REFS_RECEIVED);
230+ message.AddRef("refs", &ref);
231+
232+ return target.SendMessage(&message);
233 } else {
234 // It's not a directory. Must be a file.
235 entry_ref ref;
236 if (entry.GetRef(&ref) == B_NO_ERROR) {
237 if (argc > 1)
238- be_roster->Launch(&ref, argc-1, &argv[1]);
239+ be_roster->Launch(&ref, argc - 1, &argv[1]);
240 else
241 be_roster->Launch(&ref);
242 return B_NO_ERROR;
243diff --git a/src/add-ons/tracker/filetype/FileType.rdef b/src/add-ons/tracker/filetype/FileType.rdef
244index f51396c..329d140 100644
245--- a/src/add-ons/tracker/filetype/FileType.rdef
246+++ b/src/add-ons/tracker/filetype/FileType.rdef
247@@ -110,3 +110,4 @@ resource mini_icon array {
248
249 #endif // HAIKU_TARGET_PLATFORM_HAIKU
250
251+resource(100, "default_shortcut") "F";
252diff --git a/src/add-ons/tracker/filetype/Jamfile b/src/add-ons/tracker/filetype/Jamfile
253index 8ca0227..f2209a6 100644
254--- a/src/add-ons/tracker/filetype/Jamfile
255+++ b/src/add-ons/tracker/filetype/Jamfile
256@@ -3,9 +3,9 @@ SubDir HAIKU_TOP src add-ons tracker filetype ;
257 SetSubDirSupportedPlatformsBeOSCompatible ;
258
259 # TODO: does not seem to work:
260-AddResources FileType-F : FileType.rdef ;
261+AddResources FileType : FileType.rdef ;
262
263-Addon FileType-F :
264+Addon FileType :
265 FileType.cpp
266
267 : be tracker
268diff --git a/src/add-ons/tracker/mark_as/Jamfile b/src/add-ons/tracker/mark_as/Jamfile
269index 0a22ea1..f8492aa 100644
270--- a/src/add-ons/tracker/mark_as/Jamfile
271+++ b/src/add-ons/tracker/mark_as/Jamfile
272@@ -5,14 +5,14 @@ SetSubDirSupportedPlatformsBeOSCompatible ;
273 UsePrivateHeaders mail ;
274
275 AddResources Mark\ as… : MarkAs.rdef ;
276-AddResources Mark\ as\ Read-R : MarkAsRead.rdef ;
277+AddResources Mark\ as\ Read : MarkAsRead.rdef ;
278
279 Addon Mark\ as… :
280 MarkAs.cpp
281 : be tracker $(TARGET_LIBSUPC++) libmail.so
282 ;
283
284-Addon Mark\ as\ Read-R :
285+Addon Mark\ as\ Read :
286 MarkAsRead.cpp
287 : be tracker $(TARGET_LIBSUPC++) libmail.so
288 ;
289diff --git a/src/add-ons/tracker/mark_as/MarkAsRead.rdef b/src/add-ons/tracker/mark_as/MarkAsRead.rdef
290index 8ebf49e..ec62047 100644
291--- a/src/add-ons/tracker/mark_as/MarkAsRead.rdef
292+++ b/src/add-ons/tracker/mark_as/MarkAsRead.rdef
293@@ -32,3 +32,4 @@ resource vector_icon {
294 $"000A020105000A03010200"
295 };
296
297+resource(100, "default_shortcut") "R";
298diff --git a/src/add-ons/tracker/opentargetfolder/Jamfile b/src/add-ons/tracker/opentargetfolder/Jamfile
299index c44dfd8..0fcc931 100644
300--- a/src/add-ons/tracker/opentargetfolder/Jamfile
301+++ b/src/add-ons/tracker/opentargetfolder/Jamfile
302@@ -1,6 +1,6 @@
303 SubDir HAIKU_TOP src add-ons tracker opentargetfolder ;
304
305-Application Open\ Target\ Folder-O :
306+Application Open\ Target\ Folder :
307 opentargetfolder.cpp
308
309 : be tracker $(TARGET_LIBSUPC++)
310diff --git a/src/add-ons/tracker/opentargetfolder/opentargetfolder.rdef b/src/add-ons/tracker/opentargetfolder/opentargetfolder.rdef
311index c9afdf1..8d525a5 100644
312--- a/src/add-ons/tracker/opentargetfolder/opentargetfolder.rdef
313+++ b/src/add-ons/tracker/opentargetfolder/opentargetfolder.rdef
314@@ -92,3 +92,5 @@ resource mini_icon array {
315 };
316
317 #endif // HAIKU_TARGET_PLATFORM_HAIKU
318+
319+resource(100, "default_shortcut") "O";
320diff --git a/src/add-ons/tracker/openterminal/Jamfile b/src/add-ons/tracker/openterminal/Jamfile
321index 63f6c26..93a8d35 100644
322--- a/src/add-ons/tracker/openterminal/Jamfile
323+++ b/src/add-ons/tracker/openterminal/Jamfile
324@@ -2,9 +2,9 @@ SubDir HAIKU_TOP src add-ons tracker openterminal ;
325
326 SetSubDirSupportedPlatformsBeOSCompatible ;
327
328-AddResources Open\ Terminal-T : OpenTerminal.rdef ;
329+AddResources Open\ Terminal : OpenTerminal.rdef ;
330
331-Addon Open\ Terminal-T :
332+Addon Open\ Terminal :
333 OpenTerminal.cpp
334
335 : be tracker $(TARGET_LIBSTDC++)
336diff --git a/src/add-ons/tracker/openterminal/OpenTerminal.rdef b/src/add-ons/tracker/openterminal/OpenTerminal.rdef
337index e413574..fae9ae6 100644
338--- a/src/add-ons/tracker/openterminal/OpenTerminal.rdef
339+++ b/src/add-ons/tracker/openterminal/OpenTerminal.rdef
340@@ -42,3 +42,4 @@ resource vector_icon {
341 $"B30CB30C0A0C0110000A0B010F2032290A09010D2032BA450A09010D2036BB11"
342 };
343
344+resource("default_shortcut") "T";
345diff --git a/src/add-ons/tracker/zipomatic/Jamfile b/src/add-ons/tracker/zipomatic/Jamfile
346index f974e05..4c84ea6 100644
347--- a/src/add-ons/tracker/zipomatic/Jamfile
348+++ b/src/add-ons/tracker/zipomatic/Jamfile
349@@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons tracker zipomatic ;
350
351 UsePrivateHeaders shared ;
352
353-Application ZipOMatic-Z :
354+Application ZipOMatic :
355 GenericThread.cpp
356 ZipOMatic.cpp
357 ZipOMaticActivity.cpp
358@@ -13,7 +13,7 @@ Application ZipOMatic-Z :
359 : ZipOMatic.rdef
360 ;
361
362-DoCatalogs ZipOMatic-Z :
363+DoCatalogs ZipOMatic :
364 x-vnd.haiku.zip-o-matic
365 :
366 ZipOMatic.cpp
367diff --git a/src/add-ons/tracker/zipomatic/ZipOMatic.rdef b/src/add-ons/tracker/zipomatic/ZipOMatic.rdef
368index 052f62e..d817c0e 100644
369--- a/src/add-ons/tracker/zipomatic/ZipOMatic.rdef
370+++ b/src/add-ons/tracker/zipomatic/ZipOMatic.rdef
371@@ -59,3 +59,4 @@ resource vector_icon {
372 $"0111000A0B010E000A0C010F000A0B011000"
373 };
374
375+resource(100, "default_shortcut") "Z";
376diff --git a/src/apps/diskusage/DiskUsage.rdef b/src/apps/diskusage/DiskUsage.rdef
377index 0205feb..7e5158c 100644
378--- a/src/apps/diskusage/DiskUsage.rdef
379+++ b/src/apps/diskusage/DiskUsage.rdef
380@@ -49,3 +49,5 @@ resource vector_icon {
381 $"18001501178600040A01010B1815FF01178400040A08010C000A09010D000A0A"
382 $"010E00"
383 };
384+
385+resource(100, "default_shortcut") "I";
386diff --git a/src/apps/text_search/TextSearch.rdef b/src/apps/text_search/TextSearch.rdef
387index 3bad6e5..7beffcd 100644
388--- a/src/apps/text_search/TextSearch.rdef
389+++ b/src/apps/text_search/TextSearch.rdef
390@@ -45,3 +45,4 @@ resource vector_icon {
391 $"000A09010C023C00000000000000003C000048B00048F000"
392 };
393
394+resource(100, "default_shortcut") "G";
395diff --git a/src/kits/tracker/ContainerWindow.cpp b/src/kits/tracker/ContainerWindow.cpp
396index c2380b2..3721538 100644
397--- a/src/kits/tracker/ContainerWindow.cpp
398+++ b/src/kits/tracker/ContainerWindow.cpp
399@@ -145,6 +145,8 @@ const int32 kWindowStaggerBy = 17;
400
401 BRect BContainerWindow::sNewWindRect(85, 50, 548, 280);
402
403+LockingList<AddonShortcut>* BContainerWindow::fAddonsList
404+ = new LockingList<struct AddonShortcut>(10, true);
405
406 namespace BPrivate {
407
408@@ -165,48 +167,6 @@ ActivateWindowFilter(BMessage*, BHandler** target, BMessageFilter*)
409 }
410
411
412-static void
413-StripShortcut(const Model* model, char* result, uint32 &shortcut)
414-{
415- // model name (possibly localized) for the menu item label
416- strlcpy(result, model->Name(), B_FILE_NAME_LENGTH);
417-
418- // check if there is a shortcut in the model name
419- uint32 length = strlen(result);
420- if (length > 2 && result[length - 2] == '-') {
421- shortcut = result[length - 1];
422- result[length - 2] = '\0';
423- return;
424- }
425-
426- // check if there is a shortcut in the filename
427- char* refName = model->EntryRef()->name;
428- length = strlen(refName);
429- if (length > 2 && refName[length - 2] == '-') {
430- shortcut = refName[length - 1];
431- return;
432- }
433-
434- shortcut = '\0';
435-}
436-
437-
438-static const Model*
439-MatchOne(const Model* model, void* castToName)
440-{
441- char buffer[B_FILE_NAME_LENGTH];
442- uint32 dummy;
443- StripShortcut(model, buffer, dummy);
444-
445- if (strcmp(buffer, (const char*)castToName) == 0) {
446- // found match, bail out
447- return model;
448- }
449-
450- return 0;
451-}
452-
453-
454 int
455 CompareLabels(const BMenuItem* item1, const BMenuItem* item2)
456 {
457@@ -217,8 +177,8 @@ CompareLabels(const BMenuItem* item1, const BMenuItem* item2)
458
459
460 static bool
461-AddOneAddon(const Model* model, const char* name, uint32 shortcut,
462- bool primary, void* context)
463+AddOneAddon(const Model* model, const char* name, uint32 shortcut,
464+ uint32 modifiers, bool primary, void* context)
465 {
466 AddOneAddonParams* params = (AddOneAddonParams*)context;
467
468@@ -226,7 +186,7 @@ AddOneAddon(const Model* model, const char* name, uint32 shortcut,
469 message->AddRef("refs", model->EntryRef());
470
471 ModelMenuItem* item = new ModelMenuItem(model, name, message,
472- (char)shortcut, B_OPTION_KEY);
473+ (char)shortcut, modifiers);
474
475 if (primary)
476 params->primaryList->AddItem(item);
477@@ -2919,114 +2879,56 @@ BContainerWindow::AddTrashContextMenus(BMenu* menu)
478
479 void
480 BContainerWindow::EachAddon(bool (*eachAddon)(const Model*, const char*,
481- uint32 shortcut, bool primary, void* context), void* passThru,
482- BObjectList<BString> &mimeTypes)
483-{
484- BObjectList<Model> uniqueList(10, true);
485- BPath path;
486- bool bail = false;
487- if (find_directory(B_BEOS_ADDONS_DIRECTORY, &path) == B_OK)
488- bail = EachAddon(path, eachAddon, &uniqueList, passThru, mimeTypes);
489-
490- if (!bail && find_directory(B_USER_ADDONS_DIRECTORY, &path) == B_OK)
491- bail = EachAddon(path, eachAddon, &uniqueList, passThru, mimeTypes);
492-
493- if (!bail && find_directory(B_COMMON_ADDONS_DIRECTORY, &path) == B_OK)
494- EachAddon(path, eachAddon, &uniqueList, passThru, mimeTypes);
495-}
496-
497-
498-bool
499-BContainerWindow::EachAddon(BPath &path, bool (*eachAddon)(const Model*,
500- const char*, uint32 shortcut, bool primary, void*),
501- BObjectList<Model>* uniqueList, void* params,
502- BObjectList<BString> &mimeTypes)
503+ uint32 shortcut, uint32 modifiers, bool primary, void* context),
504+ void* passThru, BObjectList<BString> &mimeTypes)
505 {
506- path.Append("Tracker");
507-
508- BDirectory dir;
509- BEntry entry;
510-
511- if (dir.SetTo(path.Path()) != B_OK)
512- return false;
513-
514- dir.Rewind();
515- while (dir.GetNextEntry(&entry) == B_OK) {
516- Model* model = new Model(&entry);
517-
518- if (model->InitCheck() == B_OK && model->IsSymLink()) {
519- // resolve symlinks
520- Model* resolved = new Model(model->EntryRef(), true, true);
521- if (resolved->InitCheck() == B_OK)
522- model->SetLinkTo(resolved);
523- else
524- delete resolved;
525- }
526- if (model->InitCheck() != B_OK
527- || !model->ResolveIfLink()->IsExecutable()) {
528- delete model;
529- continue;
530- }
531-
532- // check if it supports at least one of the selected entries
533-
534- bool primary = false;
535-
536- if (mimeTypes.CountItems()) {
537- BFile file(&entry, B_READ_ONLY);
538- if (file.InitCheck() == B_OK) {
539- BAppFileInfo info(&file);
540- if (info.InitCheck() == B_OK) {
541- bool secondary = true;
542-
543- // does this add-on has types set at all?
544- BMessage message;
545- if (info.GetSupportedTypes(&message) == B_OK) {
546- type_code type;
547- int32 count;
548- if (message.GetInfo("types", &type, &count) == B_OK)
549- secondary = false;
550- }
551+ AutoLock<LockingList<AddonShortcut> > lock(fAddonsList);
552+ if (lock.IsLocked()) {
553+ for (int i = fAddonsList->CountItems() - 1; i >= 0; i--) {
554+ struct AddonShortcut* item = fAddonsList->ItemAt(i);
555+ bool primary = false;
556+
557+ if (mimeTypes.CountItems()) {
558+ BFile file(item->model->EntryRef(), B_READ_ONLY);
559+ if (file.InitCheck() == B_OK) {
560+ BAppFileInfo info(&file);
561+ if (info.InitCheck() == B_OK) {
562+ bool secondary = true;
563+
564+ // does this add-on has types set at all?
565+ BMessage message;
566+ if (info.GetSupportedTypes(&message) == B_OK) {
567+ type_code type;
568+ int32 count;
569+ if (message.GetInfo("types", &type,
570+ &count) == B_OK)
571+ secondary = false;
572+ }
573
574- // check all supported types if it has some set
575- if (!secondary) {
576- for (int32 i = mimeTypes.CountItems();
577- !primary && i-- > 0;) {
578- BString* type = mimeTypes.ItemAt(i);
579- if (info.IsSupportedType(type->String())) {
580- BMimeType mimeType(type->String());
581- if (info.Supports(&mimeType))
582- primary = true;
583- else
584- secondary = true;
585+ // check all supported types if it has some set
586+ if (!secondary) {
587+ for (int32 i = mimeTypes.CountItems();
588+ !primary && i-- > 0;) {
589+ BString* type = mimeTypes.ItemAt(i);
590+ if (info.IsSupportedType(type->String())) {
591+ BMimeType mimeType(type->String());
592+ if (info.Supports(&mimeType))
593+ primary = true;
594+ else
595+ secondary = true;
596+ }
597 }
598 }
599- }
600
601- if (!secondary && !primary) {
602- delete model;
603- continue;
604+ if (!secondary && !primary)
605+ continue;
606 }
607 }
608 }
609+ ((eachAddon)(item->model, item->model->Name(), item->key,
610+ item->modifiers, primary, passThru));
611 }
612-
613- char name[B_FILE_NAME_LENGTH];
614- uint32 key;
615- StripShortcut(model, name, key);
616-
617- // do a uniqueness check
618- if (uniqueList->EachElement(MatchOne, name)) {
619- // found one already in the list
620- delete model;
621- continue;
622- }
623- uniqueList->AddItem(model);
624-
625- if ((eachAddon)(model, name, key, primary, params))
626- return true;
627 }
628- return false;
629 }
630
631
632diff --git a/src/kits/tracker/ContainerWindow.h b/src/kits/tracker/ContainerWindow.h
633index 138d4f6..6935c24 100644
634--- a/src/kits/tracker/ContainerWindow.h
635+++ b/src/kits/tracker/ContainerWindow.h
636@@ -72,6 +72,13 @@ enum {
637 kRestoreDecor = 0x4
638 };
639
640+struct AddonShortcut {
641+ Model* model;
642+ char key;
643+ char defaultKey;
644+ uint32 modifiers;
645+};
646+
647 class BContainerWindow : public BWindow {
648 public:
649 BContainerWindow(LockingList<BWindow>* windowList,
650@@ -173,7 +180,8 @@ class BContainerWindow : public BWindow {
651
652 // add-on iteration
653 void EachAddon(bool (*)(const Model*, const char*, uint32 shortcut,
654- bool primary, void*), void*, BObjectList<BString> &);
655+ uint32 modifiers, bool primary, void*), void*,
656+ BObjectList<BString> &);
657
658 BPopUpMenu* ContextMenu();
659
660@@ -291,6 +299,8 @@ class BContainerWindow : public BWindow {
661 uint32 fContainerWindowFlags;
662 BackgroundImage* fBackgroundImage;
663
664+ static LockingList<struct AddonShortcut>* fAddonsList;
665+
666 private:
667 BRect fSavedZoomRect;
668 BRect fPreviousBounds;
669diff --git a/src/kits/tracker/DeskWindow.cpp b/src/kits/tracker/DeskWindow.cpp
670index b8ea334..1584f9b 100644
671--- a/src/kits/tracker/DeskWindow.cpp
672+++ b/src/kits/tracker/DeskWindow.cpp
673@@ -38,7 +38,9 @@ All rights reserved.
674 #include <Locale.h>
675 #include <NodeMonitor.h>
676 #include <Path.h>
677+#include <PathMonitor.h>
678 #include <PopUpMenu.h>
679+#include <Resources.h>
680 #include <Roster.h>
681 #include <Screen.h>
682 #include <Volume.h>
683@@ -55,6 +57,7 @@ All rights reserved.
684 #include "DeskWindow.h"
685 #include "FSUtils.h"
686 #include "IconMenuItem.h"
687+#include "KeyInfos.h"
688 #include "MountMenu.h"
689 #include "PoseView.h"
690 #include "Tracker.h"
691@@ -64,44 +67,117 @@ All rights reserved.
692 const char* kShelfPath = "tracker_shelf";
693 // replicant support
694
695+const char* kShortcutsSettings = "shortcuts_settings";
696+const char* kDefaultShortcut = "default_shortcut";
697+const uint32 kDefaultModifiers = B_OPTION_KEY | B_COMMAND_KEY;
698
699-static void
700-WatchAddOnDir(directory_which dirName, BDeskWindow* window)
701+static struct AddonShortcut*
702+MatchOne(struct AddonShortcut* item, void* castToName)
703 {
704- BPath path;
705- if (find_directory(dirName, &path) == B_OK) {
706- path.Append("Tracker");
707- BNode node(path.Path());
708- node_ref nodeRef;
709- node.GetNodeRef(&nodeRef);
710- TTracker::WatchNode(&nodeRef, B_WATCH_DIRECTORY, window);
711+ if (strcmp(item->model->Name(), (const char*)castToName) == 0) {
712+ // found match, bail out
713+ return item;
714 }
715-}
716
717+ return 0;
718+}
719
720-struct AddOneShortcutParams {
721- BDeskWindow* window;
722- std::set<uint32>* currentAddonShortcuts;
723-};
724
725-static bool
726-AddOneShortcut(const Model* model, const char*, uint32 shortcut,
727- bool /*primary*/, void* context)
728+static void
729+AddOneShortcut(Model* model, char key, uint32 modifiers, BDeskWindow* window)
730 {
731- if (!shortcut)
732- // no shortcut, bail
733- return false;
734-
735- AddOneShortcutParams* params = (AddOneShortcutParams*)context;
736+ if (key == '\0')
737+ return;
738 BMessage* runAddon = new BMessage(kLoadAddOn);
739 runAddon->AddRef("refs", model->EntryRef());
740+ window->AddShortcut(key, modifiers, runAddon);
741+}
742
743- params->window->AddShortcut(shortcut, B_OPTION_KEY | B_COMMAND_KEY,
744- runAddon);
745- params->currentAddonShortcuts->insert(shortcut);
746- PRINT(("adding new shortcut %c\n", (char)shortcut));
747
748- return false;
749+
750+static struct AddonShortcut*
751+RevertToDefault(struct AddonShortcut* item, void* castToWindow)
752+{
753+ if (item->key != item->defaultKey || item->modifiers != kDefaultModifiers) {
754+ BDeskWindow* window = static_cast<BDeskWindow*>(castToWindow);
755+ if (window != NULL) {
756+ window->RemoveShortcut(item->key, item->modifiers);
757+ item->key = item->defaultKey;
758+ item->modifiers = kDefaultModifiers;
759+ AddOneShortcut(item->model, item->key, item->modifiers, window);
760+ }
761+ }
762+ return 0;
763+}
764+
765+
766+static struct AddonShortcut*
767+FindElement(struct AddonShortcut* item, void* castToOther)
768+{
769+ Model* other = static_cast<Model*>(castToOther);
770+ if (*item->model->EntryRef() == *other->EntryRef())
771+ return item;
772+
773+ return 0;
774+}
775+
776+
777+static void
778+LoadAddOnDir(directory_which dirName, BDeskWindow* window,
779+ LockingList<AddonShortcut>* list)
780+{
781+ BPath path;
782+ if (find_directory(dirName, &path) == B_OK) {
783+ path.Append("Tracker");
784+
785+ BDirectory dir;
786+ BEntry entry;
787+
788+ if (dir.SetTo(path.Path()) != B_OK)
789+ return;
790+
791+ while (dir.GetNextEntry(&entry) == B_OK) {
792+ Model* model = new Model(&entry);
793+ if (model->InitCheck() == B_OK && model->IsSymLink()) {
794+ // resolve symlinks
795+ Model* resolved = new Model(model->EntryRef(), true, true);
796+ if (resolved->InitCheck() == B_OK)
797+ model->SetLinkTo(resolved);
798+ else
799+ delete resolved;
800+ }
801+ if (model->InitCheck() != B_OK
802+ || !model->ResolveIfLink()->IsExecutable()) {
803+ delete model;
804+ continue;
805+ }
806+
807+ char* name = strdup(model->Name());
808+ if (!list->EachElement(MatchOne, name)) {
809+ struct AddonShortcut* item = new struct AddonShortcut;
810+ item->model = model;
811+
812+ BResources resources(model->ResolveIfLink()->EntryRef());
813+ size_t size;
814+ char* shortcut = (char*)resources.LoadResource(B_STRING_TYPE,
815+ kDefaultShortcut, &size);
816+ if (shortcut == NULL || strlen(shortcut) > 1)
817+ item->key = '\0';
818+ else
819+ item->key = shortcut[0];
820+ AddOneShortcut(model, item->key, kDefaultModifiers, window);
821+ item->defaultKey = item->key;
822+ list->AddItem(item);
823+ }
824+ free(name);
825+ }
826+
827+ BNode node(path.Path());
828+ node_ref nodeRef;
829+ node.GetNodeRef(&nodeRef);
830+
831+ TTracker::WatchNode(&nodeRef, B_WATCH_DIRECTORY, window);
832+ }
833 }
834
835
836@@ -118,7 +194,8 @@ BDeskWindow::BDeskWindow(LockingList<BWindow>* windowList)
837 | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS, B_ALL_WORKSPACES),
838 fDeskShelf(0),
839 fTrashContextMenu(0),
840- fShouldUpdateAddonShortcuts(true)
841+ fNodeRef(NULL),
842+ fShortcutsSettings(NULL)
843 {
844 // Add icon view switching shortcuts. These are displayed in the context
845 // menu, although they obviously don't work from those menu items.
846@@ -173,43 +250,133 @@ BDeskWindow::Init(const BMessage*)
847 if (fDeskShelf)
848 fDeskShelf->SetDisplaysZombies(true);
849 }
850-
851- // watch add-on directories so that we can track the addons with
852- // corresponding shortcuts
853- WatchAddOnDir(B_USER_ADDONS_DIRECTORY, this);
854- WatchAddOnDir(B_COMMON_ADDONS_DIRECTORY, this);
855- WatchAddOnDir(B_SYSTEM_ADDONS_DIRECTORY, this);
856+ InitKeyIndices();
857+ InitAddonsList(false);
858+ ApplyShortcutPreferences(false);
859
860 _inherited::Init();
861 }
862
863
864 void
865-BDeskWindow::MenusBeginning()
866+BDeskWindow::InitAddonsList(bool update)
867 {
868- _inherited::MenusBeginning();
869-
870- if (fShouldUpdateAddonShortcuts) {
871- PRINT(("updating addon shortcuts\n"));
872- fShouldUpdateAddonShortcuts = false;
873-
874- // remove all current addon shortcuts
875- for (std::set<uint32>::iterator it= fCurrentAddonShortcuts.begin();
876- it != fCurrentAddonShortcuts.end(); it++) {
877- PRINT(("removing shortcut %c\n", (int)*it));
878- RemoveShortcut(*it, B_OPTION_KEY | B_COMMAND_KEY);
879+ AutoLock<LockingList<AddonShortcut> > lock(fAddonsList);
880+ if (lock.IsLocked()) {
881+ if (update) {
882+ for (int i = fAddonsList->CountItems() - 1; i >= 0; i--) {
883+ AddonShortcut* item = fAddonsList->ItemAt(i);
884+ RemoveShortcut(item->key, B_OPTION_KEY | B_COMMAND_KEY);
885+ }
886+ fAddonsList->MakeEmpty(true);
887 }
888
889- fCurrentAddonShortcuts.clear();
890+ LoadAddOnDir(B_USER_ADDONS_DIRECTORY, this, fAddonsList);
891+ LoadAddOnDir(B_COMMON_ADDONS_DIRECTORY, this, fAddonsList);
892+ LoadAddOnDir(B_SYSTEM_ADDONS_DIRECTORY, this, fAddonsList);
893+ }
894+}
895+
896
897- AddOneShortcutParams params;
898- params.window = this;
899- params.currentAddonShortcuts = &fCurrentAddonShortcuts;
900+void
901+BDeskWindow::ApplyShortcutPreferences(bool update)
902+{
903+ AutoLock<LockingList<AddonShortcut> > lock(fAddonsList);
904+ if (lock.IsLocked()) {
905+ if (!update) {
906+ BPath path;
907+ if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
908+ BPathMonitor::StartWatching(path.Path(), B_WATCH_STAT | B_WATCH_FILES_ONLY, this);
909+ path.Append(kShortcutsSettings);
910+ fShortcutsSettings = new char[strlen(path.Path()) + 1];
911+ strcpy(fShortcutsSettings, path.Path());
912+ }
913+ }
914
915- BObjectList<BString> mimeTypes(10, true);
916- BuildMimeTypeList(mimeTypes);
917+ fAddonsList->EachElement(RevertToDefault, this);
918
919- EachAddon(&AddOneShortcut, &params, mimeTypes);
920+ BFile shortcutSettings(fShortcutsSettings, B_READ_ONLY);
921+ BMessage fileMsg;
922+ if (shortcutSettings.InitCheck() != B_OK
923+ || fileMsg.Unflatten(&shortcutSettings) != B_OK) {
924+ fNodeRef = NULL;
925+ return;
926+ }
927+ shortcutSettings.GetNodeRef(fNodeRef);
928+
929+ int i = 0;
930+ BMessage message;
931+ while (fileMsg.FindMessage("spec", i++, &message) == B_OK) {
932+
933+ int32 key;
934+ BMessage actMsg;
935+
936+ if (message.FindInt32("key", &key) == B_OK
937+ && message.FindMessage("act", &actMsg) == B_OK) {
938+
939+ // only handle shortcuts referring add-ons
940+ BString command;
941+ if (actMsg.FindString("largv", &command) != B_OK)
942+ continue;
943+ BPath path;
944+ bool isInAddons = false;
945+ if (find_directory(B_SYSTEM_ADDONS_DIRECTORY, &path)
946+ == B_OK) {
947+ path.Append("Tracker/");
948+ isInAddons = command.FindFirst(path.Path()) == 0;
949+ }
950+ if (!isInAddons
951+ && (find_directory(B_COMMON_ADDONS_DIRECTORY, &path)
952+ == B_OK)) {
953+ path.Append("Tracker/");
954+ isInAddons = command.FindFirst(path.Path()) == 0;
955+ }
956+ if (!isInAddons
957+ && (find_directory(B_USER_ADDONS_DIRECTORY, &path)
958+ == B_OK)) {
959+ path.Append("Tracker/");
960+ isInAddons = command.FindFirst(path.Path()) == 0;
961+ }
962+ if (!isInAddons)
963+ continue;
964+
965+ BEntry entry(command);
966+ if (entry.InitCheck() != B_OK)
967+ continue;
968+
969+ const char* shortcut = GetKeyName(key);
970+ if (strlen(shortcut) != 1)
971+ continue;
972+
973+ uint32 modifiers = 0;
974+ int32 value;
975+ if (message.FindInt32("mcidx", 0, &value) == B_OK)
976+ modifiers |= (value != 0 ? B_SHIFT_KEY : 0);
977+
978+ if (message.FindInt32("mcidx", 1, &value) == B_OK)
979+ modifiers |= (value != 0 ? B_CONTROL_KEY : 0);
980+
981+ if (message.FindInt32("mcidx", 2, &value) == B_OK)
982+ modifiers |= (value != 0 ? B_COMMAND_KEY : 0);
983+
984+ if (message.FindInt32("mcidx", 3, &value) == B_OK)
985+ modifiers |= (value != 0 ? B_OPTION_KEY : 0);
986+
987+ if (modifiers == 0)
988+ modifiers = kDefaultModifiers;
989+
990+ Model model(&entry);
991+ AddonShortcut* item = fAddonsList->EachElement(FindElement,
992+ &model);
993+ if (item != NULL) {
994+ if (item->key != '\0')
995+ RemoveShortcut(item->key, item->modifiers);
996+ item->key = shortcut[0];
997+ item->modifiers = modifiers;
998+ AddOneShortcut(&model, item->key, item->modifiers, this);
999+ }
1000+ }
1001+ }
1002 }
1003 }
1004
1005@@ -228,6 +395,11 @@ BDeskWindow::Quit()
1006 fNavigationItem = 0;
1007 }
1008
1009+ while (fAddonsList->CountItems())
1010+ fAddonsList->RemoveItem(0);
1011+
1012+ delete fAddonsList;
1013+
1014 delete fTrashContextMenu;
1015 fTrashContextMenu = NULL;
1016
1017@@ -482,9 +654,28 @@ BDeskWindow::MessageReceived(BMessage* message)
1018 }
1019
1020 switch (message->what) {
1021+ case B_PATH_MONITOR:
1022+ {
1023+ const char* path = "";
1024+ if (!(message->FindString("path", &path) == B_OK
1025+ && strcmp(path, fShortcutsSettings) == 0)) {
1026+
1027+ dev_t device;
1028+ ino_t node;
1029+ if (fNodeRef == NULL
1030+ || message->FindInt32("device", &device) != B_OK
1031+ || message->FindInt64("node", &node) != B_OK
1032+ || device != fNodeRef->device
1033+ || node != fNodeRef->node)
1034+ break;
1035+ }
1036+ ApplyShortcutPreferences(true);
1037+ break;
1038+ }
1039 case B_NODE_MONITOR:
1040 PRINT(("will update addon shortcuts\n"));
1041- fShouldUpdateAddonShortcuts = true;
1042+ InitAddonsList(true);
1043+ ApplyShortcutPreferences(true);
1044 break;
1045
1046 default:
1047diff --git a/src/kits/tracker/DeskWindow.h b/src/kits/tracker/DeskWindow.h
1048index d83a55a..8b670aa 100644
1049--- a/src/kits/tracker/DeskWindow.h
1050+++ b/src/kits/tracker/DeskWindow.h
1051@@ -75,24 +75,20 @@ protected:
1052 virtual BPoseView* NewPoseView(Model*, BRect, uint32);
1053
1054 virtual void WorkspaceActivated(int32, bool);
1055- virtual void MenusBeginning();
1056 virtual void MessageReceived(BMessage*);
1057
1058 private:
1059+ void InitAddonsList(bool);
1060+ void ApplyShortcutPreferences(bool);
1061+
1062 BShelf* fDeskShelf;
1063 // shelf for replicant support
1064 BPopUpMenu* fTrashContextMenu;
1065
1066 BRect fOldFrame;
1067
1068- // in the desktop window addon shortcuts have to be added by AddShortcut
1069- // and we don't always get the MenusBeginning call to check for new
1070- // addons/update the shortcuts -- instead we need to node monitor the
1071- // addon directory and keep a dirty flag that triggers shortcut
1072- // reinstallation
1073- bool fShouldUpdateAddonShortcuts;
1074- std::set<uint32> fCurrentAddonShortcuts;
1075- // keeps track of which shortcuts are installed for Tracker addons
1076+ node_ref* fNodeRef;
1077+ char* fShortcutsSettings;
1078
1079 typedef BContainerWindow _inherited;
1080 };
1081diff --git a/src/kits/tracker/Jamfile b/src/kits/tracker/Jamfile
1082index 248e9c3..17e2c54 100644
1083--- a/src/kits/tracker/Jamfile
1084+++ b/src/kits/tracker/Jamfile
1085@@ -7,6 +7,8 @@ UsePrivateHeaders interface mount shared storage support tracker ;
1086
1087 AddResources libtracker.so : TrackerIcons.rdef libtracker.rdef ;
1088
1089+SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons input_server filters shortcut_catcher ] ;
1090+
1091 SubDirC++Flags
1092 -D_BUILDING_tracker=1
1093 # -D_INCLUDES_CLASS_DEVICE_MAP=1
1094@@ -89,7 +91,7 @@ SharedLibrary libtracker.so :
1095 VolumeWindow.cpp
1096 WidgetAttributeText.cpp
1097
1098- : be translation $(vector_icon_libs) $(TARGET_LIBSTDC++) $(HAIKU_LOCALE_LIBS) libshared.a
1099+ : be translation $(vector_icon_libs) $(TARGET_LIBSTDC++) $(HAIKU_LOCALE_LIBS) libshared.a libshortcuts_shared.a
1100 ;
1101
1102 DoCatalogs libtracker.so :
1103diff --git a/src/preferences/backgrounds/Backgrounds.rdef b/src/preferences/backgrounds/Backgrounds.rdef
1104index 668c823..2099c29 100644
1105--- a/src/preferences/backgrounds/Backgrounds.rdef
1106+++ b/src/preferences/backgrounds/Backgrounds.rdef
1107@@ -58,3 +58,5 @@ resource vector_icon {
1108 $"000A0D0114000A00011500"
1109 };
1110
1111+resource(100, "default_shortcut") "B";
1112+