explorer: Watch the desktop folders for changes and update the launcher list accordingly.

This commit is contained in:
Hans Leidekker 2013-05-28 12:42:50 +02:00 committed by Alexandre Julliard
parent e44f0c8f2d
commit d62e7f7b9b

View file

@ -252,6 +252,36 @@ error:
return FALSE; 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 ) static BOOL get_icon_text_metrics( HWND hwnd, TEXTMETRICW *tm )
{ {
BOOL ret; BOOL ret;
@ -268,6 +298,107 @@ static BOOL get_icon_text_metrics( HWND hwnd, TEXTMETRICW *tm )
return ret; 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 void add_folder( const WCHAR *folder )
{ {
static const WCHAR lnkW[] = {'\\','*','.','l','n','k',0}; 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 );
add_folder( desktop_folder_public ); add_folder( desktop_folder_public );
if (SUCCEEDED( init )) CoUninitialize(); if (SUCCEEDED( init )) CoUninitialize();
CreateThread( NULL, 0, watch_desktop_folders, hwnd, 0, NULL );
} }
} }