ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

appswitch.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:       See COPYING in the top level directory
00003  * PROJECT:         ReactOS system libraries
00004  * FILE:            dll/win32/user32/controls/appswitch.c
00005  * PURPOSE:         app switching functionality
00006  * PROGRAMMERS:     Johannes Anderwald (janderwald@reactos.org)
00007  *                  David Quintana (gigaherz@gmail.com)
00008  */
00009 
00010 #include <user32.h>
00011 
00012 #include <wine/debug.h>
00013 WINE_DEFAULT_DEBUG_CHANNEL(user32);
00014 
00015 // limit the number of windows shown in the alt-tab window
00016 // 120 windows results in (12*40) by (10*40) pixels worth of icons.
00017 #define MAX_WINDOWS 120
00018 
00019 // Global variables
00020 HWND switchdialog;
00021 HFONT dialogFont;
00022 int selectedWindow = 0;
00023 BOOL isOpen = FALSE;
00024 
00025 int fontHeight=0;
00026 
00027 WCHAR windowText[1024];
00028 
00029 HWND windowList[MAX_WINDOWS];
00030 HICON iconList[MAX_WINDOWS];
00031 int windowCount = 0;
00032 
00033 int cxBorder, cyBorder;
00034 int nItems, nCols, nRows;
00035 int itemsW, itemsH;
00036 int totalW, totalH;
00037 int xOffset, yOffset;
00038 POINT pt;
00039 
00040 void ResizeAndCenter(HWND hwnd, int width, int height)
00041 {
00042    int screenwidth = GetSystemMetrics(SM_CXSCREEN);
00043    int screenheight = GetSystemMetrics(SM_CYSCREEN);
00044 
00045    pt.x = (screenwidth - width) / 2;
00046    pt.y = (screenheight - height) / 2;
00047 
00048    MoveWindow(hwnd, pt.x, pt.y, width, height, FALSE);
00049 }
00050 
00051 void MakeWindowActive(HWND hwnd)
00052 {
00053    WINDOWPLACEMENT wpl;
00054 
00055    wpl.length = sizeof(WINDOWPLACEMENT);
00056    GetWindowPlacement(hwnd, &wpl);
00057   
00058    TRACE("GetWindowPlacement wpl.showCmd %d\n",wpl.showCmd);
00059    if (wpl.showCmd == SW_SHOWMINIMIZED)
00060       ShowWindowAsync(hwnd, SW_RESTORE);
00061 
00062    BringWindowToTop(hwnd);  // same as: SetWindowPos(hwnd,HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); ?
00063    SetForegroundWindow(hwnd);
00064 }
00065 
00066 void CompleteSwitch(BOOL doSwitch)
00067 {
00068    if (!isOpen)
00069       return;
00070 
00071    isOpen = FALSE;
00072 
00073    TRACE("[ATbot] CompleteSwitch Hiding Window.\n");
00074    ShowWindow(switchdialog, SW_HIDE);
00075 
00076    if(doSwitch)
00077    {
00078       if(selectedWindow >= windowCount)
00079          return;
00080 
00081       // FIXME: workaround because reactos fails to activate the previous window correctly.
00082       //if(selectedWindow != 0)
00083       {
00084          HWND hwnd = windowList[selectedWindow];
00085                   
00086          GetWindowTextW(hwnd, windowText, 1023);
00087 
00088          TRACE("[ATbot] CompleteSwitch Switching to 0x%08x (%ls)\n", hwnd, windowText);
00089 
00090          MakeWindowActive(hwnd);
00091       }
00092    }
00093 
00094    windowCount = 0;
00095 }
00096 
00097 BOOL CALLBACK EnumerateCallback(HWND window, LPARAM lParam)
00098 {
00099    HICON hIcon;
00100 
00101    UNREFERENCED_PARAMETER(lParam);
00102 
00103    if (!IsWindowVisible(window))
00104             return TRUE;
00105 
00106    GetClassNameW(window,windowText,4095);
00107    if ((wcscmp(L"Shell_TrayWnd",windowText)==0) ||
00108        (wcscmp(L"Progman",windowText)==0) )
00109             return TRUE;
00110       
00111    // First try to get the big icon assigned to the window
00112    hIcon = (HICON)SendMessageW(window, WM_GETICON, ICON_BIG, 0);
00113    if (!hIcon)
00114    {
00115       // If no icon is assigned, try to get the icon assigned to the windows' class
00116       hIcon = (HICON)GetClassLongPtrW(window, GCL_HICON);
00117       if (!hIcon)
00118       {
00119          // If we still don't have an icon, see if we can do with the small icon,
00120          // or a default application icon
00121          hIcon = (HICON)SendMessageW(window, WM_GETICON, ICON_SMALL2, 0);
00122          if (!hIcon)
00123          {
00124             // If all fails, give up and continue with the next window
00125             return TRUE;
00126          }
00127       }
00128    }
00129 
00130    windowList[windowCount] = window;
00131    iconList[windowCount] = CopyIcon(hIcon);
00132 
00133    windowCount++;
00134 
00135    // If we got to the max number of windows,
00136    // we won't be able to add any more
00137    if(windowCount == MAX_WINDOWS)
00138       return FALSE;
00139 
00140    return TRUE;
00141 }
00142 
00143 // Function mostly compatible with the normal EnumWindows,
00144 // except it lists in Z-Order and it doesn't ensure consistency
00145 // if a window is removed while enumerating
00146 void EnumWindowsZOrder(WNDENUMPROC callback, LPARAM lParam)
00147 {
00148     HWND next = GetTopWindow(NULL);
00149     while (next != NULL)
00150     {
00151         if(!callback(next, lParam))
00152          break;
00153         next = GetWindow(next, GW_HWNDNEXT);
00154     }
00155 }
00156 
00157 void ProcessMouseMessage(UINT message, LPARAM lParam)
00158 {
00159    int xPos = LOWORD(lParam); 
00160    int yPos = HIWORD(lParam); 
00161 
00162    int xIndex = (xPos - xOffset)/40;
00163    int xOff   = (xPos - xOffset)%40;
00164 
00165    int yIndex = (yPos - yOffset)/40;
00166    int yOff   = (yPos - yOffset)%40;
00167 
00168    if(xOff > 32 || xIndex > nItems)
00169       return;
00170 
00171    if(yOff > 32 || yIndex > nRows)
00172       return;
00173 
00174    selectedWindow = (yIndex*nCols) + xIndex;
00175    if (message == WM_MOUSEMOVE)
00176    {
00177       InvalidateRect(switchdialog, NULL, TRUE);
00178       //RedrawWindow(switchdialog, NULL, NULL, 0);
00179    }
00180    else
00181    {
00182       selectedWindow = (yIndex*nCols) + xIndex;
00183       CompleteSwitch(TRUE);
00184    }
00185 }
00186 
00187 void OnPaint(HWND hWnd)
00188 {
00189    HDC dialogDC;
00190    PAINTSTRUCT paint;
00191    RECT cRC, textRC;
00192    int i;
00193    HBRUSH hBrush;
00194    HPEN hPen;
00195    HFONT dcFont;
00196    COLORREF cr;
00197    int nch = GetWindowTextW(windowList[selectedWindow], windowText, 1023);
00198 
00199    dialogDC = BeginPaint(hWnd, &paint);
00200    {
00201       GetClientRect(hWnd, &cRC);
00202       FillRect(dialogDC, &cRC, GetSysColorBrush(COLOR_MENU));
00203 
00204       for(i=0; i< windowCount; i++)
00205       {
00206          HICON hIcon = iconList[i];
00207          
00208          int xpos = xOffset + 40 * (i % nCols);
00209          int ypos = yOffset + 40 * (i / nCols);
00210 
00211          if (selectedWindow == i)
00212          {
00213             hBrush = GetSysColorBrush(COLOR_HIGHLIGHT);
00214          }
00215          else
00216          {
00217             hBrush = GetSysColorBrush(COLOR_MENU);
00218          }
00219 #if TRUE
00220          cr = GetSysColor(COLOR_BTNTEXT); // doesn't look right! >_<
00221          hPen = CreatePen(PS_DOT, 1, cr);
00222          SelectObject(dialogDC, hPen);
00223          SelectObject(dialogDC, hBrush);
00224          Rectangle(dialogDC, xpos-2, ypos-2, xpos+32+2, ypos+32+2);
00225          DeleteObject(hPen);
00226          // Must NOT destroy the system brush!
00227 #else
00228          RECT rc = { xpos-2, ypos-2, xpos+32+2, ypos+32+2 };
00229          FillRect(dialogDC, &rc, hBrush);
00230 #endif
00231          DrawIcon(dialogDC, xpos, ypos, hIcon);
00232       }
00233 
00234       dcFont = SelectObject(dialogDC, dialogFont);
00235       SetTextColor(dialogDC, GetSysColor(COLOR_BTNTEXT));
00236       SetBkColor(dialogDC, GetSysColor(COLOR_BTNFACE));
00237 
00238       textRC.top = itemsH;
00239       textRC.left = 8;
00240       textRC.right = totalW - 8;
00241       textRC.bottom = totalH - 8;
00242       DrawTextW(dialogDC, windowText, nch, &textRC, DT_CENTER|DT_END_ELLIPSIS);
00243       SelectObject(dialogDC, dcFont);
00244    }
00245    EndPaint(hWnd, &paint);
00246 }
00247 
00248 DWORD CreateSwitcherWindow(HINSTANCE hInstance)
00249 {
00250     switchdialog = CreateWindowExW( WS_EX_TOPMOST|WS_EX_DLGMODALFRAME|WS_EX_TOOLWINDOW,
00251                                     WC_SWITCH,
00252                                     L"",
00253                                     WS_POPUP|WS_BORDER|WS_DISABLED,
00254                                     CW_USEDEFAULT,
00255                                     CW_USEDEFAULT,
00256                                     400, 150,
00257                                     NULL, NULL,
00258                                     hInstance, NULL);
00259     if (!switchdialog)
00260     {
00261        TRACE("[ATbot] Task Switcher Window failed to create.\n");
00262        return 0;
00263     }
00264                                 
00265     isOpen = FALSE;
00266     return 1;
00267 }
00268                                         
00269 DWORD GetDialogFont()
00270 {
00271    HDC tDC;
00272    TEXTMETRIC tm;
00273 
00274    dialogFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
00275 
00276    tDC = GetDC(0);
00277    GetTextMetrics(tDC, &tm);
00278    fontHeight = tm.tmHeight;
00279    ReleaseDC(0, tDC);
00280 
00281    return 1;
00282 }
00283 
00284 void PrepareWindow()
00285 {
00286    cxBorder = GetSystemMetrics(SM_CXBORDER);
00287    cyBorder = GetSystemMetrics(SM_CYBORDER);
00288    
00289    nItems = windowCount;
00290    nCols = min(max(nItems,8),12);
00291    nRows = (nItems+nCols-1)/nCols;
00292 
00293    itemsW = nCols*32 + (nCols+1)*8;
00294    itemsH = nRows*32 + (nRows+1)*8;
00295 
00296    totalW = itemsW + 2*cxBorder + 4;
00297    totalH = itemsH + 2*cyBorder + fontHeight + 8; // give extra pixels for the window title
00298 
00299    xOffset = 8;
00300    yOffset = 8;
00301 
00302    if (nItems < nCols)
00303    {
00304       int w2 = nItems*32 + (nItems-1)*8;
00305       xOffset = (itemsW-w2)/2;
00306    }
00307    ResizeAndCenter(switchdialog, totalW, totalH);
00308 }
00309 
00310 void ProcessHotKey()
00311 {
00312    if (!isOpen)
00313    {
00314       windowCount=0;
00315       EnumWindowsZOrder(EnumerateCallback, 0);
00316 
00317       if (windowCount < 2)
00318          return;
00319 
00320       selectedWindow = 1;
00321 
00322       TRACE("[ATbot] HotKey Received. Opening window.\n");
00323       ShowWindow(switchdialog, SW_SHOWNORMAL);
00324       MakeWindowActive(switchdialog);
00325       isOpen = TRUE;
00326    }
00327    else
00328    {
00329       TRACE("[ATbot] HotKey Received  Rotating.\n");
00330       selectedWindow = (selectedWindow + 1)%windowCount;
00331       InvalidateRect(switchdialog, NULL, TRUE);
00332    }
00333 }
00334 
00335 LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam )
00336 {
00337    HWND hwnd;
00338    MSG msg;
00339    BOOL Esc = FALSE;
00340    INT Count = 0;
00341    WCHAR Text[1024];
00342 
00343    switchdialog = NULL;
00344 
00345    switch (lParam)
00346    {
00347       case VK_TAB:
00348          if( !CreateSwitcherWindow(User32Instance) ) return 0;
00349          if( !GetDialogFont() ) return 0;
00350          ProcessHotKey();
00351          break;
00352 
00353       case VK_ESCAPE:
00354          windowCount = 0;
00355          Count = 0;
00356          EnumWindowsZOrder(EnumerateCallback, 0);
00357          if (windowCount < 2) return 0;
00358          if (wParam == SC_NEXTWINDOW)
00359             Count = 1;
00360          else
00361          {
00362             if (windowCount == 2)
00363                Count = 0;
00364             else
00365                Count = windowCount - 1;
00366          }
00367          TRACE("DoAppSwitch VK_ESCAPE 1 Count %d windowCount %d\n",Count,windowCount);
00368          hwnd = windowList[Count];
00369          GetWindowTextW(hwnd, Text, 1023);
00370          TRACE("[ATbot] Switching to 0x%08x (%ls)\n", hwnd, Text);
00371          MakeWindowActive(hwnd);
00372          Esc = TRUE;
00373          break;
00374 
00375       default:
00376          return 0;
00377    }
00378    // Main message loop:
00379    while (1)
00380    {
00381       for (;;)
00382       {
00383          if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ))
00384          {
00385              if (!CallMsgFilterW( &msg, MSGF_NEXTWINDOW )) break;
00386              /* remove the message from the queue */
00387              PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
00388          }
00389          else
00390              WaitMessage();
00391       }
00392 
00393       switch (msg.message)
00394       {
00395         case WM_KEYUP:
00396         {
00397           PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
00398           if (msg.wParam == VK_MENU)
00399           {
00400              CompleteSwitch(TRUE);
00401           }
00402           else if (msg.wParam == VK_RETURN)
00403           {
00404              CompleteSwitch(TRUE);
00405           }
00406           else if (msg.wParam == VK_ESCAPE)
00407           {
00408              TRACE("DoAppSwitch VK_ESCAPE 2\n");
00409              CompleteSwitch(FALSE);
00410           }
00411           goto Exit; //break;
00412         }
00413 
00414         case WM_SYSKEYDOWN:
00415         {
00416           PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
00417           if (HIWORD(msg.lParam) & KF_ALTDOWN)
00418           {
00419              INT Shift;
00420              if ( msg.wParam == VK_TAB )
00421              {
00422                 if (Esc) break;
00423                 Shift = GetKeyState(VK_SHIFT) & 0x8000 ? SC_PREVWINDOW : SC_NEXTWINDOW;
00424                 if (Shift == SC_NEXTWINDOW)
00425                 {
00426                    selectedWindow = (selectedWindow + 1)%windowCount;
00427                 }
00428                 else
00429                 {
00430                    selectedWindow = selectedWindow - 1;
00431                    if (selectedWindow < 0)
00432                       selectedWindow = windowCount - 1;
00433                 }
00434                 InvalidateRect(switchdialog, NULL, TRUE);
00435              }
00436              else if ( msg.wParam == VK_ESCAPE )
00437              {
00438                 if (!Esc) break;
00439                 if (windowCount < 2)
00440                    goto Exit;
00441                 if (wParam == SC_NEXTWINDOW)
00442                 {
00443                    Count = (Count + 1)%windowCount;
00444                 }
00445                 else
00446                 {
00447                    Count--;
00448                    if (Count < 0)
00449                       Count = windowCount - 1;
00450                 }
00451                 hwnd = windowList[Count];
00452                 GetWindowTextW(hwnd, Text, 1023);
00453                 MakeWindowActive(hwnd);
00454              }
00455           }
00456           break;
00457         }
00458 
00459         case WM_LBUTTONUP:
00460           PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
00461           ProcessMouseMessage(msg.message, msg.lParam);
00462           goto Exit;
00463 
00464         default:
00465           if (PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ))
00466           {
00467              TranslateMessage(&msg);
00468              DispatchMessageW(&msg);
00469           }
00470           break;
00471       }
00472    }
00473 Exit:
00474    if (switchdialog) DestroyWindow(switchdialog);
00475    switchdialog = NULL;
00476    selectedWindow = 0;
00477    windowCount = 0;
00478    return 0;
00479 }
00480 
00481 VOID
00482 DestroyAppWindows()
00483 {
00484    INT i;
00485    for (i=0; i< windowCount; i++)
00486    {
00487       HICON hIcon = iconList[i];
00488       DestroyIcon(hIcon);
00489    }
00490 }
00491 
00492 //
00493 // Switch System Class Window Proc.
00494 //
00495 LRESULT WINAPI SwitchWndProc_common(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL unicode )
00496 {
00497    PWND pWnd;
00498    PALTTABINFO ati;
00499    pWnd = ValidateHwnd(hWnd);
00500    if (pWnd)
00501    {
00502       if (!pWnd->fnid)
00503       {
00504          NtUserSetWindowFNID(hWnd, FNID_SWITCH);
00505       }
00506    }    
00507 
00508    switch (uMsg)
00509    {
00510       case WM_NCCREATE:
00511          if (!(ati = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ati))))
00512             return 0;
00513          SetWindowLongPtrW( hWnd, 0, (LONG_PTR)ati );
00514          return TRUE;
00515 
00516       case WM_SHOWWINDOW:
00517          if (wParam == TRUE)
00518          {
00519             PrepareWindow();
00520             ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0);
00521             ati->cItems = nItems;
00522             ati->cxItem = ati->cyItem = 43;
00523             ati->cRows = nRows;
00524             ati->cColumns = nCols;
00525          }
00526          return 0;
00527 
00528       case WM_MOUSEMOVE:
00529          ProcessMouseMessage(uMsg, lParam);
00530          return 0;
00531 
00532       case WM_ACTIVATE:
00533          if (wParam == WA_INACTIVE)
00534          {
00535             CompleteSwitch(FALSE);
00536          }
00537          return 0;
00538 
00539       case WM_PAINT:
00540          OnPaint(hWnd);
00541          return 0;
00542 
00543       case WM_DESTROY:
00544          isOpen = FALSE;
00545          ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0);
00546          HeapFree( GetProcessHeap(), 0, ati );
00547          SetWindowLongPtrW( hWnd, 0, 0 );
00548          DestroyAppWindows();
00549          NtUserSetWindowFNID(hWnd, FNID_DESTROY);
00550          return 0;
00551    }
00552    return DefWindowProcW(hWnd, uMsg, wParam, lParam);
00553 }
00554 
00555 LRESULT WINAPI SwitchWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00556 {
00557    return SwitchWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
00558 }
00559 
00560 LRESULT WINAPI SwitchWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00561 {
00562    return SwitchWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
00563 }

Generated on Sun May 27 2012 04:38:37 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.