kernel32/tests: Fix fiber tests compilation with __WINESRC__ defined.
[wine.git] / programs / explorer / desktop.c
blob3ea3e6004694c93e7c481d5ed91eab5b4a7c8e7f
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 BOOL using_root;
45 struct launcher
47 WCHAR *path;
48 HICON icon;
49 WCHAR *title;
52 static WCHAR *desktop_folder;
53 static WCHAR *desktop_folder_public;
55 static int icon_cx, icon_cy, icon_offset_cx, icon_offset_cy;
56 static int title_cx, title_cy, title_offset_cx, title_offset_cy;
57 static int desktop_width, launcher_size, launchers_per_row;
59 static struct launcher **launchers;
60 static unsigned int nb_launchers, nb_allocated;
62 static RECT get_icon_rect( unsigned int index )
64 RECT rect;
65 unsigned int row = index / launchers_per_row;
66 unsigned int col = index % launchers_per_row;
68 rect.left = col * launcher_size + icon_offset_cx;
69 rect.right = rect.left + icon_cx;
70 rect.top = row * launcher_size + icon_offset_cy;
71 rect.bottom = rect.top + icon_cy;
72 return rect;
75 static RECT get_title_rect( unsigned int index )
77 RECT rect;
78 unsigned int row = index / launchers_per_row;
79 unsigned int col = index % launchers_per_row;
81 rect.left = col * launcher_size + title_offset_cx;
82 rect.right = rect.left + title_cx;
83 rect.top = row * launcher_size + title_offset_cy;
84 rect.bottom = rect.top + title_cy;
85 return rect;
88 static const struct launcher *launcher_from_point( int x, int y )
90 RECT icon, title;
91 unsigned int index;
93 if (!nb_launchers) return NULL;
94 index = x / launcher_size + (y / launcher_size) * launchers_per_row;
95 if (index >= nb_launchers) return NULL;
97 icon = get_icon_rect( index );
98 title = get_title_rect( index );
99 if ((x < icon.left || x > icon.right || y < icon.top || y > icon.bottom) &&
100 (x < title.left || x > title.right || y < title.top || y > title.bottom)) return NULL;
101 return launchers[index];
104 static void draw_launchers( HDC hdc, RECT update_rect )
106 COLORREF color = SetTextColor( hdc, RGB(255,255,255) ); /* FIXME: depends on background color */
107 int mode = SetBkMode( hdc, TRANSPARENT );
108 unsigned int i;
109 LOGFONTW lf;
110 HFONT font;
112 SystemParametersInfoW( SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0 );
113 font = SelectObject( hdc, CreateFontIndirectW( &lf ) );
115 for (i = 0; i < nb_launchers; i++)
117 RECT dummy, icon = get_icon_rect( i ), title = get_title_rect( i );
119 if (IntersectRect( &dummy, &icon, &update_rect ))
120 DrawIconEx( hdc, icon.left, icon.top, launchers[i]->icon, icon_cx, icon_cy,
121 0, 0, DI_DEFAULTSIZE|DI_NORMAL );
123 if (IntersectRect( &dummy, &title, &update_rect ))
124 DrawTextW( hdc, launchers[i]->title, -1, &title,
125 DT_CENTER|DT_WORDBREAK|DT_EDITCONTROL|DT_END_ELLIPSIS );
128 SelectObject( hdc, font );
129 SetTextColor( hdc, color );
130 SetBkMode( hdc, mode );
133 static void do_launch( const struct launcher *launcher )
135 static const WCHAR openW[] = {'o','p','e','n',0};
136 ShellExecuteW( NULL, openW, launcher->path, NULL, NULL, 0 );
139 static WCHAR *append_path( const WCHAR *path, const WCHAR *filename, int len_filename )
141 int len_path = strlenW( path );
142 WCHAR *ret;
144 if (len_filename == -1) len_filename = strlenW( filename );
145 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len_path + len_filename + 2) * sizeof(WCHAR) )))
146 return NULL;
147 memcpy( ret, path, len_path * sizeof(WCHAR) );
148 ret[len_path] = '\\';
149 memcpy( ret + len_path + 1, filename, len_filename * sizeof(WCHAR) );
150 ret[len_path + 1 + len_filename] = 0;
151 return ret;
154 static IShellLinkW *load_shelllink( const WCHAR *path )
156 HRESULT hr;
157 IShellLinkW *link;
158 IPersistFile *file;
160 hr = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW,
161 (void **)&link );
162 if (FAILED( hr )) return NULL;
164 hr = IShellLinkW_QueryInterface( link, &IID_IPersistFile, (void **)&file );
165 if (FAILED( hr ))
167 IShellLinkW_Release( link );
168 return NULL;
170 hr = IPersistFile_Load( file, path, 0 );
171 IPersistFile_Release( file );
172 if (FAILED( hr ))
174 IShellLinkW_Release( link );
175 return NULL;
177 return link;
180 static HICON extract_icon( IShellLinkW *link )
182 WCHAR tmp_path[MAX_PATH], icon_path[MAX_PATH], target_path[MAX_PATH];
183 HICON icon = NULL;
184 int index;
186 tmp_path[0] = 0;
187 IShellLinkW_GetIconLocation( link, tmp_path, MAX_PATH, &index );
188 ExpandEnvironmentStringsW( tmp_path, icon_path, MAX_PATH );
190 if (icon_path[0]) ExtractIconExW( icon_path, index, &icon, NULL, 1 );
191 if (!icon)
193 tmp_path[0] = 0;
194 IShellLinkW_GetPath( link, tmp_path, MAX_PATH, NULL, SLGP_RAWPATH );
195 ExpandEnvironmentStringsW( tmp_path, target_path, MAX_PATH );
196 ExtractIconExW( target_path, index, &icon, NULL, 1 );
198 return icon;
201 static WCHAR *build_title( const WCHAR *filename, int len )
203 const WCHAR *p;
204 WCHAR *ret;
206 if (len == -1) len = strlenW( filename );
207 for (p = filename + len - 1; p >= filename; p--)
209 if (*p == '.')
211 len = p - filename;
212 break;
215 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
216 memcpy( ret, filename, len * sizeof(WCHAR) );
217 ret[len] = 0;
218 return ret;
221 static BOOL add_launcher( const WCHAR *folder, const WCHAR *filename, int len_filename )
223 struct launcher *launcher;
224 IShellLinkW *link;
226 if (nb_launchers == nb_allocated)
228 unsigned int count = nb_allocated * 2;
229 struct launcher **tmp = HeapReAlloc( GetProcessHeap(), 0, launchers, count * sizeof(*tmp) );
230 if (!tmp) return FALSE;
231 launchers = tmp;
232 nb_allocated = count;
235 if (!(launcher = HeapAlloc( GetProcessHeap(), 0, sizeof(*launcher) ))) return FALSE;
236 if (!(launcher->path = append_path( folder, filename, len_filename ))) goto error;
237 if (!(link = load_shelllink( launcher->path ))) goto error;
239 launcher->icon = extract_icon( link );
240 launcher->title = build_title( filename, len_filename );
241 IShellLinkW_Release( link );
242 if (launcher->icon && launcher->title)
244 launchers[nb_launchers++] = launcher;
245 return TRUE;
247 HeapFree( GetProcessHeap(), 0, launcher->title );
248 DestroyIcon( launcher->icon );
250 error:
251 HeapFree( GetProcessHeap(), 0, launcher->path );
252 HeapFree( GetProcessHeap(), 0, launcher );
253 return FALSE;
256 static void free_launcher( struct launcher *launcher )
258 DestroyIcon( launcher->icon );
259 HeapFree( GetProcessHeap(), 0, launcher->path );
260 HeapFree( GetProcessHeap(), 0, launcher->title );
261 HeapFree( GetProcessHeap(), 0, launcher );
264 static BOOL remove_launcher( const WCHAR *folder, const WCHAR *filename, int len_filename )
266 UINT i;
267 WCHAR *path;
268 BOOL ret = FALSE;
270 if (!(path = append_path( folder, filename, len_filename ))) return FALSE;
271 for (i = 0; i < nb_launchers; i++)
273 if (!strcmpiW( launchers[i]->path, path ))
275 free_launcher( launchers[i] );
276 if (--nb_launchers)
277 memmove( &launchers[i], &launchers[i + 1], sizeof(launchers[i]) * (nb_launchers - i) );
278 ret = TRUE;
279 break;
282 HeapFree( GetProcessHeap(), 0, path );
283 return ret;
286 static BOOL get_icon_text_metrics( HWND hwnd, TEXTMETRICW *tm )
288 BOOL ret;
289 HDC hdc;
290 LOGFONTW lf;
291 HFONT hfont;
293 hdc = GetDC( hwnd );
294 SystemParametersInfoW( SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0 );
295 hfont = SelectObject( hdc, CreateFontIndirectW( &lf ) );
296 ret = GetTextMetricsW( hdc, tm );
297 SelectObject( hdc, hfont );
298 ReleaseDC( hwnd, hdc );
299 return ret;
302 static BOOL process_changes( const WCHAR *folder, char *buf )
304 FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION *)buf;
305 BOOL ret = FALSE;
307 for (;;)
309 switch (info->Action)
311 case FILE_ACTION_ADDED:
312 case FILE_ACTION_RENAMED_NEW_NAME:
313 if (add_launcher( folder, info->FileName, info->FileNameLength / sizeof(WCHAR) ))
314 ret = TRUE;
315 break;
317 case FILE_ACTION_REMOVED:
318 case FILE_ACTION_RENAMED_OLD_NAME:
319 if (remove_launcher( folder, info->FileName, info->FileNameLength / sizeof(WCHAR) ))
320 ret = TRUE;
321 break;
323 default:
324 WARN( "unexpected action %u\n", info->Action );
325 break;
327 if (!info->NextEntryOffset) break;
328 info = (FILE_NOTIFY_INFORMATION *)((char *)info + info->NextEntryOffset);
330 return ret;
333 static DWORD CALLBACK watch_desktop_folders( LPVOID param )
335 HWND hwnd = param;
336 HRESULT init = CoInitialize( NULL );
337 HANDLE dir0, dir1, events[2];
338 OVERLAPPED ovl0, ovl1;
339 char *buf0 = NULL, *buf1 = NULL;
340 DWORD count, size = 4096, error = ERROR_OUTOFMEMORY;
341 BOOL ret, redraw;
343 dir0 = CreateFileW( desktop_folder, FILE_LIST_DIRECTORY|SYNCHRONIZE, FILE_SHARE_READ|FILE_SHARE_WRITE,
344 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL );
345 if (dir0 == INVALID_HANDLE_VALUE) return GetLastError();
346 dir1 = CreateFileW( desktop_folder_public, FILE_LIST_DIRECTORY|SYNCHRONIZE, FILE_SHARE_READ|FILE_SHARE_WRITE,
347 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL );
348 if (dir1 == INVALID_HANDLE_VALUE)
350 CloseHandle( dir0 );
351 return GetLastError();
353 if (!(ovl0.hEvent = events[0] = CreateEventW( NULL, FALSE, FALSE, NULL ))) goto error;
354 if (!(ovl1.hEvent = events[1] = CreateEventW( NULL, FALSE, FALSE, NULL ))) goto error;
355 if (!(buf0 = HeapAlloc( GetProcessHeap(), 0, size ))) goto error;
356 if (!(buf1 = HeapAlloc( GetProcessHeap(), 0, size ))) goto error;
358 for (;;)
360 ret = ReadDirectoryChangesW( dir0, buf0, size, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ovl0, NULL );
361 if (!ret)
363 error = GetLastError();
364 goto error;
366 ret = ReadDirectoryChangesW( dir1, buf1, size, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ovl1, NULL );
367 if (!ret)
369 error = GetLastError();
370 goto error;
373 redraw = FALSE;
374 switch ((error = WaitForMultipleObjects( 2, events, FALSE, INFINITE )))
376 case WAIT_OBJECT_0:
377 if (!GetOverlappedResult( dir0, &ovl0, &count, FALSE ) || !count) break;
378 if (process_changes( desktop_folder, buf0 )) redraw = TRUE;
379 break;
381 case WAIT_OBJECT_0 + 1:
382 if (!GetOverlappedResult( dir1, &ovl1, &count, FALSE ) || !count) break;
383 if (process_changes( desktop_folder_public, buf1 )) redraw = TRUE;
384 break;
386 default:
387 goto error;
389 if (redraw) InvalidateRect( hwnd, NULL, TRUE );
392 error:
393 CloseHandle( dir0 );
394 CloseHandle( dir1 );
395 CloseHandle( events[0] );
396 CloseHandle( events[1] );
397 HeapFree( GetProcessHeap(), 0, buf0 );
398 HeapFree( GetProcessHeap(), 0, buf1 );
399 if (SUCCEEDED( init )) CoUninitialize();
400 return error;
403 static void add_folder( const WCHAR *folder )
405 static const WCHAR lnkW[] = {'\\','*','.','l','n','k',0};
406 int len = strlenW( folder ) + strlenW( lnkW );
407 WIN32_FIND_DATAW data;
408 HANDLE handle;
409 WCHAR *glob;
411 if (!(glob = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return;
412 strcpyW( glob, folder );
413 strcatW( glob, lnkW );
415 if ((handle = FindFirstFileW( glob, &data )) != INVALID_HANDLE_VALUE)
417 do { add_launcher( folder, data.cFileName, -1 ); } while (FindNextFileW( handle, &data ));
418 FindClose( handle );
420 HeapFree( GetProcessHeap(), 0, glob );
423 #define BORDER_SIZE 4
424 #define PADDING_SIZE 4
425 #define TITLE_CHARS 14
427 static void initialize_launchers( HWND hwnd )
429 HRESULT hr, init;
430 TEXTMETRICW tm;
431 int icon_size;
433 if (!(get_icon_text_metrics( hwnd, &tm ))) return;
435 icon_cx = GetSystemMetrics( SM_CXICON );
436 icon_cy = GetSystemMetrics( SM_CYICON );
437 icon_size = max( icon_cx, icon_cy );
438 title_cy = tm.tmHeight * 2;
439 title_cx = max( tm.tmAveCharWidth * TITLE_CHARS, icon_size + PADDING_SIZE + title_cy );
440 launcher_size = BORDER_SIZE + title_cx + BORDER_SIZE;
441 icon_offset_cx = (launcher_size - icon_cx) / 2;
442 icon_offset_cy = BORDER_SIZE + (icon_size - icon_cy) / 2;
443 title_offset_cx = BORDER_SIZE;
444 title_offset_cy = BORDER_SIZE + icon_size + PADDING_SIZE;
445 desktop_width = GetSystemMetrics( SM_CXSCREEN );
446 launchers_per_row = desktop_width / launcher_size;
448 hr = SHGetKnownFolderPath( &FOLDERID_Desktop, KF_FLAG_CREATE, NULL, &desktop_folder );
449 if (FAILED( hr ))
451 WINE_ERR("Could not get user desktop folder\n");
452 return;
454 hr = SHGetKnownFolderPath( &FOLDERID_PublicDesktop, KF_FLAG_CREATE, NULL, &desktop_folder_public );
455 if (FAILED( hr ))
457 WINE_ERR("Could not get public desktop folder\n");
458 CoTaskMemFree( desktop_folder );
459 return;
461 if ((launchers = HeapAlloc( GetProcessHeap(), 0, 2 * sizeof(launchers[0]) )))
463 nb_allocated = 2;
465 init = CoInitialize( NULL );
466 add_folder( desktop_folder );
467 add_folder( desktop_folder_public );
468 if (SUCCEEDED( init )) CoUninitialize();
470 CreateThread( NULL, 0, watch_desktop_folders, hwnd, 0, NULL );
474 /* screen saver handler */
475 static BOOL start_screensaver( void )
477 if (using_root)
479 const char *argv[3] = { "xdg-screensaver", "activate", NULL };
480 int pid = _spawnvp( _P_DETACH, argv[0], argv );
481 if (pid > 0)
483 WINE_TRACE( "started process %d\n", pid );
484 return TRUE;
487 return FALSE;
490 /* window procedure for the desktop window */
491 static LRESULT WINAPI desktop_wnd_proc( HWND hwnd, UINT message, WPARAM wp, LPARAM lp )
493 WINE_TRACE( "got msg %04x wp %lx lp %lx\n", message, wp, lp );
495 switch(message)
497 case WM_SYSCOMMAND:
498 switch(wp & 0xfff0)
500 case SC_CLOSE:
501 ExitWindows( 0, 0 );
502 break;
503 case SC_SCREENSAVE:
504 return start_screensaver();
506 return 0;
508 case WM_CLOSE:
509 PostQuitMessage(0);
510 return 0;
512 case WM_SETCURSOR:
513 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
515 case WM_NCHITTEST:
516 return HTCLIENT;
518 case WM_ERASEBKGND:
519 if (!using_root) PaintDesktop( (HDC)wp );
520 return TRUE;
522 case WM_SETTINGCHANGE:
523 if (wp == SPI_SETDESKWALLPAPER)
524 SystemParametersInfoW( SPI_SETDESKWALLPAPER, 0, NULL, FALSE );
525 return 0;
527 case WM_LBUTTONDBLCLK:
528 if (!using_root)
530 const struct launcher *launcher = launcher_from_point( (short)LOWORD(lp), (short)HIWORD(lp) );
531 if (launcher) do_launch( launcher );
533 return 0;
535 case WM_PAINT:
537 PAINTSTRUCT ps;
538 BeginPaint( hwnd, &ps );
539 if (!using_root)
541 if (ps.fErase) PaintDesktop( ps.hdc );
542 draw_launchers( ps.hdc, ps.rcPaint );
544 EndPaint( hwnd, &ps );
546 return 0;
548 default:
549 return DefWindowProcW( hwnd, message, wp, lp );
553 /* create the desktop and the associated driver window, and make it the current desktop */
554 static BOOL create_desktop( HMODULE driver, const WCHAR *name, unsigned int width, unsigned int height )
556 static const WCHAR rootW[] = {'r','o','o','t',0};
557 BOOL ret = FALSE;
558 BOOL (CDECL *create_desktop_func)(unsigned int, unsigned int);
560 /* magic: desktop "root" means use the root window */
561 if (driver && strcmpiW( name, rootW ))
563 create_desktop_func = (void *)GetProcAddress( driver, "wine_create_desktop" );
564 if (create_desktop_func) ret = create_desktop_func( width, height );
566 return ret;
569 /* parse the desktop size specification */
570 static BOOL parse_size( const WCHAR *size, unsigned int *width, unsigned int *height )
572 WCHAR *end;
574 *width = strtoulW( size, &end, 10 );
575 if (end == size) return FALSE;
576 if (*end != 'x') return FALSE;
577 size = end + 1;
578 *height = strtoulW( size, &end, 10 );
579 return !*end;
582 /* retrieve the desktop name to use if not specified on the command line */
583 static const WCHAR *get_default_desktop_name(void)
585 static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
586 static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',0};
587 static const WCHAR explorer_keyW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
588 'E','x','p','l','o','r','e','r',0};
589 static WCHAR buffer[MAX_PATH];
590 DWORD size = sizeof(buffer);
591 HDESK desk = GetThreadDesktop( GetCurrentThreadId() );
592 WCHAR *ret = NULL;
593 HKEY hkey;
595 if (desk && GetUserObjectInformationW( desk, UOI_NAME, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
597 if (strcmpiW( buffer, defaultW )) return buffer;
600 /* @@ Wine registry key: HKCU\Software\Wine\Explorer */
601 if (!RegOpenKeyW( HKEY_CURRENT_USER, explorer_keyW, &hkey ))
603 if (!RegQueryValueExW( hkey, desktopW, 0, NULL, (LPBYTE)buffer, &size )) ret = buffer;
604 RegCloseKey( hkey );
606 return ret;
609 /* retrieve the default desktop size from the registry */
610 static BOOL get_default_desktop_size( const WCHAR *name, unsigned int *width, unsigned int *height )
612 static const WCHAR desktop_keyW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
613 'E','x','p','l','o','r','e','r','\\',
614 'D','e','s','k','t','o','p','s',0};
615 HKEY hkey;
616 WCHAR buffer[64];
617 DWORD size = sizeof(buffer);
618 BOOL found = FALSE;
620 *width = 800;
621 *height = 600;
623 /* @@ Wine registry key: HKCU\Software\Wine\Explorer\Desktops */
624 if (!RegOpenKeyW( HKEY_CURRENT_USER, desktop_keyW, &hkey ))
626 if (!RegQueryValueExW( hkey, name, 0, NULL, (LPBYTE)buffer, &size ))
628 found = TRUE;
629 if (!parse_size( buffer, width, height )) *width = *height = 0;
631 RegCloseKey( hkey );
633 return found;
636 static void initialize_display_settings( HWND desktop )
638 static const WCHAR display_device_guid_propW[] = {
639 '_','_','w','i','n','e','_','d','i','s','p','l','a','y','_',
640 'd','e','v','i','c','e','_','g','u','i','d',0 };
641 GUID guid;
642 RPC_CSTR guid_str;
643 ATOM guid_atom;
644 DEVMODEW dmW;
646 UuidCreate( &guid );
647 UuidToStringA( &guid, &guid_str );
648 WINE_TRACE( "display guid %s\n", guid_str );
650 guid_atom = GlobalAddAtomA( (LPCSTR)guid_str );
651 SetPropW( desktop, display_device_guid_propW, ULongToHandle(guid_atom) );
653 RpcStringFreeA( &guid_str );
655 /* Store current display mode in the registry */
656 if (EnumDisplaySettingsExW( NULL, ENUM_CURRENT_SETTINGS, &dmW, 0 ))
658 WINE_TRACE( "Current display mode %ux%u %u bpp %u Hz\n", dmW.dmPelsWidth,
659 dmW.dmPelsHeight, dmW.dmBitsPerPel, dmW.dmDisplayFrequency );
660 ChangeDisplaySettingsExW( NULL, &dmW, 0,
661 CDS_GLOBAL | CDS_NORESET | CDS_UPDATEREGISTRY,
662 NULL );
666 static void set_desktop_window_title( HWND hwnd, const WCHAR *name )
668 static const WCHAR desktop_nameW[] = {'W','i','n','e',' ','d','e','s','k','t','o','p',0};
669 static const WCHAR desktop_name_separatorW[] = {' ', '-', ' ', 0};
670 WCHAR *window_titleW = NULL;
671 int window_title_len;
673 if (!name[0])
675 SetWindowTextW( hwnd, desktop_nameW );
676 return;
679 window_title_len = strlenW(name) * sizeof(WCHAR)
680 + sizeof(desktop_name_separatorW)
681 + sizeof(desktop_nameW);
682 window_titleW = HeapAlloc( GetProcessHeap(), 0, window_title_len );
683 if (!window_titleW)
685 SetWindowTextW( hwnd, desktop_nameW );
686 return;
689 strcpyW( window_titleW, name );
690 strcatW( window_titleW, desktop_name_separatorW );
691 strcatW( window_titleW, desktop_nameW );
693 SetWindowTextW( hwnd, window_titleW );
694 HeapFree( GetProcessHeap(), 0, window_titleW );
697 /* main desktop management function */
698 void manage_desktop( WCHAR *arg )
700 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
701 HDESK desktop = 0;
702 MSG msg;
703 HDC hdc;
704 HWND hwnd, msg_hwnd;
705 unsigned int width, height;
706 WCHAR *cmdline = NULL;
707 WCHAR *p = arg;
708 const WCHAR *name = NULL;
710 /* get the rest of the command line (if any) */
711 while (*p && !isspace(*p)) p++;
712 if (*p)
714 *p++ = 0;
715 while (*p && isspace(*p)) p++;
716 if (*p) cmdline = p;
719 /* parse the desktop option */
720 /* the option is of the form /desktop=name[,widthxheight] */
721 if (*arg == '=' || *arg == ',')
723 arg++;
724 name = arg;
725 if ((p = strchrW( arg, ',' ))) *p++ = 0;
726 if (!p || !parse_size( p, &width, &height ))
727 get_default_desktop_size( name, &width, &height );
729 else if ((name = get_default_desktop_name()))
731 if (!get_default_desktop_size( name, &width, &height )) width = height = 0;
734 if (name && width && height)
736 if (!(desktop = CreateDesktopW( name, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL )))
738 WINE_ERR( "failed to create desktop %s error %d\n", wine_dbgstr_w(name), GetLastError() );
739 ExitProcess( 1 );
741 SetThreadDesktop( desktop );
744 /* create the desktop window */
745 hwnd = CreateWindowExW( 0, DESKTOP_CLASS_ATOM, NULL,
746 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 0, 0, 0, 0, 0, NULL );
748 /* create the HWND_MESSAGE parent */
749 msg_hwnd = CreateWindowExW( 0, messageW, NULL, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
750 0, 0, 100, 100, 0, 0, 0, NULL );
752 if (hwnd == GetDesktopWindow())
754 HMODULE shell32, graphics_driver;
755 void (WINAPI *pShellDDEInit)( BOOL );
757 hdc = GetDC( hwnd );
758 graphics_driver = __wine_get_driver_module( hdc );
759 using_root = !desktop || !create_desktop( graphics_driver, 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 );