Hans Leidekker : explorer: Watch the desktop folders for changes and update the launcher list accordingly .
Alexandre Julliard
julliard at winehq.org
Tue May 28 15:16:59 CDT 2013
Module: wine
Branch: master
Commit: d62e7f7b9b2cd32c6e9f55c2642303c40402ab8e
URL: http://source.winehq.org/git/wine.git/?a=commit;h=d62e7f7b9b2cd32c6e9f55c2642303c40402ab8e
Author: Hans Leidekker <hans at codeweavers.com>
Date: Tue May 28 12:42:50 2013 +0200
explorer: Watch the desktop folders for changes and update the launcher list accordingly.
---
programs/explorer/desktop.c | 133 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 133 insertions(+), 0 deletions(-)
diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c
index cf0de3c..e426c1a 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 );
}
}
More information about the wine-cvs
mailing list