diff options
| author | Eli Zaretskii | 2015-11-11 18:29:36 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2015-11-11 18:29:36 +0200 |
| commit | 9d43941569fc3840fa9306d149461a8439a54d68 (patch) | |
| tree | eb92562206e85b6c5cb6ebe0f54c06544580df89 /src | |
| parent | ef75c3b56b8ff034eb47e0c69328227127cc93fa (diff) | |
| download | emacs-9d43941569fc3840fa9306d149461a8439a54d68.tar.gz emacs-9d43941569fc3840fa9306d149461a8439a54d68.zip | |
Implement tray notifications for MS-Windows
* src/w32fns.c (MY_NOTIFYICONDATAW): New typedef.
(NOTIFYICONDATAW_V1_SIZE, NOTIFYICONDATAW_V2_SIZE)
(NOTIFYICONDATAW_V3_SIZE, NIF_INFO, NIIF_NONE, NIIF_INFO)
(NIIF_WARNING, NIIF_ERROR, EMACS_TRAY_NOTIFICATION_ID)
(EMACS_NOTIFICATION_MSG): New macros.
(NI_Severity): New enumeration.
(get_dll_version, utf8_mbslen_lim, add_tray_notification)
(delete_tray_notification, Fw32_notification_notify)
(Fw32_notification_close): New functions.
(syms_of_w32fns): Defsubr functions exposed to Lisp. DEFSYM
keywords used by w32-notification-notify.
* doc/lispref/os.texi (Desktop Notifications): Describe the native
w32 tray notifications.
Diffstat (limited to 'src')
| -rw-r--r-- | src/w32fns.c | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/src/w32fns.c b/src/w32fns.c index d92352a9802..eed849f1034 100644 --- a/src/w32fns.c +++ b/src/w32fns.c | |||
| @@ -55,6 +55,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 55 | #include <commctrl.h> | 55 | #include <commctrl.h> |
| 56 | #include <commdlg.h> | 56 | #include <commdlg.h> |
| 57 | #include <shellapi.h> | 57 | #include <shellapi.h> |
| 58 | #include <shlwapi.h> | ||
| 58 | #include <ctype.h> | 59 | #include <ctype.h> |
| 59 | #include <winspool.h> | 60 | #include <winspool.h> |
| 60 | #include <objbase.h> | 61 | #include <objbase.h> |
| @@ -8755,6 +8756,473 @@ Internal use only. */) | |||
| 8755 | return menubar_in_use ? Qt : Qnil; | 8756 | return menubar_in_use ? Qt : Qnil; |
| 8756 | } | 8757 | } |
| 8757 | 8758 | ||
| 8759 | /*********************************************************************** | ||
| 8760 | Tray notifications | ||
| 8761 | ***********************************************************************/ | ||
| 8762 | /* A private struct declaration to avoid compile-time limits. */ | ||
| 8763 | typedef struct MY_NOTIFYICONDATAW { | ||
| 8764 | DWORD cbSize; | ||
| 8765 | HWND hWnd; | ||
| 8766 | UINT uID; | ||
| 8767 | UINT uFlags; | ||
| 8768 | UINT uCallbackMessage; | ||
| 8769 | HICON hIcon; | ||
| 8770 | WCHAR szTip[128]; | ||
| 8771 | DWORD dwState; | ||
| 8772 | DWORD dwStateMask; | ||
| 8773 | WCHAR szInfo[256]; | ||
| 8774 | _ANONYMOUS_UNION union { | ||
| 8775 | UINT uTimeout; | ||
| 8776 | UINT uVersion; | ||
| 8777 | } DUMMYUNIONNAME; | ||
| 8778 | WCHAR szInfoTitle[64]; | ||
| 8779 | DWORD dwInfoFlags; | ||
| 8780 | GUID guidItem; | ||
| 8781 | HICON hBalloonIcon; | ||
| 8782 | } MY_NOTIFYICONDATAW; | ||
| 8783 | |||
| 8784 | #ifndef NOTIFYICONDATAW_V1_SIZE | ||
| 8785 | # define NOTIFYICONDATAW_V1_SIZE offsetof (MY_NOTIFYICONDATAW, szTip[64]) | ||
| 8786 | #endif | ||
| 8787 | #ifndef NOTIFYICONDATAW_V2_SIZE | ||
| 8788 | # define NOTIFYICONDATAW_V2_SIZE offsetof (MY_NOTIFYICONDATAW, guidItem) | ||
| 8789 | #endif | ||
| 8790 | #ifndef NOTIFYICONDATAW_V3_SIZE | ||
| 8791 | # define NOTIFYICONDATAW_V3_SIZE offsetof (MY_NOTIFYICONDATAW, hBalloonIcon) | ||
| 8792 | #endif | ||
| 8793 | #ifndef NIF_INFO | ||
| 8794 | # define NIF_INFO 0x00000010 | ||
| 8795 | #endif | ||
| 8796 | #ifndef NIIF_NONE | ||
| 8797 | # define NIIF_NONE 0x00000000 | ||
| 8798 | #endif | ||
| 8799 | #ifndef NIIF_INFO | ||
| 8800 | # define NIIF_INFO 0x00000001 | ||
| 8801 | #endif | ||
| 8802 | #ifndef NIIF_WARNING | ||
| 8803 | # define NIIF_WARNING 0x00000002 | ||
| 8804 | #endif | ||
| 8805 | #ifndef NIIF_ERROR | ||
| 8806 | # define NIIF_ERROR 0x00000003 | ||
| 8807 | #endif | ||
| 8808 | |||
| 8809 | |||
| 8810 | #define EMACS_TRAY_NOTIFICATION_ID 42 /* arbitrary */ | ||
| 8811 | #define EMACS_NOTIFICATION_MSG (WM_APP + 1) | ||
| 8812 | |||
| 8813 | enum NI_Severity { | ||
| 8814 | Ni_None, | ||
| 8815 | Ni_Info, | ||
| 8816 | Ni_Warn, | ||
| 8817 | Ni_Err | ||
| 8818 | }; | ||
| 8819 | |||
| 8820 | /* Report the version of a DLL given by its name. The return value is | ||
| 8821 | constructed using MAKEDLLVERULL. */ | ||
| 8822 | static ULONGLONG | ||
| 8823 | get_dll_version (const char *dll_name) | ||
| 8824 | { | ||
| 8825 | ULONGLONG version = 0; | ||
| 8826 | HINSTANCE hdll = LoadLibrary (dll_name); | ||
| 8827 | |||
| 8828 | if (hdll) | ||
| 8829 | { | ||
| 8830 | DLLGETVERSIONPROC pDllGetVersion | ||
| 8831 | = (DLLGETVERSIONPROC) GetProcAddress (hdll, "DllGetVersion"); | ||
| 8832 | |||
| 8833 | if (pDllGetVersion) | ||
| 8834 | { | ||
| 8835 | DLLVERSIONINFO dvi; | ||
| 8836 | HRESULT result; | ||
| 8837 | |||
| 8838 | memset (&dvi, 0, sizeof(dvi)); | ||
| 8839 | dvi.cbSize = sizeof(dvi); | ||
| 8840 | result = pDllGetVersion (&dvi); | ||
| 8841 | if (SUCCEEDED (result)) | ||
| 8842 | version = MAKEDLLVERULL (dvi.dwMajorVersion, dvi.dwMinorVersion, | ||
| 8843 | 0, 0); | ||
| 8844 | } | ||
| 8845 | FreeLibrary (hdll); | ||
| 8846 | } | ||
| 8847 | |||
| 8848 | return version; | ||
| 8849 | } | ||
| 8850 | |||
| 8851 | /* Return the number of bytes in UTF-8 encoded string STR that | ||
| 8852 | corresponds to at most LIM characters. If STR ends before LIM | ||
| 8853 | characters, return the number of bytes in STR including the | ||
| 8854 | terminating null byte. */ | ||
| 8855 | static int | ||
| 8856 | utf8_mbslen_lim (const char *str, int lim) | ||
| 8857 | { | ||
| 8858 | const char *p = str; | ||
| 8859 | int mblen = 0, nchars = 0; | ||
| 8860 | |||
| 8861 | while (*p && nchars < lim) | ||
| 8862 | { | ||
| 8863 | int nbytes = CHAR_BYTES (*p); | ||
| 8864 | |||
| 8865 | mblen += nbytes; | ||
| 8866 | nchars++; | ||
| 8867 | p += nbytes; | ||
| 8868 | } | ||
| 8869 | |||
| 8870 | if (!*p && nchars < lim) | ||
| 8871 | mblen++; | ||
| 8872 | |||
| 8873 | return mblen; | ||
| 8874 | } | ||
| 8875 | |||
| 8876 | /* Low-level subroutine to show tray notifications. All strings are | ||
| 8877 | supposed to be unibyte UTF-8 encoded by the caller. */ | ||
| 8878 | static EMACS_INT | ||
| 8879 | add_tray_notification (struct frame *f, const char *icon, const char *tip, | ||
| 8880 | enum NI_Severity severity, unsigned timeout, | ||
| 8881 | const char *title, const char *msg) | ||
| 8882 | { | ||
| 8883 | EMACS_INT retval = EMACS_TRAY_NOTIFICATION_ID; | ||
| 8884 | |||
| 8885 | if (FRAME_W32_P (f)) | ||
| 8886 | { | ||
| 8887 | MY_NOTIFYICONDATAW nidw; | ||
| 8888 | ULONGLONG shell_dll_version = get_dll_version ("Shell32.dll"); | ||
| 8889 | wchar_t tipw[128], msgw[256], titlew[64]; | ||
| 8890 | int tiplen; | ||
| 8891 | |||
| 8892 | memset (&nidw, 0, sizeof(nidw)); | ||
| 8893 | |||
| 8894 | /* MSDN says the full struct is supported since Vista, whose | ||
| 8895 | Shell32.dll version is said to be 6.0.6. But DllGetVersion | ||
| 8896 | cannot report the 3rd field value, it reports "build number" | ||
| 8897 | instead, which is something else. So we use the Windows 7's | ||
| 8898 | version 6.1 as cutoff, and Vista loses. (Actually, the loss | ||
| 8899 | is not a real one, since we don't expose the hBalloonIcon | ||
| 8900 | member of the struct to Lisp.) */ | ||
| 8901 | if (shell_dll_version >= MAKEDLLVERULL (6, 1, 0, 0)) /* >= Windows 7 */ | ||
| 8902 | nidw.cbSize = sizeof (nidw); | ||
| 8903 | else if (shell_dll_version >= MAKEDLLVERULL (6, 0, 0, 0)) /* XP */ | ||
| 8904 | nidw.cbSize = NOTIFYICONDATAW_V3_SIZE; | ||
| 8905 | else if (shell_dll_version >= MAKEDLLVERULL (5, 0, 0, 0)) /* W2K */ | ||
| 8906 | nidw.cbSize = NOTIFYICONDATAW_V2_SIZE; | ||
| 8907 | else | ||
| 8908 | nidw.cbSize = NOTIFYICONDATAW_V1_SIZE; /* < W2K */ | ||
| 8909 | nidw.hWnd = FRAME_W32_WINDOW (f); | ||
| 8910 | nidw.uID = EMACS_TRAY_NOTIFICATION_ID; | ||
| 8911 | nidw.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO; | ||
| 8912 | nidw.uCallbackMessage = EMACS_NOTIFICATION_MSG; | ||
| 8913 | if (!*icon) | ||
| 8914 | nidw.hIcon = LoadIcon (hinst, EMACS_CLASS); | ||
| 8915 | else | ||
| 8916 | { | ||
| 8917 | if (w32_unicode_filenames) | ||
| 8918 | { | ||
| 8919 | wchar_t icon_w[MAX_PATH]; | ||
| 8920 | |||
| 8921 | if (filename_to_utf16 (icon, icon_w) != 0) | ||
| 8922 | { | ||
| 8923 | errno = ENOENT; | ||
| 8924 | return -1; | ||
| 8925 | } | ||
| 8926 | nidw.hIcon = LoadImageW (NULL, icon_w, IMAGE_ICON, 0, 0, | ||
| 8927 | LR_DEFAULTSIZE | LR_LOADFROMFILE); | ||
| 8928 | } | ||
| 8929 | else | ||
| 8930 | { | ||
| 8931 | char icon_a[MAX_PATH]; | ||
| 8932 | |||
| 8933 | if (filename_to_ansi (icon, icon_a) != 0) | ||
| 8934 | { | ||
| 8935 | errno = ENOENT; | ||
| 8936 | return -1; | ||
| 8937 | } | ||
| 8938 | nidw.hIcon = LoadImageA (NULL, icon_a, IMAGE_ICON, 0, 0, | ||
| 8939 | LR_DEFAULTSIZE | LR_LOADFROMFILE); | ||
| 8940 | } | ||
| 8941 | } | ||
| 8942 | if (!nidw.hIcon) | ||
| 8943 | { | ||
| 8944 | switch (GetLastError ()) | ||
| 8945 | { | ||
| 8946 | case ERROR_FILE_NOT_FOUND: | ||
| 8947 | errno = ENOENT; | ||
| 8948 | break; | ||
| 8949 | default: | ||
| 8950 | errno = ENOMEM; | ||
| 8951 | break; | ||
| 8952 | } | ||
| 8953 | return -1; | ||
| 8954 | } | ||
| 8955 | |||
| 8956 | /* Windows 9X and NT4 support only 64 characters in the Tip, | ||
| 8957 | later versions support up to 128. */ | ||
| 8958 | if (nidw.cbSize == NOTIFYICONDATAW_V1_SIZE) | ||
| 8959 | { | ||
| 8960 | tiplen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, | ||
| 8961 | tip, utf8_mbslen_lim (tip, 63), | ||
| 8962 | tipw, 64); | ||
| 8963 | if (tiplen >= 63) | ||
| 8964 | tipw[63] = 0; | ||
| 8965 | } | ||
| 8966 | else | ||
| 8967 | { | ||
| 8968 | tiplen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, | ||
| 8969 | tip, utf8_mbslen_lim (tip, 127), | ||
| 8970 | tipw, 128); | ||
| 8971 | if (tiplen >= 127) | ||
| 8972 | tipw[127] = 0; | ||
| 8973 | } | ||
| 8974 | if (tiplen == 0) | ||
| 8975 | { | ||
| 8976 | errno = EINVAL; | ||
| 8977 | retval = -1; | ||
| 8978 | goto done; | ||
| 8979 | } | ||
| 8980 | wcscpy (nidw.szTip, tipw); | ||
| 8981 | |||
| 8982 | /* The rest of the structure is only supported since Windows 2000. */ | ||
| 8983 | if (nidw.cbSize > NOTIFYICONDATAW_V1_SIZE) | ||
| 8984 | { | ||
| 8985 | int slen; | ||
| 8986 | |||
| 8987 | slen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, | ||
| 8988 | msg, utf8_mbslen_lim (msg, 255), | ||
| 8989 | msgw, 256); | ||
| 8990 | if (slen >= 255) | ||
| 8991 | msgw[255] = 0; | ||
| 8992 | else if (slen == 0) | ||
| 8993 | { | ||
| 8994 | errno = EINVAL; | ||
| 8995 | retval = -1; | ||
| 8996 | goto done; | ||
| 8997 | } | ||
| 8998 | wcscpy (nidw.szInfo, msgw); | ||
| 8999 | nidw.uTimeout = timeout; | ||
| 9000 | slen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, | ||
| 9001 | title, utf8_mbslen_lim (title, 63), | ||
| 9002 | titlew, 64); | ||
| 9003 | if (slen >= 63) | ||
| 9004 | titlew[63] = 0; | ||
| 9005 | else if (slen == 0) | ||
| 9006 | { | ||
| 9007 | errno = EINVAL; | ||
| 9008 | retval = -1; | ||
| 9009 | goto done; | ||
| 9010 | } | ||
| 9011 | wcscpy (nidw.szInfoTitle, titlew); | ||
| 9012 | |||
| 9013 | switch (severity) | ||
| 9014 | { | ||
| 9015 | case Ni_None: | ||
| 9016 | nidw.dwInfoFlags = NIIF_NONE; | ||
| 9017 | break; | ||
| 9018 | case Ni_Info: | ||
| 9019 | default: | ||
| 9020 | nidw.dwInfoFlags = NIIF_INFO; | ||
| 9021 | break; | ||
| 9022 | case Ni_Warn: | ||
| 9023 | nidw.dwInfoFlags = NIIF_WARNING; | ||
| 9024 | break; | ||
| 9025 | case Ni_Err: | ||
| 9026 | nidw.dwInfoFlags = NIIF_ERROR; | ||
| 9027 | break; | ||
| 9028 | } | ||
| 9029 | } | ||
| 9030 | |||
| 9031 | if (!Shell_NotifyIconW (NIM_ADD, (PNOTIFYICONDATAW)&nidw)) | ||
| 9032 | { | ||
| 9033 | /* GetLastError returns meaningless results when | ||
| 9034 | Shell_NotifyIcon fails. */ | ||
| 9035 | DebPrint (("Shell_NotifyIcon ADD failed (err=%d)\n", | ||
| 9036 | GetLastError ())); | ||
| 9037 | errno = EINVAL; | ||
| 9038 | retval = -1; | ||
| 9039 | } | ||
| 9040 | done: | ||
| 9041 | if (*icon && !DestroyIcon (nidw.hIcon)) | ||
| 9042 | DebPrint (("DestroyIcon failed (err=%d)\n", GetLastError ())); | ||
| 9043 | } | ||
| 9044 | return retval; | ||
| 9045 | } | ||
| 9046 | |||
| 9047 | /* Low-level subroutine to remove a tray notification. Note: we only | ||
| 9048 | pass the minimum data about the notification: its ID and the handle | ||
| 9049 | of the window to which it sends messages. MSDN doesn't say this is | ||
| 9050 | enough, but it works in practice. This allows us to avoid keeping | ||
| 9051 | the notification data around after we show the notification. */ | ||
| 9052 | static void | ||
| 9053 | delete_tray_notification (struct frame *f, int id) | ||
| 9054 | { | ||
| 9055 | if (FRAME_W32_P (f)) | ||
| 9056 | { | ||
| 9057 | MY_NOTIFYICONDATAW nidw; | ||
| 9058 | |||
| 9059 | memset (&nidw, 0, sizeof(nidw)); | ||
| 9060 | nidw.hWnd = FRAME_W32_WINDOW (f); | ||
| 9061 | nidw.uID = id; | ||
| 9062 | |||
| 9063 | if (!Shell_NotifyIconW (NIM_DELETE, (PNOTIFYICONDATAW)&nidw)) | ||
| 9064 | { | ||
| 9065 | /* GetLastError returns meaningless results when | ||
| 9066 | Shell_NotifyIcon fails. */ | ||
| 9067 | DebPrint (("Shell_NotifyIcon DELETE failed\n")); | ||
| 9068 | errno = EINVAL; | ||
| 9069 | return; | ||
| 9070 | } | ||
| 9071 | } | ||
| 9072 | return; | ||
| 9073 | } | ||
| 9074 | |||
| 9075 | DEFUN ("w32-notification-notify", | ||
| 9076 | Fw32_notification_notify, Sw32_notification_notify, | ||
| 9077 | 0, MANY, 0, | ||
| 9078 | doc: /* Display an MS-Windows tray notification as specified by PARAMS. | ||
| 9079 | |||
| 9080 | Value is the integer unique ID of the notification that can be used | ||
| 9081 | to remove the notification using `w32-notification-close', which see. | ||
| 9082 | If the function fails, the return value is nil. | ||
| 9083 | |||
| 9084 | Tray notifications, a.k.a. \"taskbar messages\", are messages that | ||
| 9085 | inform the user about events unrelated to the current user activity, | ||
| 9086 | such as a significant system event, by briefly displaying informative | ||
| 9087 | text in a balloon from an icon in the notification area of the taskbar. | ||
| 9088 | |||
| 9089 | Parameters in PARAMS are specified as keyword/value pairs. All the | ||
| 9090 | parameters are optional, but if no parameters are specified, the | ||
| 9091 | function will do nothing and return nil. | ||
| 9092 | |||
| 9093 | The following parameters are supported: | ||
| 9094 | |||
| 9095 | :icon ICON -- Display ICON in the system tray. If ICON is a string, | ||
| 9096 | it should specify a file name from which to load the | ||
| 9097 | icon; the specified file should be a .ico Windows icon | ||
| 9098 | file. If ICON is not a string, or if this parameter | ||
| 9099 | is not specified, the standard Emacs icon will be used. | ||
| 9100 | |||
| 9101 | :tip TIP -- Use TIP as the tooltip for the notification. If TIP | ||
| 9102 | is a string, this is the text of a tooltip that will | ||
| 9103 | be shown when the mouse pointer hovers over the tray | ||
| 9104 | icon added by the notification. If TIP is not a | ||
| 9105 | string, or if this parameter is not specified, the | ||
| 9106 | default tooltip text is \"Emacs notification\". The | ||
| 9107 | tooltip text can be up to 127 characters long (63 | ||
| 9108 | on Windows versions before W2K). Longer strings | ||
| 9109 | will be truncated. | ||
| 9110 | |||
| 9111 | :level LEVEL -- Notification severity level, one of `info', | ||
| 9112 | `warning', or `error'. If given, the value | ||
| 9113 | determines the icon displayed to the left of the | ||
| 9114 | notification title, but only if the `:title' | ||
| 9115 | parameter (see below) is also specified and is a | ||
| 9116 | string. | ||
| 9117 | |||
| 9118 | :timeout TIMEOUT -- TIMEOUT is the time in seconds after which the | ||
| 9119 | notification disappears. The value can be integer | ||
| 9120 | or floating-point. This is ignored on Vista and | ||
| 9121 | later systems, where the duration is fixed at 9 sec | ||
| 9122 | and can only be customized via system-wide | ||
| 9123 | Accessibility settings. | ||
| 9124 | |||
| 9125 | :title TITLE -- The title of the notification. If TITLE is a string, | ||
| 9126 | it is displayed in a larger font immediately above | ||
| 9127 | the body text. The title text can be up to 63 | ||
| 9128 | characters long; longer text will be truncated. | ||
| 9129 | |||
| 9130 | :body BODY -- The body of the notification. If BODY is a string, | ||
| 9131 | it specifies the text of the notification message. | ||
| 9132 | Use embedded newlines to control how the text is | ||
| 9133 | broken into lines. The body text can be up to 255 | ||
| 9134 | characters long, and will be truncated if it's longer. | ||
| 9135 | |||
| 9136 | Note that versions of Windows before W2K support only `:icon' and `:tip'. | ||
| 9137 | You can pass the other parameters, but they will be ignored on those | ||
| 9138 | old systems. | ||
| 9139 | |||
| 9140 | There can be at most one active notification at any given time. An | ||
| 9141 | active notification must be removed by calling `w32-notification-close' | ||
| 9142 | before a new one can be shown. | ||
| 9143 | |||
| 9144 | usage: (w32-notification-notify &rest PARAMS) */) | ||
| 9145 | (ptrdiff_t nargs, Lisp_Object *args) | ||
| 9146 | { | ||
| 9147 | struct frame *f = SELECTED_FRAME (); | ||
| 9148 | Lisp_Object arg_plist, lres; | ||
| 9149 | EMACS_INT retval; | ||
| 9150 | char *icon, *tip, *title, *msg; | ||
| 9151 | enum NI_Severity severity; | ||
| 9152 | unsigned timeout; | ||
| 9153 | |||
| 9154 | if (nargs == 0) | ||
| 9155 | return Qnil; | ||
| 9156 | |||
| 9157 | arg_plist = Flist (nargs, args); | ||
| 9158 | |||
| 9159 | /* Icon. */ | ||
| 9160 | lres = Fplist_get (arg_plist, QCicon); | ||
| 9161 | if (STRINGP (lres)) | ||
| 9162 | icon = SSDATA (ENCODE_FILE (Fexpand_file_name (lres, Qnil))); | ||
| 9163 | else | ||
| 9164 | icon = ""; | ||
| 9165 | |||
| 9166 | /* Tip. */ | ||
| 9167 | lres = Fplist_get (arg_plist, QCtip); | ||
| 9168 | if (STRINGP (lres)) | ||
| 9169 | tip = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1)); | ||
| 9170 | else | ||
| 9171 | tip = "Emacs notification"; | ||
| 9172 | |||
| 9173 | /* Severity. */ | ||
| 9174 | lres = Fplist_get (arg_plist, QClevel); | ||
| 9175 | if (NILP (lres)) | ||
| 9176 | severity = Ni_None; | ||
| 9177 | else if (EQ (lres, Qinfo)) | ||
| 9178 | severity = Ni_Info; | ||
| 9179 | else if (EQ (lres, Qwarning)) | ||
| 9180 | severity = Ni_Warn; | ||
| 9181 | else if (EQ (lres, Qerror)) | ||
| 9182 | severity = Ni_Err; | ||
| 9183 | else | ||
| 9184 | severity = Ni_Info; | ||
| 9185 | |||
| 9186 | /* Timeout. */ | ||
| 9187 | lres = Fplist_get (arg_plist, QCtimeout); | ||
| 9188 | if (NUMBERP (lres)) | ||
| 9189 | timeout = 1000 * (INTEGERP (lres) ? XINT (lres) : XFLOAT_DATA (lres)); | ||
| 9190 | else | ||
| 9191 | timeout = 0; | ||
| 9192 | |||
| 9193 | /* Title. */ | ||
| 9194 | lres = Fplist_get (arg_plist, QCtitle); | ||
| 9195 | if (STRINGP (lres)) | ||
| 9196 | title = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1)); | ||
| 9197 | else | ||
| 9198 | title = ""; | ||
| 9199 | |||
| 9200 | /* Notification body text. */ | ||
| 9201 | lres = Fplist_get (arg_plist, QCbody); | ||
| 9202 | if (STRINGP (lres)) | ||
| 9203 | msg = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1)); | ||
| 9204 | else | ||
| 9205 | msg = ""; | ||
| 9206 | |||
| 9207 | /* Do it! */ | ||
| 9208 | retval = add_tray_notification (f, icon, tip, severity, timeout, title, msg); | ||
| 9209 | return (retval < 0 ? Qnil : make_number (retval)); | ||
| 9210 | } | ||
| 9211 | |||
| 9212 | DEFUN ("w32-notification-close", | ||
| 9213 | Fw32_notification_close, Sw32_notification_close, | ||
| 9214 | 1, 1, 0, | ||
| 9215 | doc: /* Remove the MS-Windows tray notification specified by its ID. */) | ||
| 9216 | (Lisp_Object id) | ||
| 9217 | { | ||
| 9218 | struct frame *f = SELECTED_FRAME (); | ||
| 9219 | |||
| 9220 | if (INTEGERP (id)) | ||
| 9221 | delete_tray_notification (f, XINT (id)); | ||
| 9222 | |||
| 9223 | return Qnil; | ||
| 9224 | } | ||
| 9225 | |||
| 8758 | 9226 | ||
| 8759 | /*********************************************************************** | 9227 | /*********************************************************************** |
| 8760 | Initialization | 9228 | Initialization |
| @@ -8828,6 +9296,14 @@ syms_of_w32fns (void) | |||
| 8828 | DEFSYM (Qframes, "frames"); | 9296 | DEFSYM (Qframes, "frames"); |
| 8829 | DEFSYM (Qtip_frame, "tip-frame"); | 9297 | DEFSYM (Qtip_frame, "tip-frame"); |
| 8830 | DEFSYM (Qunicode_sip, "unicode-sip"); | 9298 | DEFSYM (Qunicode_sip, "unicode-sip"); |
| 9299 | DEFSYM (QCicon, ":icon"); | ||
| 9300 | DEFSYM (QCtip, ":tip"); | ||
| 9301 | DEFSYM (QClevel, ":level"); | ||
| 9302 | DEFSYM (Qinfo, "info"); | ||
| 9303 | DEFSYM (Qwarning, "warning"); | ||
| 9304 | DEFSYM (QCtimeout, ":timeout"); | ||
| 9305 | DEFSYM (QCtitle, ":title"); | ||
| 9306 | DEFSYM (QCbody, ":body"); | ||
| 8831 | 9307 | ||
| 8832 | /* Symbols used elsewhere, but only in MS-Windows-specific code. */ | 9308 | /* Symbols used elsewhere, but only in MS-Windows-specific code. */ |
| 8833 | DEFSYM (Qgnutls_dll, "gnutls"); | 9309 | DEFSYM (Qgnutls_dll, "gnutls"); |
| @@ -9161,6 +9637,8 @@ This variable has effect only on Windows Vista and later. */); | |||
| 9161 | defsubr (&Sw32_window_exists_p); | 9637 | defsubr (&Sw32_window_exists_p); |
| 9162 | defsubr (&Sw32_battery_status); | 9638 | defsubr (&Sw32_battery_status); |
| 9163 | defsubr (&Sw32__menu_bar_in_use); | 9639 | defsubr (&Sw32__menu_bar_in_use); |
| 9640 | defsubr (&Sw32_notification_notify); | ||
| 9641 | defsubr (&Sw32_notification_close); | ||
| 9164 | 9642 | ||
| 9165 | #ifdef WINDOWSNT | 9643 | #ifdef WINDOWSNT |
| 9166 | defsubr (&Sfile_system_info); | 9644 | defsubr (&Sfile_system_info); |