ml_history.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #include "main.h"
  2. #include "..\..\General\gen_ml/config.h"
  3. #include "..\..\General\gen_ml/gaystring.h"
  4. #include "..\..\General\gen_hotkeys/wa_hotkeys.h"
  5. #include "..\..\General\gen_ml/MediaLibraryCOM.h"
  6. #include "..\..\General\gen_ml/ml_ipc_0313.h"
  7. #include <malloc.h>
  8. int ml_history_tree = -1;
  9. HWND m_curview_hwnd = NULL;
  10. static WNDPROC wa_oldWndProc=0;
  11. wchar_t *history_fn = 0;
  12. int timer = -1;
  13. static wchar_t *last_history_fn;
  14. static int last_timer=-1;
  15. static int last_play_pos=0;
  16. int history_fn_mode = 0;
  17. nde_database_t g_db = NULL;
  18. nde_table_t g_table = NULL;
  19. int g_table_dirty = 0;
  20. C_Config *g_config;
  21. CRITICAL_SECTION g_db_cs;
  22. HWND onTreeViewSelectChange(HWND hwnd)
  23. {
  24. openDb();
  25. if (m_curview_hwnd) DestroyWindow(m_curview_hwnd);
  26. if (!g_table || nde_error)
  27. {
  28. m_curview_hwnd = WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_DB_ERROR, hwnd, view_errorinfoDialogProc, 0);
  29. }
  30. else
  31. {
  32. m_curview_hwnd = WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_RECENTITEMS, hwnd, view_historyDialogProc, 0);
  33. }
  34. return m_curview_hwnd;
  35. }
  36. static void history_cleanupifnecessary();
  37. static LRESULT APIENTRY wa_newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  38. int history_init()
  39. {
  40. if ( !g_config->ReadInt( L"showrecentitems", 1 ) )
  41. return 1;
  42. NAVINSERTSTRUCT nis = {0};
  43. nis.item.cbSize = sizeof(NAVITEM);
  44. nis.item.pszText = WASABI_API_LNGSTRINGW(IDS_HISTORY);
  45. nis.item.pszInvariant = L"History";
  46. nis.item.mask = NIMF_TEXT | NIMF_TEXTINVARIANT | NIMF_IMAGE | NIMF_IMAGESEL;
  47. nis.item.iSelectedImage = nis.item.iImage = mediaLibrary.AddTreeImageBmp(IDB_TREEITEM_RECENT);
  48. // map to item id (will probably have to change but is a quick port to support invariant item naming)
  49. NAVITEM nvItem = {sizeof(NAVITEM),0,NIMF_ITEMID,};
  50. nvItem.hItem = MLNavCtrl_InsertItem(plugin.hwndLibraryParent, &nis);
  51. MLNavItem_GetInfo(plugin.hwndLibraryParent, &nvItem);
  52. ml_history_tree = nvItem.id;
  53. if (!wa_oldWndProc) // don't double dip (we call history_init() dynamically if the user fiddles with prefs
  54. {
  55. wa_oldWndProc = (WNDPROC)SetWindowLongPtrW(plugin.hwndWinampParent, GWLP_WNDPROC, (LONG_PTR)wa_newWndProc);
  56. }
  57. return 1;
  58. }
  59. void history_quit()
  60. {
  61. if (last_history_fn)
  62. {
  63. if ((last_timer <= 0) || (last_play_pos > last_timer))
  64. {
  65. if (last_play_pos) history_onFile(last_history_fn, last_play_pos);
  66. }
  67. }
  68. free(last_history_fn);
  69. last_history_fn = 0;
  70. free(history_fn);
  71. history_fn = 0;
  72. closeDb();
  73. mediaLibrary.RemoveTreeItem(ml_history_tree);
  74. ml_history_tree=0;
  75. }
  76. static void RetypeFilename(nde_table_t table)
  77. {
  78. // TODO: UI
  79. int totalRecords = NDE_Table_GetRecordsCount(g_table);
  80. if (totalRecords == 0) // bail out early so we don't flash a dialog
  81. return;
  82. nde_scanner_t pruneScanner = NDE_Table_CreateScanner(table);
  83. if (pruneScanner)
  84. {
  85. NDE_Scanner_First(pruneScanner);
  86. while (!NDE_Scanner_EOF(pruneScanner))
  87. {
  88. nde_field_t f = NDE_Scanner_GetFieldByID(pruneScanner, HISTORYVIEW_COL_FILENAME);
  89. if (f && NDE_Field_GetType(f) == FIELD_STRING)
  90. {
  91. wchar_t *s = NDE_StringField_GetString(f);
  92. ndestring_retain(s);
  93. NDE_Scanner_DeleteField(pruneScanner, f);
  94. nde_field_t new_f = NDE_Scanner_NewFieldByID(pruneScanner, HISTORYVIEW_COL_FILENAME);
  95. NDE_StringField_SetNDEString(new_f, s);
  96. ndestring_release(s);
  97. NDE_Scanner_Post(pruneScanner);
  98. }
  99. else if (f)
  100. break;
  101. NDE_Scanner_Next(pruneScanner);
  102. }
  103. NDE_Table_DestroyScanner(table, pruneScanner);
  104. NDE_Table_Sync(table);
  105. }
  106. }
  107. static void CreateFields(nde_table_t table)
  108. {
  109. // create defaults
  110. NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_LASTPLAYED, L"lastplay", FIELD_DATETIME);
  111. NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_PLAYCOUNT, L"playcount", FIELD_INTEGER);
  112. NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_TITLE, L"title", FIELD_STRING);
  113. NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_LENGTH, L"length", FIELD_INTEGER);
  114. NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_FILENAME, L"filename", FIELD_FILENAME);
  115. NDE_Table_NewColumnW(g_table, HISTORYVIEW_COL_OFFSET, L"offset", FIELD_INTEGER);
  116. NDE_Table_PostColumns(g_table);
  117. NDE_Table_AddIndexByIDW(g_table, 0, L"filename");}
  118. int openDb()
  119. {
  120. if (g_table) return 1; // need to close first
  121. EnterCriticalSection(&g_db_cs);
  122. // benski> i know this looks redundant, but we might have sat and blocked at the above Critical Section for a while
  123. if (g_table)
  124. {
  125. LeaveCriticalSection(&g_db_cs);
  126. return 1;
  127. }
  128. if (!g_db)
  129. {
  130. __try
  131. {
  132. g_db = NDE_CreateDatabase(plugin.hDllInstance);
  133. }
  134. __except(EXCEPTION_EXECUTE_HANDLER)
  135. {
  136. g_db = NULL;
  137. LeaveCriticalSection(&g_db_cs);
  138. return 0;
  139. }
  140. }
  141. wchar_t tableName[MAX_PATH] = {0}, indexName[MAX_PATH] = {0};
  142. PathCombineW(tableName, g_tableDir, L"recent.dat");
  143. PathCombineW(indexName, g_tableDir, L"recent.idx");
  144. if (!g_db)
  145. {
  146. LeaveCriticalSection(&g_db_cs);
  147. return 0;
  148. }
  149. g_table = NDE_Database_OpenTable(g_db, tableName, indexName, NDE_OPEN_ALWAYS, NDE_CACHE);
  150. if (g_table)
  151. {
  152. CreateFields(g_table);
  153. RetypeFilename(g_table);
  154. }
  155. LeaveCriticalSection(&g_db_cs);
  156. return (g_table != NULL);
  157. }
  158. void closeDb(bool clear_dirty)
  159. {
  160. if (g_table_dirty && g_table)
  161. {
  162. history_bgQuery_Stop();
  163. NDE_Table_Sync(g_table);
  164. if (clear_dirty) g_table_dirty=0;
  165. }
  166. if (g_db)
  167. {
  168. __try
  169. {
  170. if (g_table)
  171. NDE_Database_CloseTable(g_db, g_table);
  172. NDE_DestroyDatabase(g_db);
  173. }
  174. __except(EXCEPTION_EXECUTE_HANDLER)
  175. {
  176. }
  177. }
  178. g_db = NULL;
  179. g_table = NULL;
  180. }
  181. INT_PTR pluginHandleIpcMessage(int msg, INT_PTR param)
  182. {
  183. return (INT_PTR) SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, param, msg);
  184. }
  185. static LRESULT APIENTRY wa_newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  186. {
  187. if ((uMsg == WM_SYSKEYDOWN || uMsg == WM_KEYDOWN) &&
  188. wParam == 'H' &&
  189. !(GetAsyncKeyState(VK_MENU)&0x8000) &&
  190. !(GetAsyncKeyState(VK_SHIFT)&0x8000) &&
  191. (GetAsyncKeyState(VK_CONTROL)&0x8000)
  192. && ml_history_tree > 0)
  193. {
  194. mediaLibrary.ShowMediaLibrary();
  195. mediaLibrary.SelectTreeItem(ml_history_tree);
  196. }
  197. else if (history_fn && uMsg == WM_TIMER && wParam == 8082)
  198. {
  199. if (!history_fn_mode || SendMessage(hwndDlg, WM_WA_IPC, 0, IPC_GETOUTPUTTIME) > 350)
  200. {
  201. KillTimer(hwndDlg, 8082);
  202. if (SendMessage(hwndDlg, WM_WA_IPC, 0, IPC_ISPLAYING) == 1)
  203. {
  204. history_onFile(history_fn, -1);
  205. }
  206. free(history_fn);
  207. history_fn = 0;
  208. }
  209. return CallWindowProcW(wa_oldWndProc, hwndDlg, uMsg, wParam, lParam);
  210. }
  211. else if (last_history_fn && uMsg == WM_TIMER && wParam == 8083)
  212. {
  213. KillTimer(hwndDlg, 8083);
  214. history_onFile(last_history_fn, last_play_pos);
  215. return CallWindowProcW(wa_oldWndProc, hwndDlg, uMsg, wParam, lParam);
  216. }
  217. else if (uMsg == WM_WA_IPC)
  218. {
  219. if(lParam == IPC_STOPPLAYING && g_config->ReadInt(L"resumeplayback",0))
  220. {
  221. KillTimer(hwndDlg, 8082);
  222. if (last_history_fn)
  223. {
  224. free(last_history_fn);
  225. last_history_fn = 0;
  226. }
  227. if (history_fn) last_history_fn = _wcsdup(history_fn);
  228. // copes with stopping after playback was tracked otherwise this aspect will fail!
  229. else last_history_fn = _wcsdup((wchar_t*)SendMessage(hwndDlg,WM_WA_IPC,0,IPC_GET_PLAYING_FILENAME));
  230. last_timer = timer;
  231. stopPlayingInfoStruct *stopPlayingInfo = (stopPlayingInfoStruct *)wParam;
  232. last_play_pos = stopPlayingInfo->last_time;
  233. if (!stopPlayingInfo->g_fullstop)
  234. {
  235. if ((last_timer <= 0) || (last_play_pos > last_timer))
  236. {
  237. if (last_play_pos) SetTimer(hwndDlg, 8083, 150, NULL);
  238. }
  239. }
  240. else // clean up play offset
  241. {
  242. if (last_history_fn) history_onFile(last_history_fn, 0);
  243. }
  244. }
  245. else if(lParam == IPC_CB_MISC)
  246. {
  247. if (wParam == IPC_CB_MISC_PAUSE)
  248. {
  249. KillTimer(hwndDlg, 8082);
  250. }
  251. else if (wParam == IPC_CB_MISC_UNPAUSE)
  252. {
  253. if (history_fn) History_StartTracking(history_fn, true);
  254. }
  255. }
  256. } // wm_wa_ipc
  257. return CallWindowProcW(wa_oldWndProc, hwndDlg, uMsg, wParam, lParam);
  258. }