github.com/shurcool/trayhost@v0.0.0-20181020202213-114974ef9e16/platform/windows/tray.c (about)

     1  #include <stdio.h>
     2  #include <windows.h>
     3  #include <shellapi.h>
     4  
     5  #define WM_MYMESSAGE (WM_USER + 1)
     6  
     7  #define MAX_LOADSTRING 100
     8  
     9  HINSTANCE hInst;
    10  HMENU hSubMenu;
    11  TCHAR szTitle[MAX_LOADSTRING];
    12  TCHAR szWindowClass[MAX_LOADSTRING];
    13  wchar_t *titleWide;
    14  NOTIFYICONDATA nid;
    15  
    16  ATOM                MyRegisterClass(HINSTANCE hInstance);
    17  HWND                InitInstance(HINSTANCE, int);
    18  LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
    19  
    20  extern void tray_callback(int itemId);
    21  
    22  void add_separator_item()
    23  {
    24      AppendMenuW(hSubMenu, MF_SEPARATOR, 0, NULL);
    25  }
    26  
    27  void add_menu_item(int id, const char* title, int disabled)
    28  {
    29      UINT uFlags = MF_STRING;
    30      if (disabled == TRUE) {
    31          uFlags |= MF_GRAYED;
    32      }
    33      AppendMenuW(hSubMenu, uFlags, id, (wchar_t*)title);
    34  }
    35  
    36  void clear_menu_items()
    37  {
    38      int count = GetMenuItemCount(hSubMenu);
    39      UINT i = 0;
    40      for (; i < count; i++) {
    41          // always remove at 0 because they shift every time
    42          RemoveMenu(hSubMenu, 0, MF_BYPOSITION);
    43      }
    44  }
    45  
    46  void native_loop()
    47  {
    48      MSG msg;
    49      // Main message loop:
    50      while (GetMessage(&msg, NULL, 0, 0))
    51      {
    52          TranslateMessage(&msg);
    53          DispatchMessage(&msg);
    54      }
    55  }
    56  
    57  int init(const char * title, struct image img) {
    58      HWND hWnd;
    59      HINSTANCE hInstance = GetModuleHandle(NULL);
    60  
    61      // get thish shit into windows whide chars or whatever
    62      titleWide = (wchar_t*)calloc(strlen(title) + 1, sizeof(wchar_t));
    63      mbstowcs(titleWide, title, strlen(title));
    64  
    65      wcscpy((wchar_t*)szTitle, titleWide);
    66      wcscpy((wchar_t*)szWindowClass, (wchar_t*)TEXT("MyClass"));
    67      MyRegisterClass(hInstance);
    68  
    69      hWnd = InitInstance(hInstance, FALSE); // Don't show window
    70      if (!hWnd)
    71      {
    72          return -1;
    73      }
    74  
    75      // Let's load up the tray icon
    76      HICON hIcon;
    77      {
    78          // This is really hacky, but LoadImage won't let me load an image from memory.
    79          // So we have to write out a temporary file, load it from there, then delete the file.
    80  
    81          // From http://msdn.microsoft.com/en-us/library/windows/desktop/aa363875.aspx
    82          TCHAR szTempFileName[MAX_PATH+1];
    83          TCHAR lpTempPathBuffer[MAX_PATH+1];
    84          int dwRetVal = GetTempPath(MAX_PATH+1,        // length of the buffer
    85                                     lpTempPathBuffer); // buffer for path
    86          if (dwRetVal > MAX_PATH+1 || (dwRetVal == 0))
    87          {
    88              return -1; // Failure
    89          }
    90  
    91          //  Generates a temporary file name.
    92          int uRetVal = GetTempFileName(lpTempPathBuffer, // directory for tmp files
    93                                        TEXT("_tmpicon"), // temp file name prefix
    94                                        0,                // create unique name
    95                                        szTempFileName);  // buffer for name
    96          if (uRetVal == 0)
    97          {
    98              return -1; // Failure
    99          }
   100  
   101          // Dump the icon to the temp file
   102          FILE* fIcon = fopen(szTempFileName, "wb");
   103          fwrite(img.bytes, 1, img.length, fIcon);
   104          fclose(fIcon);
   105          fIcon = NULL;
   106  
   107          // Load the image from the file
   108          hIcon = LoadImage(NULL, szTempFileName, IMAGE_ICON, 64, 64, LR_LOADFROMFILE);
   109  
   110          // Delete the temp file
   111          remove(szTempFileName);
   112      }
   113  
   114      nid.cbSize = sizeof(NOTIFYICONDATA);
   115      nid.hWnd = hWnd;
   116      nid.uID = 100;
   117      nid.uCallbackMessage = WM_MYMESSAGE;
   118      nid.hIcon = hIcon;
   119  
   120      strcpy(nid.szTip, title); // MinGW seems to use ANSI
   121      nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
   122  
   123      Shell_NotifyIcon(NIM_ADD, &nid);
   124  
   125      hSubMenu = CreatePopupMenu();
   126      return 0;
   127  }
   128  
   129  void exit_loop() {
   130      Shell_NotifyIcon(NIM_DELETE, &nid);
   131      PostQuitMessage(0);
   132  }
   133  
   134  
   135  ATOM MyRegisterClass(HINSTANCE hInstance)
   136  {
   137      WNDCLASSEX wcex;
   138  
   139      wcex.cbSize = sizeof(WNDCLASSEX);
   140  
   141      wcex.style          = CS_HREDRAW | CS_VREDRAW;
   142      wcex.lpfnWndProc    = WndProc;
   143      wcex.cbClsExtra     = 0;
   144      wcex.cbWndExtra     = 0;
   145      wcex.hInstance      = hInstance;
   146      wcex.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
   147      wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
   148      wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
   149      wcex.lpszMenuName   = 0;
   150      wcex.lpszClassName  = szWindowClass;
   151      wcex.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);
   152  
   153      return RegisterClassEx(&wcex);
   154  }
   155  
   156  HWND InitInstance(HINSTANCE hInstance, int nCmdShow)
   157  {
   158      HWND hWnd;
   159  
   160      hInst = hInstance;
   161  
   162      hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
   163                          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
   164      // hWnd = CreateWindowW(L"Krneki", L"Title", WS_OVERLAPPEDWINDOW,
   165      //                     CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
   166  
   167      if (!hWnd)
   168      {
   169          return 0;
   170      }
   171  
   172      ShowWindow(hWnd, nCmdShow);
   173      UpdateWindow(hWnd);
   174  
   175      return hWnd;
   176  }
   177  
   178  void ShowMenu(HWND hWnd)
   179  {
   180      POINT p;
   181      GetCursorPos(&p);
   182      SetForegroundWindow(hWnd); // Win32 bug work-around
   183      TrackPopupMenu(hSubMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, p.x, p.y, 0, hWnd, NULL);
   184  }
   185  
   186  LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
   187  {
   188      switch (message)
   189      {
   190          case WM_COMMAND:
   191              tray_callback(LOWORD(wParam));
   192              break;
   193          case WM_DESTROY:
   194              exit_loop();
   195              break;
   196          case WM_MYMESSAGE:
   197              switch(lParam)
   198              {
   199                  case WM_RBUTTONUP:
   200                      ShowMenu(hWnd);
   201                      break;
   202                  case WM_LBUTTONUP:
   203                      tray_callback(-1);
   204                      break;
   205                  default:
   206                      return DefWindowProc(hWnd, message, wParam, lParam);
   207              };
   208              break;
   209          default:
   210              return DefWindowProc(hWnd, message, wParam, lParam);
   211      }
   212      return 0;
   213  }
   214  
   215  void set_clipboard_string(const char * string) {
   216      // TODO: Implement.
   217  }
   218  
   219  struct clipboard_content get_clipboard_content() {
   220      // TODO: Implement.
   221      struct clipboard_content cc;
   222      return cc;
   223  }
   224  
   225  void display_notification(int notificationId, const char * title, const char * body, struct image img, double timeout) {
   226      // TODO: Implement.
   227  }