1 /* 2 * Copyright 2004-2009, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Matthijs Hollemans 7 * Jerome Leveque 8 * Philippe Houdoin 9 */ 10 11 #include "DeviceWatcher.h" 12 #include "PortDrivers.h" 13 14 #include <Application.h> 15 #include <Bitmap.h> 16 #include <Directory.h> 17 #include <Entry.h> 18 #include <File.h> 19 #include <Path.h> 20 #include <Resources.h> 21 #include <Roster.h> 22 #include <PathMonitor.h> 23 24 #include <new> 25 using std::nothrow; 26 27 using namespace BPrivate; 28 using BPrivate::HashMap; 29 using BPrivate::HashString; 30 31 32 const char *kDevicesRoot = "/dev/midi"; 33 34 35 class DeviceEndpoints { 36 public: 37 DeviceEndpoints(int fd, MidiPortConsumer* consumer, MidiPortProducer* producer) 38 : fFD(fd), fConsumer(consumer), fProducer(producer) 39 { 40 } 41 42 int fFD; 43 MidiPortConsumer* fConsumer; 44 MidiPortProducer* fProducer; 45 }; 46 47 48 49 DeviceWatcher::DeviceWatcher() 50 : BLooper("MIDI devices watcher"), 51 fDeviceEndpointsMap() 52 { 53 // TODO: add support for vector icons 54 55 fLargeIcon = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8); 56 fMiniIcon = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8); 57 58 app_info info; 59 be_app->GetAppInfo(&info); 60 BFile file(&info.ref, B_READ_ONLY); 61 62 BResources res; 63 if (res.SetTo(&file) == B_OK) { 64 size_t size; 65 const void* bits; 66 67 bits = res.LoadResource(B_LARGE_ICON_TYPE, 10, &size); 68 fLargeIcon->SetBits(bits, size, 0, B_CMAP8); 69 70 bits = res.LoadResource(B_MINI_ICON_TYPE, 11, &size); 71 fMiniIcon->SetBits(bits, size, 0, B_CMAP8); 72 } 73 74 Start(); 75 } 76 77 78 DeviceWatcher::~DeviceWatcher() 79 { 80 Stop(); 81 82 delete fLargeIcon; 83 delete fMiniIcon; 84 } 85 86 87 status_t 88 DeviceWatcher::Start() 89 { 90 // Do an initial scan 91 _ScanDevices(kDevicesRoot); 92 93 // Okay, now just watch for any change 94 return BPathMonitor::StartWatching(kDevicesRoot, B_ENTRY_CREATED 95 | B_ENTRY_REMOVED | B_ENTRY_MOVED | B_WATCH_FILES_ONLY 96 | B_WATCH_RECURSIVELY, this); 97 } 98 99 100 status_t 101 DeviceWatcher::Stop() 102 { 103 return BPathMonitor::StopWatching(kDevicesRoot, this); 104 } 105 106 107 void 108 DeviceWatcher::MessageReceived(BMessage* message) 109 { 110 if (message->what != B_PATH_MONITOR) 111 return; 112 113 int32 opcode; 114 if (message->FindInt32("opcode", &opcode) != B_OK) 115 return; 116 117 // message->PrintToStream(); 118 119 const char* path; 120 if (message->FindString("path", &path) != B_OK) 121 return; 122 123 switch (opcode) { 124 case B_ENTRY_CREATED: { 125 _AddDevice(path); 126 break; 127 } 128 case B_ENTRY_REMOVED: { 129 _RemoveDevice(path); 130 break; 131 } 132 } 133 } 134 135 136 // #pragma mark - 137 138 139 void 140 DeviceWatcher::_ScanDevices(const char* path) 141 { 142 BDirectory dir(path); 143 if (dir.InitCheck() != B_OK) 144 return; 145 146 BEntry entry; 147 while (dir.GetNextEntry(&entry) == B_OK) { 148 BPath name; 149 entry.GetPath(&name); 150 if (entry.IsDirectory()) 151 _ScanDevices(name.Path()); 152 else 153 _AddDevice(name.Path()); 154 } 155 } 156 157 158 void 159 DeviceWatcher::_AddDevice(const char* path) 160 { 161 if ( fDeviceEndpointsMap.ContainsKey(path) ) 162 // Already known 163 return; 164 165 int fd = open(path, O_RDWR | O_EXCL); 166 if (fd < 0) 167 return; 168 169 // printf("DeviceWatcher::_AddDevice(\"%s\");\n", path); 170 171 172 MidiPortConsumer* consumer = new MidiPortConsumer(fd, path); 173 _SetIcons(consumer); 174 // printf("Register %s MidiPortConsumer\n", consumer->Name()); 175 consumer->Register(); 176 177 MidiPortProducer* producer = new MidiPortProducer(fd, path); 178 _SetIcons(producer); 179 // printf("Register %s MidiPortProducer\n", producer->Name()); 180 producer->Register(); 181 182 DeviceEndpoints * deviceEndpoints = new DeviceEndpoints(fd, consumer, producer); 183 fDeviceEndpointsMap.Put(path, deviceEndpoints); 184 } 185 186 187 void 188 DeviceWatcher::_RemoveDevice(const char* path) 189 { 190 // printf("DeviceWatcher::_RemoveDevice(\"%s\");\n", path); 191 192 DeviceEndpoints * deviceEndpoints = fDeviceEndpointsMap.Get(path); 193 if (!deviceEndpoints) 194 return; 195 196 close(deviceEndpoints->fFD); 197 198 deviceEndpoints->fConsumer->Unregister(); 199 deviceEndpoints->fProducer->Unregister(); 200 201 delete deviceEndpoints->fConsumer; 202 delete deviceEndpoints->fProducer; 203 204 fDeviceEndpointsMap.Remove(path); 205 } 206 207 208 void 209 DeviceWatcher::_SetIcons(BMidiEndpoint* endpoint) 210 { 211 BMessage msg; 212 213 // TODO: handle Haiku vector icon type 214 215 msg.AddData("be:large_icon", B_LARGE_ICON_TYPE, fLargeIcon->Bits(), 216 fLargeIcon->BitsLength()); 217 218 msg.AddData("be:mini_icon", B_MINI_ICON_TYPE, fMiniIcon->Bits(), 219 fMiniIcon->BitsLength()); 220 221 endpoint->SetProperties(&msg); 222 } 223