From d62e7f7b9b2cd32c6e9f55c2642303c40402ab8e Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Tue, 28 May 2013 12:42:50 +0200 Subject: [PATCH] explorer: Watch the desktop folders for changes and update the launcher list accordingly. --- programs/explorer/desktop.c | 133 ++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index cf0de3c6963..e426c1a1e63 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -252,6 +252,36 @@ error: return FALSE; } +static void free_launcher( struct launcher *launcher ) +{ + DestroyIcon( launcher->icon ); + HeapFree( GetProcessHeap(), 0, launcher->path ); + HeapFree( GetProcessHeap(), 0, launcher->title ); + HeapFree( GetProcessHeap(), 0, launcher ); +} + +static BOOL remove_launcher( const WCHAR *folder, const WCHAR *filename, int len_filename ) +{ + UINT i; + WCHAR *path; + BOOL ret = FALSE; + + if (!(path = append_path( folder, filename, len_filename ))) return FALSE; + for (i = 0; i < nb_launchers; i++) + { + if (!strcmpiW( launchers[i]->path, path )) + { + free_launcher( launchers[i] ); + if (--nb_launchers) + memmove( &launchers[i], &launchers[i + 1], sizeof(launchers[i]) * (nb_launchers - i) ); + ret = TRUE; + break; + } + } + HeapFree( GetProcessHeap(), 0, path ); + return ret; +} + static BOOL get_icon_text_metrics( HWND hwnd, TEXTMETRICW *tm ) { BOOL ret; @@ -268,6 +298,107 @@ static BOOL get_icon_text_metrics( HWND hwnd, TEXTMETRICW *tm ) return ret; } +static BOOL process_changes( const WCHAR *folder, char *buf ) +{ + FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION *)buf; + BOOL ret = FALSE; + + for (;;) + { + switch (info->Action) + { + case FILE_ACTION_ADDED: + case FILE_ACTION_RENAMED_NEW_NAME: + if (add_launcher( folder, info->FileName, info->FileNameLength / sizeof(WCHAR) )) + ret = TRUE; + break; + + case FILE_ACTION_REMOVED: + case FILE_ACTION_RENAMED_OLD_NAME: + if (remove_launcher( folder, info->FileName, info->FileNameLength / sizeof(WCHAR) )) + ret = TRUE; + break; + + default: + WARN( "unexpected action %u\n", info->Action ); + break; + } + if (!info->NextEntryOffset) break; + info = (FILE_NOTIFY_INFORMATION *)((char *)info + info->NextEntryOffset); + } + return ret; +} + +static DWORD CALLBACK watch_desktop_folders( LPVOID param ) +{ + HWND hwnd = param; + HRESULT init = CoInitialize( NULL ); + HANDLE dir0, dir1, events[2]; + OVERLAPPED ovl0, ovl1; + char *buf0 = NULL, *buf1 = NULL; + DWORD count, size = 4096, error = ERROR_OUTOFMEMORY; + BOOL ret, redraw; + + dir0 = CreateFileW( desktop_folder, FILE_LIST_DIRECTORY|SYNCHRONIZE, FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL ); + if (dir0 == INVALID_HANDLE_VALUE) return GetLastError(); + dir1 = CreateFileW( desktop_folder_public, FILE_LIST_DIRECTORY|SYNCHRONIZE, FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL ); + if (dir1 == INVALID_HANDLE_VALUE) + { + CloseHandle( dir0 ); + return GetLastError(); + } + if (!(ovl0.hEvent = events[0] = CreateEventW( NULL, FALSE, FALSE, NULL ))) goto error; + if (!(ovl1.hEvent = events[1] = CreateEventW( NULL, FALSE, FALSE, NULL ))) goto error; + if (!(buf0 = HeapAlloc( GetProcessHeap(), 0, size ))) goto error; + if (!(buf1 = HeapAlloc( GetProcessHeap(), 0, size ))) goto error; + + for (;;) + { + ret = ReadDirectoryChangesW( dir0, buf0, size, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ovl0, NULL ); + if (!ret) + { + error = GetLastError(); + goto error; + } + ret = ReadDirectoryChangesW( dir1, buf1, size, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ovl1, NULL ); + if (!ret) + { + error = GetLastError(); + goto error; + } + + redraw = FALSE; + switch ((error = WaitForMultipleObjects( 2, events, FALSE, INFINITE ))) + { + case WAIT_OBJECT_0: + if (!GetOverlappedResult( dir0, &ovl0, &count, FALSE ) || !count) break; + if (process_changes( desktop_folder, buf0 )) redraw = TRUE; + break; + + case WAIT_OBJECT_0 + 1: + if (!GetOverlappedResult( dir1, &ovl1, &count, FALSE ) || !count) break; + if (process_changes( desktop_folder_public, buf1 )) redraw = TRUE; + break; + + default: + goto error; + } + if (redraw) InvalidateRect( hwnd, NULL, TRUE ); + } + +error: + CloseHandle( dir0 ); + CloseHandle( dir1 ); + CloseHandle( events[0] ); + CloseHandle( events[1] ); + HeapFree( GetProcessHeap(), 0, buf0 ); + HeapFree( GetProcessHeap(), 0, buf1 ); + if (SUCCEEDED( init )) CoUninitialize(); + return error; +} + static void add_folder( const WCHAR *folder ) { static const WCHAR lnkW[] = {'\\','*','.','l','n','k',0}; @@ -334,6 +465,8 @@ static void initialize_launchers( HWND hwnd ) add_folder( desktop_folder ); add_folder( desktop_folder_public ); if (SUCCEEDED( init )) CoUninitialize(); + + CreateThread( NULL, 0, watch_desktop_folders, hwnd, 0, NULL ); } }