explorer: Create the driver desktop window after the window handle is created.
[wine.git] / programs / explorer / desktop.c
blob694f3f6a10cb3b57df33d5084d82af78a8ba14db
1 /*
2 * Explorer desktop support
4 * Copyright 2006 Alexandre Julliard
5 * Copyright 2013 Hans Leidekker for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "wine/port.h"
24 #include <stdio.h>
26 #define COBJMACROS
27 #define OEMRESOURCE
28 #include <windows.h>
29 #include <rpc.h>
30 #include <shlobj.h>
31 #include <shellapi.h>
33 #include "wine/gdi_driver.h"
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
36 #include "explorer_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(explorer);
40 #define DESKTOP_CLASS_ATOM ((LPCWSTR)MAKEINTATOM(32769))
41 #define DESKTOP_ALL_ACCESS 0x01ff
43 static HMODULE graphics_driver;
44 static BOOL using_root;
46 struct launcher
48 WCHAR *path;
49 HICON icon;
50 WCHAR *title;
53 static WCHAR *desktop_folder;
54 static WCHAR *desktop_folder_public;
56 static int icon_cx, icon_cy, icon_offset_cx, icon_offset_cy;
57 static int title_cx, title_cy, title_offset_cx, title_offset_cy;
58 static int desktop_width, launcher_size, launchers_per_row;
60 static struct launcher **launchers;
61 static unsigned int nb_launchers, nb_allocated;
63 static RECT get_icon_rect( unsigned int index )
65 RECT rect;
66 unsigned int row = index / launchers_per_row;
67 unsigned int col = index % launchers_per_row;
69 rect.left = col * launcher_size + icon_offset_cx;
70 rect.right = rect.left + icon_cx;
71 rect.top = row * launcher_size + icon_offset_cy;
72 rect.bottom = rect.top + icon_cy;
73 return rect;
76 static RECT get_title_rect( unsigned int index )
78 RECT rect;
79 unsigned int row = index / launchers_per_row;
80 unsigned int col = index % launchers_per_row;
82 rect.left = col * launcher_size + title_offset_cx;
83 rect.right = rect.left + title_cx;
84 rect.top = row * launcher_size + title_offset_cy;
85 rect.bottom = rect.top + title_cy;
86 return rect;
89 static const struct launcher *launcher_from_point( int x, int y )
91 RECT icon, title;
92 unsigned int index = x / launcher_size + (y / launcher_size) * launchers_per_row;
94 if (index >= nb_launchers) return NULL;
96 icon = get_icon_rect( index );
97 title = get_title_rect( index );
98 if ((x < icon.left || x > icon.right || y < icon.top || y > icon.bottom) &&
99 (x < title.left || x > title.right || y < title.top || y > title.bottom)) return NULL;
100 return launchers[index];
103 static void draw_launchers( HDC hdc, RECT update_rect )
105 COLORREF color = SetTextColor( hdc, RGB(255,255,255) ); /* FIXME: depends on background color */
106 int mode = SetBkMode( hdc, TRANSPARENT );
107 unsigned int i;
108 LOGFONTW lf;
109 HFONT font;
111 SystemParametersInfoW( SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0 );
112 font = SelectObject( hdc, CreateFontIndirectW( &lf ) );
114 for (i = 0; i < nb_launchers; i++)
116 RECT dummy, icon = get_icon_rect( i ), title = get_title_rect( i );
118 if (IntersectRect( &dummy, &icon, &update_rect ))
119 DrawIconEx( hdc, icon.left, icon.top, launchers[i]->icon, icon_cx, icon_cy,
120 0, 0, DI_DEFAULTSIZE|DI_NORMAL );
122 if (IntersectRect( &dummy, &title, &update_rect ))
123 DrawTextW( hdc, launchers[i]->title, -1, &title,
124 DT_CENTER|DT_WORDBREAK|DT_EDITCONTROL|DT_END_ELLIPSIS );
127 SelectObject( hdc, font );
128 SetTextColor( hdc, color );
129 SetBkMode( hdc, mode );
132 static void do_launch( const struct launcher *launcher )
134 static const WCHAR openW[] = {'o','p','e','n',0};
135 ShellExecuteW( NULL, openW, launcher->path, NULL, NULL, 0 );
138 static WCHAR *append_path( const WCHAR *path, const WCHAR *filename, int len_filename )
140 int len_path = strlenW( path );
141 WCHAR *ret;
143 if (len_filename == -1) len_filename = strlenW( filename );
144 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len_path + len_filename + 2) * sizeof(WCHAR) )))
145 return NULL;
146 memcpy( ret, path, len_path * sizeof(WCHAR) );
147 ret[len_path] = '\\';
148 memcpy( ret + len_path + 1, filename, len_filename * sizeof(WCHAR) );
149 ret[len_path + 1 + len_filename] = 0;
150 return ret;
153 static IShellLinkW *load_shelllink( const WCHAR *path )
155 HRESULT hr;
156 IShellLinkW *link;
157 IPersistFile *file;
159 hr = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW,
160 (void **)&link );
161 if (FAILED( hr )) return NULL;
163 hr = IShellLinkW_QueryInterface( link, &IID_IPersistFile, (void **)&file );
164 if (FAILED( hr ))
166 IShellLinkW_Release( link );
167 return NULL;
169 hr = IPersistFile_Load( file, path, 0 );
170 IPersistFile_Release( file );
171 if (FAILED( hr ))
173 IShellLinkW_Release( link );
174 return NULL;
176 return link;
179 static HICON extract_icon( IShellLinkW *link )
181 WCHAR tmp_path[MAX_PATH], icon_path[MAX_PATH], target_path[MAX_PATH];
182 HICON icon = NULL;
183 int index;
185 tmp_path[0] = 0;
186 IShellLinkW_GetIconLocation( link, tmp_path, MAX_PATH, &index );
187 ExpandEnvironmentStringsW( tmp_path, icon_path, MAX_PATH );
189 if (icon_path[0]) ExtractIconExW( icon_path, index, &icon, NULL, 1 );
190 if (!icon)
192 tmp_path[0] = 0;
193 IShellLinkW_GetPath( link, tmp_path, MAX_PATH, NULL, SLGP_RAWPATH );
194 ExpandEnvironmentStringsW( tmp_path, target_path, MAX_PATH );
195 ExtractIconExW( target_path, index, &icon, NULL, 1 );
197 return icon;
200 static WCHAR *build_title( const WCHAR *filename, int len )
202 const WCHAR *p;
203 WCHAR *ret;
205 if (len == -1) len = strlenW( filename );
206 for (p = filename + len - 1; p >= filename; p--)
208 if (*p == '.')
210 len = p - filename;
211 break;
214 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
215 memcpy( ret, filename, len * sizeof(WCHAR) );
216 ret[len] = 0;
217 return ret;
220 static BOOL add_launcher( const WCHAR *folder, const WCHAR *filename, int len_filename )
222 struct launcher *launcher;
223 IShellLinkW *link;
225 if (nb_launchers == nb_allocated)
227 unsigned int count = nb_allocated * 2;
228 struct launcher **tmp = HeapReAlloc( GetProcessHeap(), 0, launchers, count * sizeof(*tmp) );
229 if (!tmp) return FALSE;
230 launchers = tmp;
231 nb_allocated = count;
234 if (!(launcher = HeapAlloc( GetProcessHeap(), 0, sizeof(*launcher) ))) return FALSE;
235 if (!(launcher->path = append_path( folder, filename, len_filename ))) goto error;
236 if (!(link = load_shelllink( launcher->path ))) goto error;
238 launcher->icon = extract_icon( link );
239 launcher->title = build_title( filename, len_filename );
240 IShellLinkW_Release( link );
241 if (launcher->icon && launcher->title)
243 launchers[nb_launchers++] = launcher;
244 return TRUE;
246 HeapFree( GetProcessHeap(), 0, launcher->title );
247 DestroyIcon( launcher->icon );
249 error:
250 HeapFree( GetProcessHeap(), 0, launcher->path );
251 HeapFree( GetProcessHeap(), 0, launcher );
252 return FALSE;
255 static void free_launcher( struct launcher *launcher )
257 DestroyIcon( launcher->icon );
258 HeapFree( GetProcessHeap(), 0, launcher->path );
259 HeapFree( GetProcessHeap(), 0, launcher->title );
260 HeapFree( GetProcessHeap(), 0, launcher );
263 static BOOL remove_launcher( const WCHAR *folder, const WCHAR *filename, int len_filename )
265 UINT i;
266 WCHAR *path;
267 BOOL ret = FALSE;
269 if (!(path = append_path( folder, filename, len_filename ))) return FALSE;
270 for (i = 0; i < nb_launchers; i++)
272 if (!strcmpiW( launchers[i]->path, path ))
274 free_launcher( launchers[i] );
275 if (--nb_launchers)
276 memmove( &launchers[i], &launchers[i + 1], sizeof(launchers[i]) * (nb_launchers - i) );
277 ret = TRUE;
278 break;
281 HeapFree( GetProcessHeap(), 0, path );
282 return ret;
285 static BOOL get_icon_text_metrics( HWND hwnd, TEXTMETRICW *tm )
287 BOOL ret;
288 HDC hdc;
289 LOGFONTW lf;
290 HFONT hfont;
292 hdc = GetDC( hwnd );
293 SystemParametersInfoW( SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0 );
294 hfont = SelectObject( hdc, CreateFontIndirectW( &lf ) );
295 ret = GetTextMetricsW( hdc, tm );
296 SelectObject( hdc, hfont );
297 ReleaseDC( hwnd, hdc );
298 return ret;
301 static BOOL process_changes( const WCHAR *folder, char *buf )
303 FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION *)buf;
304 BOOL ret = FALSE;
306 for (;;)
308 switch (info->Action)
310 case FILE_ACTION_ADDED:
311 case FILE_ACTION_RENAMED_NEW_NAME:
312 if (add_launcher( folder, info->FileName, info->FileNameLength / sizeof(WCHAR) ))
313 ret = TRUE;
314 break;
316 case FILE_ACTION_REMOVED:
317 case FILE_ACTION_RENAMED_OLD_NAME:
318 if (remove_launcher( folder, info->FileName, info->FileNameLength / sizeof(WCHAR) ))
319 ret = TRUE;
320 break;
322 default:
323 WARN( "unexpected action %u\n", info->Action );
324 break;
326 if (!info->NextEntryOffset) break;
327 info = (FILE_NOTIFY_INFORMATION *)((char *)info + info->NextEntryOffset);
329 return ret;
332 static DWORD CALLBACK watch_desktop_folders( LPVOID param )
334 HWND hwnd = param;
335 HRESULT init = CoInitialize( NULL );
336 HANDLE dir0, dir1, events[2];
337 OVERLAPPED ovl0, ovl1;
338 char *buf0 = NULL, *buf1 = NULL;
339 DWORD count, size = 4096, error = ERROR_OUTOFMEMORY;
340 BOOL ret, redraw;
342 dir0 = CreateFileW( desktop_folder, FILE_LIST_DIRECTORY|SYNCHRONIZE, FILE_SHARE_READ|FILE_SHARE_WRITE,
343 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL );
344 if (dir0 == INVALID_HANDLE_VALUE) return GetLastError();
345 dir1 = CreateFileW( desktop_folder_public, FILE_LIST_DIRECTORY|SYNCHRONIZE, FILE_SHARE_READ|FILE_SHARE_WRITE,
346 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL );
347 if (dir1 == INVALID_HANDLE_VALUE)
349 CloseHandle( dir0 );
350 return GetLastError();
352 if (!(ovl0.hEvent = events[0] = CreateEventW( NULL, FALSE, FALSE, NULL ))) goto error;
353 if (!(ovl1.hEvent = events[1] = CreateEventW( NULL, FALSE, FALSE, NULL ))) goto error;
354 if (!(buf0 = HeapAlloc( GetProcessHeap(), 0, size ))) goto error;
355 if (!(buf1 = HeapAlloc( GetProcessHeap(), 0, size ))) goto error;
357 for (;;)
359 ret = ReadDirectoryChangesW( dir0, buf0, size, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ovl0, NULL );
360 if (!ret)
362 error = GetLastError();
363 goto error;
365 ret = ReadDirectoryChangesW( dir1, buf1, size, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ovl1, NULL );
366 if (!ret)
368 error = GetLastError();
369 goto error;
372 redraw = FALSE;
373 switch ((error = WaitForMultipleObjects( 2, events, FALSE, INFINITE )))
375 case WAIT_OBJECT_0:
376 if (!GetOverlappedResult( dir0, &ovl0, &count, FALSE ) || !count) break;
377 if (process_changes( desktop_folder, buf0 )) redraw = TRUE;
378 break;
380 case WAIT_OBJECT_0 + 1:
381 if (!GetOverlappedResult( dir1, &ovl1, &count, FALSE ) || !count) break;
382 if (process_changes( desktop_folder_public, buf1 )) redraw = TRUE;
383 break;
385 default:
386 goto error;
388 if (redraw) InvalidateRect( hwnd, NULL, TRUE );
391 error:
392 CloseHandle( dir0 );
393 CloseHandle( dir1 );
394 CloseHandle( events[0] );
395 CloseHandle( events[1] );
396 HeapFree( GetProcessHeap(), 0, buf0 );
397 HeapFree( GetProcessHeap(), 0, buf1 );
398 if (SUCCEEDED( init )) CoUninitialize();
399 return error;
402 static void add_folder( const WCHAR *folder )
404 static const WCHAR lnkW[] = {'\\','*','.','l','n','k',0};
405 int len = strlenW( folder ) + strlenW( lnkW );
406 WIN32_FIND_DATAW data;
407 HANDLE handle;
408 WCHAR *glob;
410 if (!(glob = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return;
411 strcpyW( glob, folder );
412 strcatW( glob, lnkW );
414 if ((handle = FindFirstFileW( glob, &data )) != INVALID_HANDLE_VALUE)
416 do { add_launcher( folder, data.cFileName, -1 ); } while (FindNextFileW( handle, &data ));
417 FindClose( handle );
419 HeapFree( GetProcessHeap(), 0, glob );
422 #define BORDER_SIZE 4
423 #define PADDING_SIZE 4
424 #define TITLE_CHARS 14
426 static void initialize_launchers( HWND hwnd )
428 HRESULT hr, init;
429 TEXTMETRICW tm;
430 int icon_size;
432 if (!(get_icon_text_metrics( hwnd, &tm ))) return;
434 icon_cx = GetSystemMetrics( SM_CXICON );
435 icon_cy = GetSystemMetrics( SM_CYICON );
436 icon_size = max( icon_cx, icon_cy );
437 title_cy = tm.tmHeight * 2;
438 title_cx = max( tm.tmAveCharWidth * TITLE_CHARS, icon_size + PADDING_SIZE + title_cy );
439 launcher_size = BORDER_SIZE + title_cx + BORDER_SIZE;
440 icon_offset_cx = (launcher_size - icon_cx) / 2;
441 icon_offset_cy = BORDER_SIZE + (icon_size - icon_cy) / 2;
442 title_offset_cx = BORDER_SIZE;
443 title_offset_cy = BORDER_SIZE + icon_size + PADDING_SIZE;
444 desktop_width = GetSystemMetrics( SM_CXSCREEN );
445 launchers_per_row = desktop_width / launcher_size;
447 hr = SHGetKnownFolderPath( &FOLDERID_Desktop, KF_FLAG_CREATE, NULL, &desktop_folder );
448 if (FAILED( hr ))
450 WINE_ERR("Could not get user desktop folder\n");
451 return;
453 hr = SHGetKnownFolderPath( &FOLDERID_PublicDesktop, KF_FLAG_CREATE, NULL, &desktop_folder_public );
454 if (FAILED( hr ))
456 WINE_ERR("Could not get public desktop folder\n");
457 CoTaskMemFree( desktop_folder );
458 return;
460 if ((launchers = HeapAlloc( GetProcessHeap(), 0, 2 * sizeof(launchers[0]) )))
462 nb_allocated = 2;
464 init = CoInitialize( NULL );
465 add_folder( desktop_folder );
466 add_folder( desktop_folder_public );
467 if (SUCCEEDED( init )) CoUninitialize();
469 CreateThread( NULL, 0, watch_desktop_folders, hwnd, 0, NULL );
473 /* screen saver handler */
474 static BOOL start_screensaver( void )
476 if (using_root)
478 const char *argv[3] = { "xdg-screensaver", "activate", NULL };
479 int pid = _spawnvp( _P_DETACH, argv[0], argv );
480 if (pid > 0)
482 WINE_TRACE( "started process %d\n", pid );
483 return TRUE;
486 return FALSE;
489 /* window procedure for the desktop window */
490 static LRESULT WINAPI desktop_wnd_proc( HWND hwnd, UINT message, WPARAM wp, LPARAM lp )
492 WINE_TRACE( "got msg %04x wp %lx lp %lx\n", message, wp, lp );
494 switch(message)
496 case WM_SYSCOMMAND:
497 switch(wp & 0xfff0)
499 case SC_CLOSE:
500 ExitWindows( 0, 0 );
501 break;
502 case SC_SCREENSAVE:
503 return start_screensaver();
505 return 0;
507 case WM_CLOSE:
508 PostQuitMessage(0);
509 return 0;
511 case WM_SETCURSOR:
512 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
514 case WM_NCHITTEST:
515 return HTCLIENT;
517 case WM_ERASEBKGND:
518 if (!using_root) PaintDesktop( (HDC)wp );
519 return TRUE;
521 case WM_SETTINGCHANGE:
522 if (wp == SPI_SETDESKWALLPAPER)
523 SystemParametersInfoW( SPI_SETDESKWALLPAPER, 0, NULL, FALSE );
524 return 0;
526 case WM_LBUTTONDBLCLK:
528 const struct launcher *launcher = launcher_from_point( (short)LOWORD(lp), (short)HIWORD(lp) );
529 if (launcher) do_launch( launcher );
531 return 0;
533 case WM_PAINT:
535 PAINTSTRUCT ps;
536 BeginPaint( hwnd, &ps );
537 if (!using_root)
539 if (ps.fErase) PaintDesktop( ps.hdc );
540 draw_launchers( ps.hdc, ps.rcPaint );
542 EndPaint( hwnd, &ps );
544 return 0;
546 default:
547 return DefWindowProcW( hwnd, message, wp, lp );
551 /* create the desktop and the associated driver window, and make it the current desktop */
552 static BOOL create_desktop( const WCHAR *name, unsigned int width, unsigned int height )
554 static const WCHAR rootW[] = {'r','o','o','t',0};
555 BOOL ret = FALSE;
556 BOOL (CDECL *create_desktop_func)(unsigned int, unsigned int);
558 /* magic: desktop "root" means use the root window */
559 if (graphics_driver && strcmpiW( name, rootW ))
561 create_desktop_func = (void *)GetProcAddress( graphics_driver, "wine_create_desktop" );
562 if (create_desktop_func) ret = create_desktop_func( width, height );
564 return ret;
567 /* parse the desktop size specification */
568 static BOOL parse_size( const WCHAR *size, unsigned int *width, unsigned int *height )
570 WCHAR *end;
572 *width = strtoulW( size, &end, 10 );
573 if (end == size) return FALSE;
574 if (*end != 'x') return FALSE;
575 size = end + 1;
576 *height = strtoulW( size, &end, 10 );
577 return !*end;
580 /* retrieve the desktop name to use if not specified on the command line */
581 static const WCHAR *get_default_desktop_name(void)
583 static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
584 static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',0};
585 static const WCHAR explorer_keyW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
586 'E','x','p','l','o','r','e','r',0};
587 static WCHAR buffer[MAX_PATH];
588 DWORD size = sizeof(buffer);
589 HDESK desk = GetThreadDesktop( GetCurrentThreadId() );
590 WCHAR *ret = NULL;
591 HKEY hkey;
593 if (desk && GetUserObjectInformationW( desk, UOI_NAME, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
595 if (strcmpiW( buffer, defaultW )) return buffer;
598 /* @@ Wine registry key: HKCU\Software\Wine\Explorer */
599 if (!RegOpenKeyW( HKEY_CURRENT_USER, explorer_keyW, &hkey ))
601 if (!RegQueryValueExW( hkey, desktopW, 0, NULL, (LPBYTE)buffer, &size )) ret = buffer;
602 RegCloseKey( hkey );
604 return ret;
607 /* retrieve the default desktop size from the registry */
608 static BOOL get_default_desktop_size( const WCHAR *name, unsigned int *width, unsigned int *height )
610 static const WCHAR desktop_keyW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
611 'E','x','p','l','o','r','e','r','\\',
612 'D','e','s','k','t','o','p','s',0};
613 HKEY hkey;
614 WCHAR buffer[64];
615 DWORD size = sizeof(buffer);
616 BOOL found = FALSE;
618 *width = 800;
619 *height = 600;
621 /* @@ Wine registry key: HKCU\Software\Wine\Explorer\Desktops */
622 if (!RegOpenKeyW( HKEY_CURRENT_USER, desktop_keyW, &hkey ))
624 if (!RegQueryValueExW( hkey, name, 0, NULL, (LPBYTE)buffer, &size ))
626 found = TRUE;
627 if (!parse_size( buffer, width, height )) *width = *height = 0;
629 RegCloseKey( hkey );
631 return found;
634 static void initialize_display_settings( HWND desktop )
636 static const WCHAR display_device_guid_propW[] = {
637 '_','_','w','i','n','e','_','d','i','s','p','l','a','y','_',
638 'd','e','v','i','c','e','_','g','u','i','d',0 };
639 GUID guid;
640 RPC_CSTR guid_str;
641 ATOM guid_atom;
642 DEVMODEW dmW;
644 UuidCreate( &guid );
645 UuidToStringA( &guid, &guid_str );
646 WINE_TRACE( "display guid %s\n", guid_str );
648 guid_atom = GlobalAddAtomA( (LPCSTR)guid_str );
649 SetPropW( desktop, display_device_guid_propW, ULongToHandle(guid_atom) );
651 RpcStringFreeA( &guid_str );
653 /* Store current display mode in the registry */
654 if (EnumDisplaySettingsExW( NULL, ENUM_CURRENT_SETTINGS, &dmW, 0 ))
656 WINE_TRACE( "Current display mode %ux%u %u bpp %u Hz\n", dmW.dmPelsWidth,
657 dmW.dmPelsHeight, dmW.dmBitsPerPel, dmW.dmDisplayFrequency );
658 ChangeDisplaySettingsExW( NULL, &dmW, 0,
659 CDS_GLOBAL | CDS_NORESET | CDS_UPDATEREGISTRY,
660 NULL );
664 static void set_desktop_window_title( HWND hwnd, const WCHAR *name )
666 static const WCHAR desktop_nameW[] = {'W','i','n','e',' ','d','e','s','k','t','o','p',0};
667 static const WCHAR desktop_name_separatorW[] = {' ', '-', ' ', 0};
668 WCHAR *window_titleW = NULL;
669 int window_title_len;
671 if (!name[0])
673 SetWindowTextW( hwnd, desktop_nameW );
674 return;
677 window_title_len = strlenW(name) * sizeof(WCHAR)
678 + sizeof(desktop_name_separatorW)
679 + sizeof(desktop_nameW);
680 window_titleW = HeapAlloc( GetProcessHeap(), 0, window_title_len );
681 if (!window_titleW)
683 SetWindowTextW( hwnd, desktop_nameW );
684 return;
687 strcpyW( window_titleW, name );
688 strcatW( window_titleW, desktop_name_separatorW );
689 strcatW( window_titleW, desktop_nameW );
691 SetWindowTextW( hwnd, window_titleW );
692 HeapFree( GetProcessHeap(), 0, window_titleW );
695 /* main desktop management function */
696 void manage_desktop( WCHAR *arg )
698 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
699 HDESK desktop = 0;
700 MSG msg;
701 HDC hdc;
702 HWND hwnd, msg_hwnd;
703 unsigned int width, height;
704 WCHAR *cmdline = NULL;
705 WCHAR *p = arg;
706 const WCHAR *name = NULL;
708 /* get the rest of the command line (if any) */
709 while (*p && !isspace(*p)) p++;
710 if (*p)
712 *p++ = 0;
713 while (*p && isspace(*p)) p++;
714 if (*p) cmdline = p;
717 /* parse the desktop option */
718 /* the option is of the form /desktop=name[,widthxheight] */
719 if (*arg == '=' || *arg == ',')
721 arg++;
722 name = arg;
723 if ((p = strchrW( arg, ',' ))) *p++ = 0;
724 if (!p || !parse_size( p, &width, &height ))
725 get_default_desktop_size( name, &width, &height );
727 else if ((name = get_default_desktop_name()))
729 if (!get_default_desktop_size( name, &width, &height )) width = height = 0;
732 if (name && width && height)
734 if (!(desktop = CreateDesktopW( name, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL )))
736 WINE_ERR( "failed to create desktop %s error %d\n", wine_dbgstr_w(name), GetLastError() );
737 ExitProcess( 1 );
739 SetThreadDesktop( desktop );
742 /* create the desktop window */
743 hwnd = CreateWindowExW( 0, DESKTOP_CLASS_ATOM, NULL,
744 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 0, 0, 0, 0, 0, NULL );
746 /* create the HWND_MESSAGE parent */
747 msg_hwnd = CreateWindowExW( 0, messageW, NULL, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
748 0, 0, 100, 100, 0, 0, 0, NULL );
750 if (hwnd == GetDesktopWindow())
752 HMODULE shell32;
753 void (WINAPI *pShellDDEInit)( BOOL );
755 if (desktop)
757 hdc = GetDC( hwnd );
758 graphics_driver = __wine_get_driver_module( hdc );
759 using_root = !create_desktop( name, width, height );
760 ReleaseDC( hwnd, hdc );
762 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)desktop_wnd_proc );
763 SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( 0, MAKEINTRESOURCEW(OIC_WINLOGO)));
764 if (name) set_desktop_window_title( hwnd, name );
765 SetWindowPos( hwnd, 0, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN),
766 GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN),
767 SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW );
768 SystemParametersInfoW( SPI_SETDESKWALLPAPER, 0, NULL, FALSE );
769 ClipCursor( NULL );
770 initialize_display_settings( hwnd );
771 initialize_appbar();
772 initialize_systray( graphics_driver, using_root );
773 if (!using_root) initialize_launchers( hwnd );
775 if ((shell32 = LoadLibraryA( "shell32.dll" )) &&
776 (pShellDDEInit = (void *)GetProcAddress( shell32, (LPCSTR)188)))
778 pShellDDEInit( TRUE );
781 else
783 DestroyWindow( hwnd ); /* someone beat us to it */
784 hwnd = 0;
787 if (GetAncestor( msg_hwnd, GA_PARENT )) DestroyWindow( msg_hwnd ); /* someone beat us to it */
789 /* if we have a command line, execute it */
790 if (cmdline)
792 STARTUPINFOW si;
793 PROCESS_INFORMATION pi;
795 memset( &si, 0, sizeof(si) );
796 si.cb = sizeof(si);
797 WINE_TRACE( "starting %s\n", wine_dbgstr_w(cmdline) );
798 if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ))
800 CloseHandle( pi.hThread );
801 CloseHandle( pi.hProcess );
805 /* run the desktop message loop */
806 if (hwnd)
808 WINE_TRACE( "desktop message loop starting on hwnd %p\n", hwnd );
809 while (GetMessageW( &msg, 0, 0, 0 )) DispatchMessageW( &msg );
810 WINE_TRACE( "desktop message loop exiting for hwnd %p\n", hwnd );
813 ExitProcess( 0 );