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