home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- * This is a part of the Microsoft Source Code Samples.
- * Copyright (C) 1995 Microsoft Corporation.
- * All rights reserved.
- * This source code is only intended as a supplement to
- * Microsoft Development Tools and/or WinHelp documentation.
- * See these sources for detailed information regarding the
- * Microsoft samples programs.
- *
- *****************************************************************************/
-
- /****************************************************************************
-
- PROGRAM: desktop.c
-
- PURPOSE: Allow user to switch between active desktops on the User's
- WindowStation
-
- USAGE: desktop [-t #threads]
- #threads is the number of desktops and corresponding threads to create
-
- APIS of Importance:
- CreateDesktop()
- SwitchDesktop()
- GetUserObjectInformation()
- GetThreadDesktop()
- SetThreadDesktop()
- CloseDesktop()
- OpenDesktop()
-
- FUNCTIONS:
- WinMain
- StartNewDesktop
- CreateAllDesktops
- LoadResources
- InitApplication
- ThreadInit
- SaveScreen
- PaintMainWnd
- RunApp
- GetFontHeight
- TitleWindow
- CreateControls
- WndProc
- PreviewWndProc
- EditProc
-
-
- COMMENTS: This application demonstrates the multiple desktop
- capabilities of Windows NT 3.51, PPC release.
-
-
-
- ****************************************************************************/
-
- #include <windows.h> // required for all Windows applications
-
- #include "switcher.h" // specific to this program
-
- //
- // Array of string resources
- //
- TCHAR SwitchStrings[LAST_STRING-FIRST_STRING + 1][MAXSTRLEN];
- #define PSZ(x) SwitchStrings[x-FIRST_STRING]
-
- //
- // Structure used for thread-specific data
- //
- typedef struct _tdata
- {
- HDESK hDesk; // desktop assigned to new thread
- int index; // index into deskArray
- HWND hWndStatic; // "Run:" static control
- HWND hWndEdit; // edit control for user input
- HWND hWndBtn; // button for user input
- HWND hWndNew; // button for new desktop
- } ThreadData;
-
- int gMaxIndex; // Highest index for array of desk handles
- HWND gBaseWindow; // Window handle of default desktop window
- HDESK gDeskArray[MAX_THREADS]; // Global array of desktop handles
- HWND hWndArray[MAX_THREADS]; // Global array of window handles
- HDC gHDCArray[MAX_THREADS]; // global array of memory device contexts
- // these DCs store snapshots of the desktops
- int gWidth, gHeight; // dimensions of desktop rectangles
-
- //
- // Keep track of how big the controls need to be to match the
- // active system fixed font. These will help determine the
- // minimum size of the switcher window.
- //
- int gStaticWidth; // Edit control label
- int gEditWidth; // Edit control
- int gBtnWidth; // Button to run app in edit control
- int gNewWidth; // Button to create new desktop
-
- HINSTANCE ghInst = NULL; // Global hInstance
- #define DEFAULT_DESKTOP gDeskArray[0] // For easy reading
- LONG APIENTRY EditProc (HWND, UINT, WPARAM, LPARAM);
- TCHAR szAppName[] = TEXT("Desktop Switcher!");
- TCHAR szClassName[] = TEXT("SwitcherWindow");
- TCHAR szPreviewClass[]= TEXT("PreviewWindow");
-
- /****************************************************************************
- FUNCTION: StartNewDesktop
-
- PURPOSE: Create or open a handle to a desktop and put a switcher thread
- on it.
-
- ARGUMENTS:
- int nCount - Which desktop number this is
-
- Assumes gDeskArray[nCount] == NULL
-
- ****************************************************************************/
-
- void StartNewDesktop (int nCount)
- {
- ThreadData *ptd;
- TCHAR szDesk[50];
- DWORD tID;
- ptd = (ThreadData*)GlobalAlloc(GMEM_FIXED,sizeof(ThreadData));
- if (ptd)
- {
- ptd->index = nCount;
- //
- // Give the desktop a name.
- //
- wsprintf (szDesk, PSZ(IDS_DESKTOPNAME), nCount+1);
- //
- // First, try to open an existing desktop
- //
- if ( !(ptd->hDesk = OpenDesktop (szDesk, 0, FALSE, GENERIC_ALL)))
- {
- //
- // Failing an open, Create it
- //
- if (!(ptd->hDesk= CreateDesktop (szDesk, NULL,
- NULL,0,MAXIMUM_ALLOWED,
- NULL)))
- {
-
- MessageBox (NULL, PSZ(IDS_CREATEERROR),
- PSZ(IDS_ERRCAPTION), MB_OK);
- //
- //Mark this array slot as invalid
- //
- gDeskArray[nCount] = NULL;
-
- }
-
- }
- if (ptd->hDesk)
- {
- //
- // Save the handle to the global array. Start the new thread
- //
- gDeskArray[ptd->index] = ptd->hDesk;
- CloseHandle(CreateThread(NULL, 0,
- (LPTHREAD_START_ROUTINE)ThreadInit,
- (LPVOID)ptd, 0, &tID));
- }
- }
- else
- {
- //
- // Out of memory
- //
- MessageBox (NULL, PSZ(IDS_CREATEERROR),
- PSZ(IDS_MEMERRCAPTION), MB_OK);
- //
- //Mark this array slot as invalid
- //
- gDeskArray[nCount] = NULL;
- }
-
- }
- /****************************************************************************
-
- FUNCTION: CreateAllDesktops (cThreads)
-
- PURPOSE: Creates desktops and assigns a switcher thread to each.
- Updates the global desktop array.
-
- ARGUMENTS:
- int cThreads - Number of threads/desktops to open or create
-
- ****************************************************************************/
-
- void CreateAllDesktops (int cThreads)
- {
- ThreadData *ptdDefault;
-
-
- //
- // Make sure we allocate for the default desktop first
- //
- ptdDefault = (ThreadData *)GlobalAlloc (GMEM_FIXED, sizeof(ThreadData));
- if (!ptdDefault) {
- return;
- }
- while (cThreads)
- {
- StartNewDesktop (cThreads);
- cThreads--;
- }
- //
- // Main thread is one of the running threads too
- //
- ptdDefault->index = 0;
- ptdDefault->hDesk = DEFAULT_DESKTOP;
- ThreadInit((LPVOID)ptdDefault);
-
- }
-
- /****************************************************************************
-
- FUNCTION: WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
-
- PURPOSE: Creates the threads and desktops
- COMMENTS: Each thread has a separate desktop assigned to it.
-
-
- ****************************************************************************/
- int CALLBACK WinMain(
- HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPSTR lpCmdLine,
- int nCmdShow)
- {
-
- int cThreads; // number of desktops
-
- ghInst = hInstance;
-
- if (hPrevInstance)
- { // Other instances of app running?
- return (FALSE); // Exit
- } else {
- if (!InitApplication ()) {
- return FALSE;
- }
- }
-
- // parse command line to determine number of desktops
- // Assume 9 threads
-
- cThreads = 9;
- lpCmdLine = GetCommandLineA();
-
- //
- // Get past .exe name
- //
- while (*lpCmdLine != ' ' && *lpCmdLine != 0)
- lpCmdLine++;
-
- //
- // Find the parameters
- //
- while (*lpCmdLine != 0)
- {
-
- // Eat white space
-
- if (*lpCmdLine == ' ')
- {
- lpCmdLine++;
- continue;
- }
-
- //
- // Do we have a dash? If not, just exit the loop
- //
- if (*lpCmdLine++ != '-')
- break;
-
- switch (*lpCmdLine++)
- {
- case 't':
- case 'T':
- //
- // How many threads?
- //
-
- while (*lpCmdLine == ' ')
- lpCmdLine++;
-
- if (*lpCmdLine == 0 || *lpCmdLine == '-')
- continue;
-
- cThreads = 0;
- while (*lpCmdLine >= '0' && *lpCmdLine <= '9')
- cThreads = cThreads * 10 + (*lpCmdLine++ - 0x30);
- break;
-
- }
- }
-
- // Create the threads - if zero was specified, default to 1.
- // What does 0 threads mean?
- if (cThreads == 0)
- cThreads = 1;
- else if (cThreads > MAX_THREADS)
- cThreads = MAX_THREADS;
- //
- // Account for the main thread - only create extras
- //
- cThreads--;
- gMaxIndex = cThreads; // Keep track of the highest array index
-
- //
- // Assign this here, since threads reference it
- //
- DEFAULT_DESKTOP = GetThreadDesktop(GetCurrentThreadId());
- CreateAllDesktops (cThreads);
- return 0;
- }
-
- /*************************************************************
- FUNCTION: LoadResources
-
- PURPOSE: Load string table entries
-
- ARGUMENTS: None
-
- RETURNS: True if all strings are loaded, False otherwise
-
- *************************************************************/
-
- BOOL LoadResources (void)
- {
- int i;
- for (i=0;i<(LAST_STRING-FIRST_STRING+1);i++)
- {
- if (!LoadString (ghInst, FIRST_STRING + i, SwitchStrings[i], MAXSTRLEN))
- return FALSE;
- }
- return TRUE;
- }
- /*************************************************************
-
- FUNCTION: InitApplication
-
- PURPOSE: Register the window class and init global variables
-
- ARGUMENTS:
-
- RETURNS:
- TRUE if window class registration and other initialization succeeds
-
- **************************************************************/
-
- BOOL InitApplication (void) {
-
- WNDCLASS wc;
- HWND hTemp;
- HWINSTA hWndSta;
- RECT rect;
-
- if (!LoadResources ())
- return FALSE;
- //
- // Initialize the gHDCArray to all NULLS
- //
- ZeroMemory (gHDCArray, sizeof (gHDCArray));
- hTemp = GetDesktopWindow(); // Call this so User will assign us a WindowStation.
- //
- // Initialize gWidth and gHeight
- // Get the size of the screen, make gWidth/gHeight == scrnW/scrnH
- //
- GetClientRect (hTemp, &rect);
- gWidth = rect.right/DIVISOR;
- gHeight = rect.bottom/DIVISOR;
-
- //
- // Make sure this app has a windowstation
- //
- hWndSta = GetProcessWindowStation();
- if (!hWndSta)
- {
- MessageBox (NULL, PSZ(IDS_WNDSTAERROR), PSZ(IDS_ERRCAPTION), MB_OK);
- return FALSE;
- }
- //
- // Register the main window class
- //
- wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
- wc.lpfnWndProc = WndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = ghInst;
- wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
- wc.hCursor = LoadCursor (NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)GetStockObject (WHITE_BRUSH);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = szClassName;
-
- if (!RegisterClass (&wc))
- {
- return FALSE;
- }
-
- //
- // Register the preview window class
- //
- wc.style = 0;
- wc.lpfnWndProc = PreviewWndProc;
- wc.lpszClassName = szPreviewClass;
-
- if (!RegisterClass (&wc)) {
- return FALSE;
- }
-
-
- return TRUE;
- }
-
- /*******************************************************************
-
- FUNCTION: ThreadInit
-
- PURPOSE: Given a desktop handle, create a window on it to allow switching
- among desktops.
-
- ARGUMENTS:
- LPVOID tData - Thread-specific data
-
- RETURNS:
- nothing
- ********************************************************************/
-
- void ThreadInit(LPVOID tData)
- {
- MSG msg;
- HWND hWnd;
- HDC hTemp;
- int width; // window width
- USEROBJECTFLAGS uof; // To set Desktop attributes
-
- uof.fInherit = FALSE; // If an app inherits multiple desktop handles,
- // it could run on any one of those desktops
- uof.fReserved = FALSE;
- //
- // Let other account processes hook this desktop
- //
- uof.dwFlags = DF_ALLOWOTHERACCOUNTHOOK;
- SetUserObjectInformation (((ThreadData*)tData)->hDesk,
- UOI_FLAGS,
- (LPVOID)&uof,
- sizeof(uof));
- //
- // Make sure the handle is valid
- //
- if (gDeskArray[((ThreadData*)tData)->index])
- {
- //
- // Assign new desktop to this thread
- //
- SetThreadDesktop (((ThreadData*)tData)->hDesk);
- // create the cool switcher window
- if ((gMaxIndex+1) * gWidth > MINWINDOWWIDTH)
- {
- width = (gMaxIndex+1) * gWidth;
- }
- else
- {
- width = MINWINDOWWIDTH;
- }
- hWnd = CreateWindow (szClassName,
- szAppName,
- WS_MINIMIZEBOX|WS_OVERLAPPED|WS_VISIBLE|WS_BORDER|WS_CAPTION|WS_SYSMENU,
- 0, 0, width, 30+gHeight + CONTROLHEIGHT,
- NULL, NULL, ghInst, tData);
- if (!hWnd) // bag it
- {
- gDeskArray[((ThreadData*)tData)->index] = NULL;
- GlobalFree (tData);
- return;
- }
-
- //
- //update the global window array
- //
- hWndArray[((ThreadData*)tData)->index] = hWnd;
-
- }
- else
- {
-
- GlobalFree (tData);
- return;
- }
-
- //
- // Acquire and dispatch messages until a WM_QUIT message is received.
- //
- while (GetMessage(&msg, NULL, 0, 0))
- {
- TranslateMessage(&msg);// Translates virtual key codes
- DispatchMessage(&msg); // Dispatches message to window
- }
- //
- // Switch back to the default desktop and close the user-created one
- //
- SetThreadDesktop (DEFAULT_DESKTOP);
- SwitchDesktop (DEFAULT_DESKTOP);
- CloseDesktop (((ThreadData*)tData)->hDesk);
- //
- // NULL out the global array entry so other threads won't try to switch to
- // this desktop
- //
- gDeskArray[((ThreadData*)tData)->index] = NULL;
- //
- // cleanup
- //
- hTemp = gHDCArray[((ThreadData*)tData)->index];
- gHDCArray[((ThreadData*)tData)->index] = NULL;
- DeleteObject (hTemp);
- GlobalFree (tData);
-
- }
-
-
- /***********************************************************************
-
- FUNCTION: SaveScreen
-
- PURPOSE: Save a snapshot of the desktop to its corresponding
- memory DC. StretchBlt!
-
- ARGUMENTS:
- int index - Index of memory DC to save bits to
-
- RETURNS: nothing
- ************************************************************************/
-
- void SaveScreen (int index) {
- HDC hdc;
- int xSize, ySize;
-
- xSize = GetSystemMetrics (SM_CXSCREEN);
- ySize = GetSystemMetrics (SM_CYSCREEN);
-
- if (hdc = CreateDC (TEXT("DISPLAY"), NULL, NULL, NULL))
- {
- //
- // Copy the desktop to a memory DC
- //
- StretchBlt (gHDCArray[index], 0, 0, gWidth*2, gHeight*2,
- hdc, 0, 0, xSize, ySize, SRCCOPY);
- DeleteDC (hdc);
- }
- }
-
- /*******************************************************************************
-
- FUNCTION: PaintMainWnd
-
- PURPOSE: Draw the main window. This window has rectangles with miniature snapshots
- of each desktop. The snapshots are retrieved from the gHDCArray and StretchBlt'd to
- the right size.
-
- ARGUMENTS:
- HWND hWnd - Window to draw
-
- RETURNS: nothing
-
- *******************************************************************************/
-
- void PaintMainWnd (HWND hWnd)
- {
- PAINTSTRUCT ps;
- RECT rect;
- HPEN hPen, hOld;
- ThreadData *ptd;
- TCHAR szName[4]; // short name!
- int myThread;
- HDC hDC; // always need a dc for drawing
- int i; // my favorite loop counter
-
- //
- // get the array index of this window
- //
- ptd = (ThreadData *)GetWindowLong (hWnd, GWL_USERDATA);
- myThread = ptd->index;
-
- //
- //Draw a rectangle for each desktop
- //
- hDC = BeginPaint (hWnd, &ps);
- if (GetClientRect (hWnd, &rect))
- {
- int right, left;
- //
- // leave space for edit control and button
- //
- rect.bottom -= CONTROLHEIGHT;
- hPen = CreatePen (PS_SOLID | PS_INSIDEFRAME, 2, RGB(255,16,16));
- hOld = SelectObject (hDC, hPen);
-
- //
- // draw each desktop rectangle
- //
- for (i=0;i<=gMaxIndex;i++)
- {
- right = gWidth * i + gWidth;
- left = right - gWidth;
- //
- // If no snapshot is available, be boring
- //
- if (!gHDCArray[i])
- {
- Rectangle (hDC, left, rect.top, right, gHeight);
- wsprintf (szName, TEXT("%d"), i+1);
- TextOut (hDC, left+(gWidth/2),
- gHeight/2, szName,
- lstrlen (szName));
- }
- else
- {
- //
- // BitBlt the snapshot into the rectangle
- //
- StretchBlt (hDC, left, rect.top, gWidth, gHeight,
- gHDCArray[i], 0, 0, gWidth*2, gHeight*2, SRCCOPY);
- //
- // draw lines around the rectangle
- //
- MoveToEx (hDC, left, rect.top, NULL);
- LineTo (hDC, left, gHeight);
- MoveToEx (hDC, right, rect.top, NULL);
- LineTo (hDC, right, gHeight);
- //
- // underline the active one
- //
- if (myThread == i)
- {
- MoveToEx (hDC, left, gHeight, NULL);
- LineTo (hDC, right, gHeight);
- }
- }
- }
- //
- // cleanup
- //
- SelectObject (hDC, hOld);
- DeleteObject (hPen);
- }
-
- EndPaint (hWnd, &ps);
-
- }
-
- /****************************************************************************
-
- FUNCTION: RunApp (HWND)
-
- PURPOSE: Create a process, using contents of HWND's edit control
- as the command line.
-
- ARGUMENTS:
- HWND hWnd - Handle of active switcher window
-
- RETURNS: nothing
-
- COMMENTS: Make sure proper desktop is passed in STARTUPINFO
-
- ****************************************************************************/
-
- void RunApp (HWND hWnd)
- {
- TCHAR szDesk[100]; // data holder
- TCHAR szExec[100]; // Command line
- STARTUPINFO sui; // Process startup info
- PROCESS_INFORMATION pi; // info returned from CreateProcess
- ThreadData *ptd;
-
- ptd = (ThreadData*)GetWindowLong (hWnd, GWL_USERDATA);
- //
- // Most sui members will be 0
- //
- ZeroMemory ((PVOID)&sui, sizeof(sui));
- //
- //Get the command line to execute
- //
- GetDlgItemText (hWnd, IDC_RUNME, szExec, 100*sizeof(TCHAR));
- //
- //Get the current desktop name
- //
- GetUserObjectInformation (GetThreadDesktop (GetCurrentThreadId()),
- UOI_NAME,
- szDesk,
- 100*sizeof(TCHAR),
- NULL);
- sui.cb = sizeof (sui);
- //
- // Need the lpDesktop member so the new process runs on this desktop
- // The lpDesktop member was reserved in previous versions of NT
- //
- sui.lpDesktop = szDesk;
- CreateProcess (NULL, // image name
- szExec, // command line
- NULL, // process security attributes
- NULL, // thread security attributes
- TRUE, // inherit handles
- CREATE_DEFAULT_ERROR_MODE|CREATE_SEPARATE_WOW_VDM,
- NULL, // environment block
- NULL, // current directory
- &sui, // STARTUPINFO
- &pi); // PROCESS_INFORMATION
-
- }
- /****************************************************************************
- FUNCTION: GetFontHeight
-
- PURPOSE: Set up widths for controls based on size of the system
- font.
-
- ARGUMENTS:
- HWND hWnd - Window whose DC to use.
-
- RETURNS:
- Return the height of the system fixed font to use for
- the controls.
-
- ****************************************************************************/
-
- LONG GetFontHeight (HWND hWnd)
- {
- HDC hdc;
- TEXTMETRIC tm;
- SIZE size;
- #define MARGIN 7 // extra space on the button around the text
-
- hdc = GetDC (hWnd);
- if (!GetTextMetrics (hdc, &tm))
- {
- //
- // Use defaults
- //
- gStaticWidth = STATICWIDTH;
- gBtnWidth = BTNWIDTH;
- gEditWidth = EDITWIDTH;
- gNewWidth = BTNWIDTH + 25;
- return CONTROLHEIGHT;
- }
-
- //
- // GetTextExtentPoint32 fills in size with the width and height of
- // a string.
- //
- GetTextExtentPoint32 (hdc, PSZ(IDS_RUNLABEL), lstrlen(PSZ(IDS_RUNLABEL)), &size);
- gStaticWidth = size.cx + MARGIN;
- gEditWidth = EDITWIDTH;
- GetTextExtentPoint32 (hdc, PSZ(IDS_BTNLABEL), lstrlen(PSZ(IDS_BTNLABEL)), &size);
- gBtnWidth = size.cx + MARGIN;
- GetTextExtentPoint32 (hdc, PSZ(IDS_NEWLABEL), lstrlen(PSZ(IDS_NEWLABEL)), &size);
- gNewWidth = size.cx + MARGIN;
- ReleaseDC (hWnd, hdc);
- return tm.tmHeight + 2;
-
- }
-
- /****************************************************************************
- FUNCTION: TitleWindow
-
- PURPOSE: Give a switcher window an appropriate title, using its
- desktop name.
-
- ARGUMENTS:
- HWND hWnd - Window to title
-
- RETURNS: nothing
-
- ****************************************************************************/
-
- void TitleWindow (HWND hWnd)
- {
- TCHAR *szTitle, *szName;
- UINT nBytes = 0;
-
- //
- // How long is the desktop name?
- //
- GetUserObjectInformation (GetThreadDesktop(GetCurrentThreadId()),
- UOI_NAME,
- (LPVOID)&nBytes, // not used since cbInfo is 0
- 0,
- &nBytes);
- szName = (LPTSTR)GlobalAlloc (GPTR, nBytes);
- if (!szName)
- {
- return;
- }
- //
- // Now get the desktop name
- //
- GetUserObjectInformation (GetThreadDesktop(GetCurrentThreadId()),
- UOI_NAME,
- (LPVOID)szName,
- nBytes,
- &nBytes);
- //
- // Now make the window title
- //
- szTitle = (LPTSTR)GlobalAlloc (
- GPTR,
- (lstrlen(szAppName)+lstrlen(TEXT(" - "))) * sizeof(TCHAR) + nBytes);
-
- if (!szTitle)
- {
- GlobalFree (szName);
- return;
- }
- wsprintf (szTitle, TEXT("%s - %s"), szAppName, szName);
- SetWindowText (hWnd, szTitle);
- //
- // Cleanup
- //
- GlobalFree (szName);
- GlobalFree (szTitle);
- }
-
- /****************************************************************************
-
- FUNCTION: CreateControls (ThreadData *, HWND)
-
- PURPOSE: Creates UI controls on a switcher window
-
- ARGUMENTS:
- ThreadData *ptd - Thread specific data to use/init
- HWND hWnd - Parent window
-
- RETURNS:
- nothing
-
-
- ****************************************************************************/
-
- void CreateControls (ThreadData *ptd, HWND hWnd)
- {
- LONG oldproc;
-
- //
- // Create the edit control label
- //
- ptd->hWndStatic = CreateWindow (TEXT("static"), PSZ(IDS_RUNLABELHOT),
- WS_CHILD | WS_VISIBLE,
- 0,0,0,0, hWnd, (HMENU)IDC_STATIC,
- ghInst, NULL);
- //
- // Create the edit control
- //
- ptd->hWndEdit = CreateWindow (TEXT("Edit"), TEXT(""),
- WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL,
- 0,0,0,0, hWnd, (HMENU)IDC_RUNME,
- ghInst, NULL);
-
- //
- // set the edit control proc and save the default one
- //
- oldproc = GetWindowLong (ptd->hWndEdit, GWL_WNDPROC);
- SetWindowLong (ptd->hWndEdit, GWL_WNDPROC, (LONG)EditProc);
- SetWindowLong (ptd->hWndEdit, GWL_USERDATA, oldproc);
-
- //
- // Create the execution button
- //
- ptd->hWndBtn = CreateWindow (TEXT("Button"), PSZ(IDS_BTNLABEL),
- WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
- 0,0,0,0, hWnd, (HMENU)IDC_RUNMEBTN,
- ghInst, NULL);
- //
- // Create a button for creating new desktops
- //
- ptd->hWndNew = CreateWindow (TEXT("button"), PSZ(IDS_NEWLABELHOT),
- WS_CHILD | WS_VISIBLE,
- 0,0,0,0, hWnd, (HMENU)IDC_NEWDSKBTN,
- ghInst, NULL);
-
- }
- /****************************************************************************
-
- FUNCTION: WndProc(UINT, WPARAM, LPARAM)
-
- PURPOSE: Processes messages to the Switcher window
-
- MESSAGES:
- WM_RBUTTONDOWN - Switch to desktop whose rectangle is under the mouse
- WM_CLOSE - Send WM_CLOSE to all windows in hWndArray
- WM_LBUTTONDOWN - Create a preview window to display a larger view of
- a desktop until WM_LBUTTONUP
- WM_COMMAND - Respond to button pushes or edit control entry
- WM_SYSCHAR - ALT+R sets focus to the edit control
- ALT+N creates a new desktop
- WM_CHAR - Carriage return executes command line from
- the edit control
- WM_HOTKEY
- WM_KEYDOWN - Respond to function keys by switching to
- the appropriate desktop. Example, F2 means switch
- to Desktop2. Ctrl-F# allows switching without
- giving focus to the switcher window
- WM_LBUTTONUP - Close the active preview window
- WM_CREATE - Initialize controls and global array entries
- WM_SIZE - Size the child controls correctly
-
-
- COMMENTS:
-
- ****************************************************************************/
-
- LONG APIENTRY WndProc(
- HWND hWnd,
- UINT message, // type of message
- WPARAM wParam, // additional information
- LPARAM lParam) // additional information
- {
-
- int newThread; // Thread index to switch to
- int i;
- ThreadData *ptd;
- static HWND hShowing = NULL; // which preview window is being shown
- static LONG fntHeight = CONTROLHEIGHT; // height for the edit control
- switch (message)
- {
- case WM_CREATE:
- {
- HDC hDC;
- HBITMAP hBmp;
-
- // Create edit control, button, and label at the bottom of the window
- // This will allow the user to input a program to run
-
- SetWindowLong (hWnd, GWL_USERDATA,
- (LONG)((CREATESTRUCT *)lParam)->lpCreateParams);
- ptd = (ThreadData *)GetWindowLong (hWnd, GWL_USERDATA);
- CreateControls (ptd, hWnd);
- fntHeight = GetFontHeight (hWnd);
- //
- // initialize the DC array entry
- //
- hDC = CreateDC (TEXT("DISPLAY"), NULL, NULL, NULL);
- gHDCArray[ptd->index] = CreateCompatibleDC (hDC);
- //
- // Halftone is the best stretching algorithm
- //
- SetStretchBltMode (gHDCArray[ptd->index], HALFTONE);
- SetBrushOrgEx (gHDCArray[ptd->index], 0, 0, NULL);
- //
- // Use a bitmap the same size as the desktop preview rectangles
- //
- hBmp = CreateCompatibleBitmap (hDC, gWidth*2, gHeight*2);
- SelectObject (gHDCArray[ptd->index], hBmp);
- DeleteDC (hDC);
- SaveScreen (ptd->index);
- TitleWindow (hWnd);
- //
- // Register hot keys
- //
- for (i=0;i<10;i++)
- {
- RegisterHotKey (hWnd, VK_F1+i, MOD_CONTROL, VK_F1+i);
- }
- return 0;
- }
-
- case WM_SIZE:
- {
- //
- // Put the child controls at the right places
- //
- #define PADDING 5
-
- RECT rect;
- ThreadData *ptd;
- if (GetClientRect (hWnd, &rect))
- {
- ptd = (ThreadData *)GetWindowLong (hWnd, GWL_USERDATA);
- MoveWindow (ptd->hWndStatic, 0, rect.bottom - CONTROLHEIGHT,
- gStaticWidth, fntHeight + PADDING, TRUE);
-
- MoveWindow (ptd->hWndEdit, gStaticWidth + 5,
- rect.bottom - fntHeight - PADDING,
- gEditWidth, fntHeight+PADDING, TRUE);
-
- MoveWindow (ptd->hWndBtn, gStaticWidth + gEditWidth + 10,
- rect.bottom - fntHeight - PADDING,
- gBtnWidth, fntHeight+PADDING, TRUE);
-
- MoveWindow (ptd->hWndNew, gStaticWidth+gEditWidth+gBtnWidth+15,
- rect.bottom - fntHeight- PADDING,
- gNewWidth, fntHeight+PADDING, TRUE);
-
-
- }
- return 0;
- }
- case WM_PAINT:
- PaintMainWnd (hWnd);
- return 0;
-
- case WM_RBUTTONDOWN:
- {
- //
- // Find the rectangle in which the button was pressed
- //
- POINTS pts;
- ThreadData *ptd;
- ptd = (ThreadData *)GetWindowLong(hWnd, GWL_USERDATA);
- pts = MAKEPOINTS (lParam);
- if (pts.y > gHeight)
- {
- return 1;
- }
- newThread = pts.x/gWidth;
-
- //
- // Get a snapshot of the current desktop
- //
- SaveScreen (ptd->index);
-
- //
- // Switch to the selected desktop
- //
- if (!gDeskArray[newThread])
- {
- StartNewDesktop (newThread);
- }
- if (!SwitchDesktop (gDeskArray[newThread]))
- MessageBox (hWnd,
- PSZ(IDS_BADDESKTOP),
- PSZ(IDS_ERRCAPTION), MB_OK);
-
- return 0;
- }
-
- case WM_LBUTTONDOWN:
- //
- // show the preview window
- //
- {
- POINTS pts;
- POINT ptl;
- int *index;
-
- pts = MAKEPOINTS (lParam);
- if (pts.y > gHeight)
- {
- return 1;
- }
- newThread = pts.x/gWidth;
- index = GlobalAlloc (GMEM_FIXED, sizeof(int));
- if (!index)
- {
- return 1;
- }
- *index = newThread;
- //
- // Want to show the preview window where the button was clicked.
- // Map the given points to screen coords.
- // ClientToScreen is expecting a POINT structure, not a POINTS
- //
- ptl.x = (LONG)pts.x;
- ptl.y = (LONG)pts.y;
- ClientToScreen (hWnd, &ptl);
- hShowing = CreateWindow (szPreviewClass, TEXT(""),
- WS_POPUP | WS_VISIBLE | WS_BORDER,
- ptl.x+3,
- ptl.y+3,
- gWidth*2,
- gHeight*2,
- hWnd,
- (HMENU)0, ghInst, (LPVOID)index);
- return 0;
- }
-
- case WM_CHAR:
- if (wParam == VK_RETURN)
- {
- PostMessage (hWnd, WM_COMMAND, (WPARAM)IDC_RUNMEBTN, 0);
- }
- return 0;
-
- case WM_SYSCHAR:
- {
- ThreadData *ptd;
- ptd = (ThreadData *)GetWindowLong(hWnd, GWL_USERDATA);
- switch (wParam)
- {
- // alt+r == focus on the edit control
- case TEXT('r'):
- case TEXT('R'):
- if (GetKeyState (VK_MENU))
- {
- SetFocus (ptd->hWndEdit);
- }
- return 0;
- // alt+n = create a new desktop
- case TEXT('n'):
- case TEXT('N'):
- if (GetKeyState (VK_MENU))
- {
- PostMessage (hWnd, WM_COMMAND, (WPARAM)IDC_NEWDSKBTN, 0);
- }
- }
- return 0;
- }
- case WM_HOTKEY:
- case WM_KEYDOWN:
- //
- // F1-F9 switches to corresponding desktop
- //
-
- if ((wParam >= VK_F1 && wParam <= VK_F10)
- && (wParam - VK_F1 <= (UINT)gMaxIndex))
- {
- LONG x, y;
- x = (wParam - VK_F1) * gWidth + 2;
- y = gHeight - 4;
- PostMessage (hWnd, WM_RBUTTONDOWN, 0, MAKELPARAM (x, y));
- }
- return 0;
-
- case WM_SETFOCUS:
- case WM_NCLBUTTONUP:
- case WM_LBUTTONUP:
-
- //
- // destroy the preview window
- //
- if (hShowing)
- {
- DestroyWindow (hShowing);
- hShowing = NULL;
- }
- return 0;
-
-
-
- case WM_CLOSE:
- //
- // to be safe, check for a preview window
- //
- if (hShowing)
- {
- DestroyWindow (hShowing);
- hShowing = NULL;
- }
- //
- // go to the default desktop so the DestroyWindow calls all succeed
- //
- SwitchDesktop (DEFAULT_DESKTOP);
- //
- // kill the window on this desktop
- // all the windows will be destroyed if this is the default desktop
- //
- for (i=gMaxIndex;i>=0;i--)
- {
- DestroyWindow (hWndArray[i]);
- }
- //
- // Unregister the hot keys
- //
- for (i=0;i<10;i++)
- {
- UnregisterHotKey (hWnd,VK_F1+i);
- }
- return 0;
-
- case WM_DESTROY: // message: window being destroyed
-
- PostQuitMessage(0);
- return 0;
-
-
- case WM_COMMAND:
- {
-
- switch (LOWORD(wParam))
- {
- case IDC_RUNMEBTN:
- {
- RunApp (hWnd);
- return 0;
- }
-
- case IDC_NEWDSKBTN:
- //
- // Create a new desktop and resize the windows to show it.
- //
- {
- RECT rect;
- int i;
- if (gMaxIndex + 1 < MAX_THREADS)
- {
- gMaxIndex++;
- StartNewDesktop (gMaxIndex);
- GetWindowRect (hWnd,&rect);
- for (i=0;i<gMaxIndex;i++)
- {
- MoveWindow (hWndArray[i],
- rect.left, rect.top,
- rect.right + gWidth, rect.bottom-rect.top,
- TRUE);
-
- }
- }
- return 0;
-
- }
-
- default:
- return DefWindowProc (hWnd, message, wParam, lParam);
- }
- }
-
- default: // Passes it on if unprocessed
- return (DefWindowProc (hWnd, message, wParam, lParam));
- }
-
- }
-
- /***********************************************************
-
- FUNCTION: PreviewWndProc
-
- PURPOSE: Displays an enlarged view of the last snapshot of a desktop
-
- ************************************************************/
-
- LONG APIENTRY PreviewWndProc (HWND hWnd,
- UINT msg,
- WPARAM wParam,
- LPARAM lParam)
- {
-
- int *index;
- switch (msg)
- {
- case WM_CREATE:
- //
- // save the index
- //
- SetWindowLong (hWnd, GWL_USERDATA,
- (LONG)((CREATESTRUCT *)lParam)->lpCreateParams);
-
- return 0;
-
- case WM_PAINT:
- {
- HDC hdc;
- PAINTSTRUCT ps;
- index = (int *)GetWindowLong (hWnd, GWL_USERDATA);
- hdc = BeginPaint (hWnd, &ps);
- //
- // slap in the desktop picture
- //
- BitBlt (hdc, 0, 0, gWidth*2, gHeight*2,
- gHDCArray[*index], 0, 0, SRCCOPY);
- EndPaint (hWnd, &ps);
- return 0;
- }
- case WM_LBUTTONUP:
- {
- //
- // In case the button is released in my client area
- //
- HWND hp;
- hp = GetWindow (hWnd, GW_OWNER);
- PostMessage (hp, msg, wParam, lParam);
- return 0;
- }
- case WM_CLOSE:
- {
- //
- // cleanup the index pointer
- //
- index = (int *)GetWindowLong (hWnd, GWL_USERDATA);
- GlobalFree (index);
-
- return DefWindowProc (hWnd, msg, wParam, lParam);
- }
- default:
- return DefWindowProc (hWnd, msg, wParam, lParam);
-
- }
- }
-
- /********************************************
-
- FUNCTION: EditProc
-
- PURPOSE: subclass the edit control to handle carriage returns
-
- ********************************************/
-
- LONG APIENTRY EditProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- if (WM_CHAR == msg && (TCHAR)wParam == 0xD)
- {
- PostMessage (GetParent (hWnd), WM_COMMAND, (WPARAM)IDC_RUNMEBTN, 0);
- return 0;
- }
- //
- // call the default edit control procedure
- //
- return CallWindowProc ( (WNDPROC)GetWindowLong (hWnd, GWL_USERDATA),
- hWnd, msg, wParam, lParam);
- }