mirror of
git://source.winehq.org/git/wine.git
synced 2024-08-31 09:04:06 +00:00
explorer: Watch the desktop folders for changes and update the launcher list accordingly.
This commit is contained in:
parent
e44f0c8f2d
commit
d62e7f7b9b
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue