diff options
Diffstat (limited to 'plugins/Alarms/src')
| -rw-r--r-- | plugins/Alarms/src/Version.h | 20 | ||||
| -rw-r--r-- | plugins/Alarms/src/alarm_win.cpp | 431 | ||||
| -rw-r--r-- | plugins/Alarms/src/alarm_win.h | 22 | ||||
| -rw-r--r-- | plugins/Alarms/src/alarmlist.cpp | 784 | ||||
| -rw-r--r-- | plugins/Alarms/src/alarmlist.h | 148 | ||||
| -rw-r--r-- | plugins/Alarms/src/alarms.cpp | 326 | ||||
| -rw-r--r-- | plugins/Alarms/src/alarms.h | 11 | ||||
| -rw-r--r-- | plugins/Alarms/src/common.h | 71 | ||||
| -rw-r--r-- | plugins/Alarms/src/frame.cpp | 667 | ||||
| -rw-r--r-- | plugins/Alarms/src/frame.h | 20 | ||||
| -rw-r--r-- | plugins/Alarms/src/icons.cpp | 71 | ||||
| -rw-r--r-- | plugins/Alarms/src/icons.h | 11 | ||||
| -rw-r--r-- | plugins/Alarms/src/options.cpp | 1217 | ||||
| -rw-r--r-- | plugins/Alarms/src/options.h | 41 | ||||
| -rw-r--r-- | plugins/Alarms/src/resource.h | 91 | ||||
| -rw-r--r-- | plugins/Alarms/src/time_utils.cpp | 25 | ||||
| -rw-r--r-- | plugins/Alarms/src/time_utils.h | 7 | ||||
| -rw-r--r-- | plugins/Alarms/src/trigger.cpp | 106 | ||||
| -rw-r--r-- | plugins/Alarms/src/trigger.h | 11 | 
19 files changed, 4080 insertions, 0 deletions
diff --git a/plugins/Alarms/src/Version.h b/plugins/Alarms/src/Version.h new file mode 100644 index 0000000000..a57e674b6d --- /dev/null +++ b/plugins/Alarms/src/Version.h @@ -0,0 +1,20 @@ +#define __MAJOR_VERSION				0
 +#define __MINOR_VERSION				4
 +#define __RELEASE_NUM				0
 +#define __BUILD_NUM					5
 +
 +#define __FILEVERSION_STRING		__MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM
 +#define __FILEVERSION_DOTS			__MAJOR_VERSION.__MINOR_VERSION.__RELEASE_NUM.__BUILD_NUM
 +
 +#define __STRINGIFY_IMPL(x)			#x
 +#define __STRINGIFY(x)				__STRINGIFY_IMPL(x)
 +#define __VERSION_STRING			__STRINGIFY(__FILEVERSION_DOTS)
 +
 +#define __PLUGIN_NAME				"Alarms"
 +#define __INTERNAL_NAME				"Alarms"
 +#define __FILENAME					"Alarms.dll"
 +#define __DESCRIPTION 				"Set once-off, daily, weekly and weekday alarms."
 +#define __AUTHOR					"Scott Ellis"
 +#define __AUTHOREMAIL				"mail@scottellis.com.au"
 +#define __AUTHORWEB					"http://www.scottellis.com.au"
 +#define __COPYRIGHT					"© 2005 Scott Ellis"
 diff --git a/plugins/Alarms/src/alarm_win.cpp b/plugins/Alarms/src/alarm_win.cpp new file mode 100644 index 0000000000..11a29e42b5 --- /dev/null +++ b/plugins/Alarms/src/alarm_win.cpp @@ -0,0 +1,431 @@ +#include "common.h"
 +#include "alarm_win.h"
 +
 +#define ID_TIMER_SOUND				10101
 +#define SOUND_REPEAT_PERIOD			5000	// milliseconds
 +#define SPEACH_REPEAT_PERIOD		15000	// milliseconds
 +HANDLE hAlarmWindowList = 0;
 +
 +HMODULE hUserDll;
 +BOOL (WINAPI *MySetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD) = 0;
 +BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags) = 0;
 +
 +FontID title_font_id, window_font_id;
 +ColourID bk_colour_id;
 +HFONT hTitleFont = 0, hWindowFont = 0;
 +COLORREF title_font_colour, window_font_colour;
 +HBRUSH hBackgroundBrush = 0;
 +
 +#define WMU_SETFONTS		(WM_USER + 61)
 +#define WMU_REFRESH			(WM_USER + 62)
 +#define WMU_ADDSNOOZER		(WM_USER + 63)
 +
 +int win_num = 0;
 +typedef struct WindowData_tag {
 +	ALARM *alarm;
 +	POINT p;
 +	bool moving;
 +	int win_num;
 +} WindowData;
 +
 +void SetAlarmWinOptions() {
 +	WindowList_Broadcast(hAlarmWindowList, WMU_SETOPT, IDC_SNOOZE, 0);
 +}
 +
 +bool TransparencyEnabled() {
 +	return MySetLayeredWindowAttributes != 0;
 +}
 +
 +INT_PTR CALLBACK DlgProcAlarm(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	switch ( msg ) {
 +	case WM_INITDIALOG: 
 +		TranslateDialogDefault( hwndDlg );
 +		{
 +			Utils_RestoreWindowPositionNoSize(hwndDlg, 0, MODULE, "Notify");
 +			SetFocus(GetDlgItem(hwndDlg, IDC_SNOOZE));
 +
 +			WindowData *wd = new WindowData;
 +			wd->moving = false;
 +			wd->alarm = 0;
 +			wd->win_num = win_num++;
 +
 +			if (wd->win_num > 0) {
 +				RECT r;
 +				GetWindowRect(hwndDlg, &r);
 +				r.top += 20;
 +				r.left += 20;
 +
 +				SetWindowPos(hwndDlg, 0, r.left, r.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
 +				Utils_SaveWindowPosition(hwndDlg, 0, MODULE, "Notify");
 +			}
 +
 +			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG)wd);
 +
 +			// options
 +			SendMessage(hwndDlg, WMU_SETOPT, 0, 0);
 +		
 +			// fonts
 +			SendMessage(hwndDlg, WMU_SETFONTS, 0, 0);
 +		}
 +		return FALSE;
 +
 +	case WMU_REFRESH:
 +		InvalidateRect(hwndDlg, 0, TRUE);
 +		return TRUE;
 +
 +	case WM_CTLCOLORSTATIC:
 +		{
 +			HDC hdc = (HDC)wParam;
 +			HWND hwndCtrl = (HWND)lParam;
 +
 +			if (hBackgroundBrush) {
 +				if (hTitleFont && GetDlgItem(hwndDlg, IDC_TITLE) == hwndCtrl)
 +					SetTextColor(hdc, title_font_colour);
 +				else if (hWindowFont)
 +					SetTextColor(hdc, window_font_colour);
 +
 +				SetBkMode(hdc, TRANSPARENT);
 +				return (BOOL)hBackgroundBrush;
 +			}
 +		}
 +		break;
 +	case WM_CTLCOLORDLG:
 +		if (hBackgroundBrush)
 +			return (BOOL)hBackgroundBrush;
 +		break;
 +	case WMU_SETFONTS:
 +		// fonts
 +		if (hWindowFont)
 +			SendMessage(hwndDlg, WM_SETFONT, (WPARAM)hWindowFont, (LPARAM)TRUE);
 +		if (hTitleFont)
 +			SendDlgItemMessage(hwndDlg, IDC_TITLE, WM_SETFONT, (WPARAM)hTitleFont, (LPARAM)TRUE);
 +
 +		if (hBackgroundBrush) {
 +			SetClassLong(hwndDlg, GCLP_HBRBACKGROUND, (LONG)hBackgroundBrush);
 +			InvalidateRect(hwndDlg, 0, TRUE);
 +		}
 +		return TRUE;
 +
 +	case WMU_SETOPT:
 +		{
 +			Options *opt;
 +			if (lParam) opt = (Options *)lParam;
 +			else opt = &options;
 +			
 +			// round corners
 +			if (opt->aw_roundcorners) {
 +				HRGN hRgn1;
 +				RECT r;
 +				int v,h;
 +				int w=10;
 +				GetWindowRect(hwndDlg,&r);
 +				h=(r.right-r.left)>(w*2)?w:(r.right-r.left);
 +				v=(r.bottom-r.top)>(w*2)?w:(r.bottom-r.top);
 +				h=(h<v)?h:v;
 +				hRgn1=CreateRoundRectRgn(0,0,(r.right-r.left+1),(r.bottom-r.top+1),h,h);
 +				SetWindowRgn(hwndDlg,hRgn1,1);
 +			} else {
 +				HRGN hRgn1;
 +				RECT r;
 +				int v,h;
 +				int w=10;
 +				GetWindowRect(hwndDlg,&r);
 +				h=(r.right-r.left)>(w*2)?w:(r.right-r.left);
 +				v=(r.bottom-r.top)>(w*2)?w:(r.bottom-r.top);
 +				h=(h<v)?h:v;
 +				hRgn1=CreateRectRgn(0,0,(r.right-r.left+1),(r.bottom-r.top+1));
 +				SetWindowRgn(hwndDlg,hRgn1,1);
 +			}
 +			// transparency
 +		
 +#ifdef WS_EX_LAYERED 
 +			SetWindowLongPtr(hwndDlg, GWL_EXSTYLE, GetWindowLongPtr(hwndDlg, GWL_EXSTYLE) | WS_EX_LAYERED);
 +#endif
 +#ifdef LWA_ALPHA
 +			if (MySetLayeredWindowAttributes) 
 +				MySetLayeredWindowAttributes(hwndDlg, RGB(0,0,0), (int)((100 - opt->aw_trans) / 100.0 * 255), LWA_ALPHA);
 +#endif
 +		}
 +		return TRUE;
 +
 +	case WMU_SETALARM:
 +		{
 +			ALARM *data = (ALARM *)lParam;
 +			SetWindowText(hwndDlg, data->szTitle);
 +			HWND hw = GetDlgItem(hwndDlg, IDC_TITLE);
 +			SetWindowText(hw, data->szTitle);
 +
 +			SetDlgItemText(hwndDlg, IDC_ED_DESC, data->szDesc);
 +			((WindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA))->alarm = data;
 +
 +			if (data->action & AAF_SOUND && options.loop_sound) {
 +				if (data->sound_num <= 3)
 +					SetTimer(hwndDlg, ID_TIMER_SOUND, SOUND_REPEAT_PERIOD, 0);	
 +				else if (data->sound_num == 4) 
 +					SetTimer(hwndDlg, ID_TIMER_SOUND, SPEACH_REPEAT_PERIOD, 0);	
 +			}
 +
 +			hw = GetDlgItem(hwndDlg, IDC_SNOOZE);
 +			EnableWindow(hw, !(data->flags & ALF_NOSNOOZE));
 +			ShowWindow(hw, (data->flags & ALF_NOSNOOZE) ? SW_HIDE : SW_SHOWNA);
 +		}
 +		return TRUE;
 +
 +	case WMU_FAKEALARM:
 +		{
 +			SetWindowText(hwndDlg, TranslateT("Example Alarm"));
 +			HWND hw = GetDlgItem(hwndDlg, IDC_TITLE);
 +			SetWindowText(hw, TranslateT("Example Alarm"));
 +			SetDlgItemText(hwndDlg, IDC_ED_DESC, TranslateT("Some example text. Example, example, example."));
 +		}
 +		return TRUE;
 +
 +	case WM_TIMER: 
 +		{
 +			if (wParam == ID_TIMER_SOUND) {
 +				WindowData *dw = (WindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +				if (dw) {
 +					ALARM *data = dw->alarm;
 +					if (data && data->action & AAF_SOUND) {
 +						if (data->sound_num <= 3) {
 +							char buff[128];
 +							sprintf(buff, "Triggered%d", data->sound_num);
 +							SkinPlaySound(buff);
 +						} else if (data->sound_num == 4) {
 +							if (data->szTitle != NULL && data->szTitle[0] != '\0') {
 +								if (ServiceExists("Speak/Say")) {
 +									CallService("Speak/Say", 0, (LPARAM)data->szTitle);
 +								}
 +							}
 +						}
 +					}
 +				}
 +			}
 +		}
 +		return TRUE;
 +	case WM_MOVE:
 +		{
 +			//WindowData *wd = (WindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +			Utils_SaveWindowPosition(hwndDlg, 0, MODULE, "Notify");
 +		}
 +		break;
 +
 +	case WMU_ADDSNOOZER:
 +		{
 +			WindowData *wd = (WindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +			if (wd) {
 +				ALARM *data = wd->alarm;
 +
 +				if (data) {
 +					// add snooze minutes to current time
 +					FILETIME ft;
 +					GetLocalTime(&data->time);
 +					SystemTimeToFileTime(&data->time, &ft);
 +					ULARGE_INTEGER uli;
 +					uli.LowPart = ft.dwLowDateTime;
 +					uli.HighPart = ft.dwHighDateTime;
 +
 +					// there are 10000000 100-nanosecond blocks in a second...
 +					uli.QuadPart += mult.QuadPart * (int)(wParam);
 +
 +					ft.dwHighDateTime = uli.HighPart;
 +					ft.dwLowDateTime = uli.LowPart;
 +
 +					FileTimeToSystemTime(&ft, &data->time);
 +
 +					data->occurrence = OC_ONCE;
 +					data->snoozer = true;
 +					data->flags = data->flags & ~ALF_NOSTARTUP;
 +
 +					data->id = next_alarm_id++;
 +
 +					append_to_list(data);
 +				}
 +			}
 +
 +		}
 +		return TRUE;
 +	case WM_COMMAND:
 +		if ( HIWORD( wParam ) == BN_CLICKED ) {
 +			switch( LOWORD( wParam )) {
 +			case IDCANCEL:  // no button - esc pressed
 +			case IDOK:		// space?
 +			case IDC_SNOOZE:
 +				SendMessage(hwndDlg, WMU_ADDSNOOZER, (WPARAM)options.snooze_minutes, 0);
 +				//drop through
 +			case IDC_DISMISS:
 +				{
 +					WindowData *window_data = (WindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +					KillTimer(hwndDlg, ID_TIMER_SOUND);
 +					if (window_data) {
 +						if (window_data->alarm) {
 +							free_alarm_data(window_data->alarm);
 +							delete window_data->alarm;
 +						}
 +						delete window_data;
 +					}
 +					SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
 +
 +					win_num--;
 +					//EndDialog(hwndDlg, IDOK); // not modal!
 +					WindowList_Remove(hAlarmWindowList, hwndDlg);
 +					DestroyWindow(hwndDlg);
 +				}
 +				break;
 +			case IDC_SNOOZELIST:
 +				{
 +					POINT pt, pt_rel;
 +					GetCursorPos(&pt);				
 +					pt_rel = pt;
 +					ScreenToClient(hwndDlg,&pt_rel);
 +
 +					HMENU hMenu = CreatePopupMenu();
 +					MENUITEMINFO mmi = {0};
 +					mmi.cbSize = sizeof(mmi);
 +					mmi.fMask = MIIM_ID | MIIM_STRING;
 +
 +#define AddItem(x)							\
 +		mmi.wID++;							\
 +		mmi.dwTypeData = TranslateT(x);		\
 +		mmi.cch = ( UINT )_tcslen(mmi.dwTypeData);	\
 +		InsertMenuItem(hMenu, mmi.wID, FALSE, &mmi);
 +
 +					AddItem("5 mins");
 +					AddItem("15 mins");
 +					AddItem("30 mins");
 +					AddItem("1 hour");
 +					AddItem("1 day");
 +					AddItem("1 week");
 +
 +					TPMPARAMS tpmp = {0};
 +					tpmp.cbSize	= sizeof(tpmp);
 +					LRESULT ret = (LRESULT)TrackPopupMenuEx(hMenu, TPM_RETURNCMD, pt.x, pt.y, hwndDlg, &tpmp);
 +					switch(ret) {
 +						case 0: DestroyMenu(hMenu); return 0; // dismis menu
 +						case 1: SendMessage(hwndDlg, WMU_ADDSNOOZER, (WPARAM)5, 0); break;
 +						case 2: SendMessage(hwndDlg, WMU_ADDSNOOZER, (WPARAM)15, 0); break;
 +						case 3: SendMessage(hwndDlg, WMU_ADDSNOOZER, (WPARAM)30, 0); break;
 +						case 4: SendMessage(hwndDlg, WMU_ADDSNOOZER, (WPARAM)60, 0); break;
 +						case 5: SendMessage(hwndDlg, WMU_ADDSNOOZER, (WPARAM)(60 * 24), 0); break;
 +						case 6: SendMessage(hwndDlg, WMU_ADDSNOOZER, (WPARAM)(60 * 24 * 7), 0); break;
 +					}
 +
 +					DestroyMenu(hMenu);
 +
 +					SendMessage(hwndDlg, WM_COMMAND, IDC_DISMISS, 0);
 +				}
 +				break;
 +			}
 +		}
 +		return TRUE;
 +
 +	case WM_MOUSEMOVE:
 +		if (wParam & MK_LBUTTON) {
 +			SetCapture(hwndDlg);
 +
 +			POINT newp;
 +			newp.x = (short)LOWORD(lParam);
 +			newp.y = (short)HIWORD(lParam);
 +
 +			ClientToScreen(hwndDlg, &newp);
 +
 +			WindowData *window_data = (WindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +			if (!window_data->moving) {
 +				window_data->moving = true;
 +			} else {
 +				RECT r;
 +				GetWindowRect(hwndDlg, &r);
 +				
 +				SetWindowPos(hwndDlg, 0, r.left + (newp.x - window_data->p.x), r.top + (newp.y - window_data->p.y), 0, 0, SWP_NOSIZE | SWP_NOZORDER);
 +			}
 +			window_data->p.x = newp.x;
 +			window_data->p.y = newp.y;			
 +		} else {
 +			ReleaseCapture();
 +			WindowData *window_data = (WindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +			window_data->moving = false;
 +		}
 +		return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +int ReloadFonts(WPARAM wParam, LPARAM lParam) {
 +	LOGFONT log_font;
 +	title_font_colour = CallService(MS_FONT_GET, (WPARAM)&title_font_id, (LPARAM)&log_font);
 +	DeleteObject(hTitleFont);
 +	hTitleFont = CreateFontIndirect(&log_font);
 +
 +	window_font_colour = CallService(MS_FONT_GET, (WPARAM)&window_font_id, (LPARAM)&log_font);
 +	DeleteObject(hWindowFont);
 +	hWindowFont = CreateFontIndirect(&log_font);
 +
 +	COLORREF bkCol = CallService(MS_COLOUR_GET, (WPARAM)&bk_colour_id, 0);
 +	DeleteObject(hBackgroundBrush);
 +	hBackgroundBrush = CreateSolidBrush(bkCol);
 +
 +	WindowList_Broadcast(hAlarmWindowList, WMU_REFRESH, 0, 0);
 +	return 0;
 +}
 +
 +int AlarmWinModulesLoaded(WPARAM wParam, LPARAM lParam)
 +{
 +	title_font_id.cbSize = sizeof(FontID);
 +	strcpy(title_font_id.group, Translate("Alarms"));
 +	strcpy(title_font_id.name, Translate("Title"));
 +	strcpy(title_font_id.dbSettingsGroup, MODULE);
 +	strcpy(title_font_id.prefix, "FontTitle");
 +	title_font_id.flags = 0;
 +	title_font_id.order = 0;
 +	FontRegister(&title_font_id);
 +
 +	window_font_id.cbSize = sizeof(FontID);
 +	strcpy(window_font_id.group, Translate("Alarms"));
 +	strcpy(window_font_id.name, Translate("Window"));
 +	strcpy(window_font_id.dbSettingsGroup, MODULE);
 +	strcpy(window_font_id.prefix, "FontWindow");
 +	window_font_id.flags = 0;
 +	window_font_id.order = 1;
 +	FontRegister(&window_font_id);
 +
 +	bk_colour_id.cbSize = sizeof(ColourID);
 +	strcpy(bk_colour_id.dbSettingsGroup, MODULE);
 +	strcpy(bk_colour_id.group, Translate("Alarms"));
 +	strcpy(bk_colour_id.name, Translate("Background"));
 +	strcpy(bk_colour_id.setting, "BkColour");
 +	bk_colour_id.defcolour = GetSysColor(COLOR_3DFACE);
 +	bk_colour_id.flags = 0;
 +	bk_colour_id.order = 0;
 +
 +	ColourRegister(&bk_colour_id);
 +
 +	ReloadFonts(0, 0);
 +	HookEvent(ME_FONT_RELOAD, ReloadFonts);
 +	return 0;
 +}
 +
 +void InitAlarmWin() {
 +	hUserDll = LoadLibrary(_T("user32.dll"));
 +	if (hUserDll) {
 +		MySetLayeredWindowAttributes = (BOOL (WINAPI *)(HWND,COLORREF,BYTE,DWORD))GetProcAddress(hUserDll, "SetLayeredWindowAttributes");
 +		//MyAnimateWindow=(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(hUserDll,"AnimateWindow");
 +	}
 +
 +	hAlarmWindowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0);
 +
 +	HookEvent(ME_SYSTEM_MODULESLOADED, AlarmWinModulesLoaded);
 +}
 +
 +void DeinitAlarmWin() {
 +	
 +	WindowList_Broadcast(hAlarmWindowList, WM_COMMAND, IDC_SNOOZE, 0);
 +
 +	FreeLibrary(hUserDll);
 +
 +	if (hBackgroundBrush) DeleteObject(hBackgroundBrush);
 +	if (hTitleFont) DeleteObject(hTitleFont);
 +	if (hWindowFont) DeleteObject(hWindowFont);
 +}
 +
 diff --git a/plugins/Alarms/src/alarm_win.h b/plugins/Alarms/src/alarm_win.h new file mode 100644 index 0000000000..19576050c6 --- /dev/null +++ b/plugins/Alarms/src/alarm_win.h @@ -0,0 +1,22 @@ +#ifndef _ALARM_WIN_INC
 +#define _ALARM_WIN_INC
 +
 +#include "options.h"
 +#include "alarmlist.h"
 +
 +INT_PTR CALLBACK DlgProcAlarm(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
 +
 +#define WMU_SETALARM				(WM_USER + 0x100)
 +#define WMU_FAKEALARM				(WM_USER + 0x101)
 +
 +#define WMU_SETOPT					(WM_USER + 60)
 +
 +extern HANDLE hAlarmWindowList;
 +
 +void SetAlarmWinOptions();
 +bool TransparencyEnabled();
 +
 +void InitAlarmWin();
 +void DeinitAlarmWin();
 +
 +#endif
 diff --git a/plugins/Alarms/src/alarmlist.cpp b/plugins/Alarms/src/alarmlist.cpp new file mode 100644 index 0000000000..d7b712dee7 --- /dev/null +++ b/plugins/Alarms/src/alarmlist.cpp @@ -0,0 +1,784 @@ +#include "common.h"
 +#include "alarmlist.h"
 +
 +AlarmList alarms;
 +CRITICAL_SECTION alarm_cs;
 +
 +unsigned short next_alarm_id = 1; // 0 is used for invalid id
 +
 +DWORD timer_id;
 +#define TIMER_PERIOD				5000 // milliseconds delay between alarm checks
 +
 +static SYSTEMTIME last_check, last_saved_check;
 +
 +HANDLE hAlarmTriggeredEvent, hAddAlarmService;
 +
 +bool startup = true;
 +
 +bool is_idle = false;
 +
 +void free_alarm_data(ALARM *alarm) {
 +	if (alarm->szTitle) {free(alarm->szTitle); alarm->szTitle = 0;}
 +	if (alarm->szDesc) {free(alarm->szDesc); alarm->szDesc = 0;}
 +	if (alarm->szCommand) {free(alarm->szCommand); alarm->szCommand = 0;}
 +	if (alarm->szCommandParams) {free(alarm->szCommandParams); alarm->szCommandParams = 0;}
 +}
 +
 +void copy_alarm_data(ALARM *dest, ALARM *src) {
 +	dest->action = src->action;
 +	dest->flags = src->flags;
 +	dest->id = src->id;
 +	dest->occurrence = src->occurrence;
 +	dest->snoozer = src->snoozer;
 +	dest->sound_num = src->sound_num;
 +	dest->time = src->time;
 +	dest->trigger_id = src->trigger_id;
 +
 +	free_alarm_data(dest);
 +	dest->szTitle = mir_tstrdup(src->szTitle);
 +	dest->szDesc = mir_tstrdup(src->szDesc);
 +	dest->szCommand = mir_tstrdup(src->szCommand);
 +	dest->szCommandParams = mir_tstrdup(src->szCommandParams);
 +}
 +
 +void GetPluginTime(SYSTEMTIME *t) {
 +	EnterCriticalSection(&alarm_cs);
 +	*t = last_check;
 +	LeaveCriticalSection(&alarm_cs);
 +}
 +
 +int MinutesInFuture(SYSTEMTIME time, Occurrence occ) {
 +	if (!UpdateAlarm(time, occ)) return 0;
 +
 +	SYSTEMTIME now;
 +	GetPluginTime(&now);
 +
 +	FILETIME ft_now, ft_then;
 +	SystemTimeToFileTime(&now, &ft_now);
 +	SystemTimeToFileTime(&time, &ft_then);
 +	
 +	ULARGE_INTEGER uli_now, uli_then, diff;
 +	uli_now.HighPart = ft_now.dwHighDateTime;
 +	uli_now.LowPart = ft_now.dwLowDateTime;
 +	uli_then.HighPart = ft_then.dwHighDateTime;
 +	uli_then.LowPart = ft_then.dwLowDateTime;
 +
 +	diff.QuadPart = uli_then.QuadPart - uli_now.QuadPart;
 +	bool inc = false;
 +	if (diff.QuadPart % mult.QuadPart >= mult.QuadPart / 2)
 +		inc = true;
 +	return (int)(diff.QuadPart / mult.QuadPart + (inc ? 1 : 0));
 +}
 +
 +void TimeForMinutesInFuture(int mins, SYSTEMTIME *time) {
 +	SYSTEMTIME now;
 +	FILETIME ft_now;
 +	GetPluginTime(&now);
 +	SystemTimeToFileTime(&now, &ft_now);
 +
 +	ULARGE_INTEGER uli_now;
 +	uli_now.HighPart = ft_now.dwHighDateTime;
 +	uli_now.LowPart = ft_now.dwLowDateTime;
 +
 +	uli_now.QuadPart += mult.QuadPart * (ULONGLONG)mins;
 +	ft_now.dwHighDateTime = uli_now.HighPart;
 +	ft_now.dwLowDateTime = uli_now.LowPart;
 +
 +	FileTimeToSystemTime(&ft_now, time);
 +}
 +
 +
 +// update an alarm so that the systemtime reflects the next time the alarm will go off, based on the last_check time
 +bool UpdateAlarm(SYSTEMTIME &time, Occurrence occ) {
 +
 +	FILETIME ft_now, ft_then;
 +	ULARGE_INTEGER uli_then;
 +
 +	switch(occ) {
 +	case OC_DAILY:
 +	case OC_WEEKDAYS:
 +	case OC_WEEKLY:
 +		time.wDay = last_check.wDay;
 +	case OC_MONTHLY:
 +		time.wMonth = last_check.wMonth;
 +	case OC_YEARLY:
 +		time.wYear = last_check.wYear;
 +	case OC_ONCE:
 +		break; // all fields valid
 +	};
 +
 +	SystemTimeToFileTime(&last_check, &ft_now); // consider 'now' to be last check time
 +	SystemTimeToFileTime(&time, &ft_then);
 +	
 +	switch(occ) {
 +	case OC_ONCE:
 +		if (CompareFileTime(&ft_then, &ft_now) < 0)
 +			return false;
 +		break;
 +	case OC_YEARLY:
 +		while(CompareFileTime(&ft_then, &ft_now) < 0) {
 +			time.wYear++;
 +			SystemTimeToFileTime(&time, &ft_then);
 +		}
 +		break;
 +	case OC_MONTHLY:
 +		while(CompareFileTime(&ft_then, &ft_now) < 0) {
 +			if (time.wMonth == 12) {
 +				time.wMonth = 1;
 +				time.wYear++;
 +			} else
 +				time.wMonth++;
 +			SystemTimeToFileTime(&time, &ft_then);
 +		}
 +		break;
 +	case OC_WEEKLY:
 +		{
 +			SYSTEMTIME temp;
 +			uli_then.HighPart = ft_then.dwHighDateTime;
 +			uli_then.LowPart = ft_then.dwLowDateTime;
 +			FileTimeToSystemTime(&ft_then, &temp);
 +			do {
 +				if (temp.wDayOfWeek != time.wDayOfWeek || CompareFileTime(&ft_then, &ft_now) < 0) {
 +					uli_then.QuadPart += mult.QuadPart * (ULONGLONG)24 * (ULONGLONG)60;
 +					ft_then.dwHighDateTime = uli_then.HighPart;
 +					ft_then.dwLowDateTime = uli_then.LowPart;
 +					FileTimeToSystemTime(&ft_then, &temp);
 +				}
 +			} while(temp.wDayOfWeek != time.wDayOfWeek || CompareFileTime(&ft_then, &ft_now) < 0);
 +		}
 +		break;
 +	case OC_WEEKDAYS:
 +		{
 +			SYSTEMTIME temp;
 +			uli_then.HighPart = ft_then.dwHighDateTime;
 +			uli_then.LowPart = ft_then.dwLowDateTime;
 +			do {
 +				FileTimeToSystemTime(&ft_then, &temp);
 +				if (temp.wDayOfWeek == 0 || temp.wDayOfWeek == 6 || CompareFileTime(&ft_then, &ft_now) < 0) {
 +					uli_then.QuadPart += mult.QuadPart * (ULONGLONG)24 * (ULONGLONG)60;
 +					ft_then.dwHighDateTime = uli_then.HighPart;
 +					ft_then.dwLowDateTime = uli_then.LowPart;
 +				}
 +			} while(temp.wDayOfWeek == 0 || temp.wDayOfWeek == 6 || CompareFileTime(&ft_then, &ft_now) < 0);
 +		}
 +		break;
 +	case OC_DAILY:
 +		uli_then.HighPart = ft_then.dwHighDateTime;
 +		uli_then.LowPart = ft_then.dwLowDateTime;
 +		while(CompareFileTime(&ft_then, &ft_now) < 0) {
 +			uli_then.QuadPart += mult.QuadPart * (ULONGLONG)24 * (ULONGLONG)60;
 +			ft_then.dwHighDateTime = uli_then.HighPart;
 +			ft_then.dwLowDateTime = uli_then.LowPart;
 +		}
 +		break;
 +	}
 +
 +	FileTimeToSystemTime(&ft_then, &time);
 +	return true;
 +}
 +
 +void LoadAlarms() {
 +	int num_alarms = DBGetContactSettingWord(0, MODULE, "Count", 0);
 +	char buff[256];
 +	DBVARIANT dbv;
 +	ALARM alarm;
 +	SYSTEMTIME now;
 +	GetLocalTime(&now);
 +
 +	EnterCriticalSection(&alarm_cs);
 +	alarms.clear();
 +
 +	for(int i = 0; i < num_alarms; i++) {
 +		memset(&alarm, 0, sizeof(ALARM));
 +
 +		sprintf(buff, "Title%d", i);
 +		if (!DBGetContactSetting(0, MODULE, buff, &dbv)) {
 +			if (dbv.ptszVal && _tcslen(dbv.ptszVal))
 +				alarm.szTitle = mir_tstrdup(dbv.ptszVal);
 +			DBFreeVariant(&dbv);
 +		}
 +		sprintf(buff, "Desc%d", i);
 +		if (!DBGetContactSetting(0, MODULE, buff, &dbv)) {
 +			if (dbv.ptszVal && _tcslen(dbv.ptszVal))
 +				alarm.szDesc = mir_tstrdup(dbv.ptszVal);
 +			DBFreeVariant(&dbv);
 +		}
 +		sprintf(buff, "Occ%d", i);
 +		alarm.occurrence = (Occurrence)DBGetContactSettingWord(0, MODULE, buff, 0);
 +
 +		sprintf(buff, "STHour%d", i);
 +		alarm.time.wHour = DBGetContactSettingWord(0, MODULE, buff, 0);
 +		sprintf(buff, "STMinute%d", i);
 +		alarm.time.wMinute = DBGetContactSettingWord(0, MODULE, buff, 0);
 +		sprintf(buff, "STSecond%d", i);
 +		alarm.time.wSecond = DBGetContactSettingWord(0, MODULE, buff, 0);
 +
 +		switch(alarm.occurrence) {
 +
 +		case OC_ONCE:
 +			sprintf(buff, "STYear%d", i);
 +			alarm.time.wYear = DBGetContactSettingWord(0, MODULE, buff, 0);
 +			sprintf(buff, "STMonth%d", i);
 +			alarm.time.wMonth = DBGetContactSettingWord(0, MODULE, buff, 0);
 +			sprintf(buff, "STDay%d", i);
 +			alarm.time.wDay = DBGetContactSettingWord(0, MODULE, buff, 0);
 +			break;
 +		case OC_WEEKLY:
 +			sprintf(buff, "STDayOfWeek%d", i);
 +			alarm.time.wDayOfWeek = DBGetContactSettingWord(0, MODULE, buff, 0);
 +			break;
 +		case OC_WEEKDAYS:
 +			break;
 +		case OC_DAILY:
 +			break;
 +		case OC_MONTHLY:
 +			sprintf(buff, "STDay%d", i);
 +			alarm.time.wDay = DBGetContactSettingWord(0, MODULE, buff, 0);
 +			break;
 +		case OC_YEARLY:
 +			sprintf(buff, "STMonth%d", i);
 +			alarm.time.wMonth = DBGetContactSettingWord(0, MODULE, buff, 0);
 +			sprintf(buff, "STDay%d", i);
 +			alarm.time.wDay = DBGetContactSettingWord(0, MODULE, buff, 0);
 +			break;
 +		}
 +
 +		sprintf(buff, "TriggerID%d", i);
 +		alarm.trigger_id = DBGetContactSettingDword(0, MODULE, buff, 0);
 +
 +		if (UpdateAlarm(alarm.time, alarm.occurrence)) {
 +			sprintf(buff, "ActionFlags%d", i);
 +			alarm.action = (unsigned short)DBGetContactSettingDword(0, MODULE, buff, AAF_POPUP | AAF_SOUND);
 +			if (alarm.action & AAF_COMMAND) {
 +				sprintf(buff, "ActionCommand%d", i);
 +				if (!DBGetContactSetting(0, MODULE, buff, &dbv)) {
 +					if (dbv.ptszVal && _tcslen(dbv.ptszVal))
 +						alarm.szCommand = mir_tstrdup(dbv.ptszVal);
 +					DBFreeVariant(&dbv);
 +					sprintf(buff, "ActionParams%d", i);
 +					if (!DBGetContactSetting(0, MODULE, buff, &dbv)) {
 +						if (dbv.ptszVal && _tcslen(dbv.ptszVal))
 +							alarm.szCommandParams = mir_tstrdup(dbv.ptszVal);
 +						DBFreeVariant(&dbv);
 +					}
 +				}
 +			}
 +
 +			sprintf(buff, "SoundNum%d", i);
 +			alarm.sound_num = (int)DBGetContactSettingByte(0, MODULE, buff, 1);
 +
 +			sprintf(buff, "Snoozer%d", i);
 +			alarm.snoozer = DBGetContactSettingByte(0, MODULE, buff, 0) == 1;
 +
 +			sprintf(buff, "Hidden%d", i);
 +			alarm.flags |= (DBGetContactSettingByte(0, MODULE, buff, 0) == 1 ? ALF_HIDDEN : 0);
 +
 +			sprintf(buff, "Suspended%d", i);
 +			alarm.flags |= (DBGetContactSettingByte(0, MODULE, buff, 0) == 1 ? ALF_SUSPENDED : 0);
 +
 +			sprintf(buff, "NoStartup%d", i);
 +			alarm.flags |= (DBGetContactSettingByte(0, MODULE, buff, 0) == 1 ? ALF_NOSTARTUP : 0);
 +
 +			sprintf(buff, "Flags%d", i);
 +			alarm.flags = DBGetContactSettingDword(0, MODULE, buff, alarm.flags);
 +
 +			alarm.id = next_alarm_id++;
 +			alarms.push_back(&alarm);
 +
 +		} else { // else ignore it - it's an expired one-off alarm (but clean up triggers)
 +			if (alarm.trigger_id != 0 && ServiceExists(MS_TRIGGER_REPORTEVENT)) {
 +				REPORTINFO ri = {0};
 +				ri.cbSize = sizeof(ri);
 +				ri.triggerID = alarm.trigger_id;
 +				ri.flags = TRG_CLEANUP;
 +				CallService(MS_TRIGGER_REPORTEVENT, 0, (LPARAM)&ri);
 +			}
 +		}
 +		free_alarm_data(&alarm);
 +	}
 +	LeaveCriticalSection(&alarm_cs);
 +}
 +
 +void SaveAlarms() {
 +	int index = 0;
 +	char buff[256];
 +
 +	EnterCriticalSection(&alarm_cs);
 +
 +	ALARM *i;
 +	for(alarms.reset(); i = alarms.current(); alarms.next(), index++) {
 +		sprintf(buff, "Title%d", index);
 +		DBWriteContactSettingTString(0, MODULE, buff, i->szTitle);
 +		sprintf(buff, "Desc%d", index);
 +		DBWriteContactSettingTString(0, MODULE, buff, i->szDesc);
 +		sprintf(buff, "Occ%d", index);
 +		DBWriteContactSettingWord(0, MODULE, buff, i->occurrence);
 +
 +		sprintf(buff, "STHour%d", index);
 +		DBWriteContactSettingWord(0, MODULE, buff, i->time.wHour);
 +		sprintf(buff, "STMinute%d", index);
 +		DBWriteContactSettingWord(0, MODULE, buff, i->time.wMinute);
 +		sprintf(buff, "STSecond%d", index);
 +		DBWriteContactSettingWord(0, MODULE, buff, i->time.wSecond);
 +
 +		switch(i->occurrence) {
 +		case OC_DAILY:
 +			break;
 +		case OC_WEEKDAYS:
 +			break;
 +		case OC_WEEKLY:
 +			sprintf(buff, "STDayOfWeek%d", index);
 +			DBWriteContactSettingWord(0, MODULE, buff, i->time.wDayOfWeek);
 +			break;
 +
 +		case OC_ONCE:
 +			sprintf(buff, "STYear%d", index);
 +			DBWriteContactSettingWord(0, MODULE, buff, i->time.wYear);
 +		case OC_YEARLY:
 +			sprintf(buff, "STMonth%d", index);
 +			DBWriteContactSettingWord(0, MODULE, buff, i->time.wMonth);
 +		case OC_MONTHLY:
 +			sprintf(buff, "STDay%d", index);
 +			DBWriteContactSettingWord(0, MODULE, buff, i->time.wDay);
 +			break;
 +		}
 +		sprintf(buff, "ActionFlags%d", index);
 +		DBWriteContactSettingDword(0, MODULE, buff, i->action);
 +		if (i->action & AAF_COMMAND) {
 +			if (_tcslen(i->szCommand)) {
 +				sprintf(buff, "ActionCommand%d", index);
 +				DBWriteContactSettingTString(0, MODULE, buff, i->szCommand);
 +				if (_tcslen(i->szCommandParams)) {
 +					sprintf(buff, "ActionParams%d", index);
 +					DBWriteContactSettingTString(0, MODULE, buff, i->szCommandParams);
 +				}
 +			}
 +		}
 +		
 +		sprintf(buff, "SoundNum%d", index);
 +		DBWriteContactSettingByte(0, MODULE, buff, i->sound_num);
 +
 +		sprintf(buff, "Snoozer%d", index);
 +		DBWriteContactSettingByte(0, MODULE, buff, i->snoozer ? 1 : 0);
 +
 +		sprintf(buff, "Flags%d", index);
 +		DBWriteContactSettingDword(0, MODULE, buff, i->flags);
 +
 +		sprintf(buff, "TriggerID%d", index);
 +		DBWriteContactSettingDword(0, MODULE, buff, i->trigger_id);
 +	}
 +	DBWriteContactSettingWord(0, MODULE, "Count", index);
 +
 +	LeaveCriticalSection(&alarm_cs);
 +}
 +
 +void copy_list(AlarmList ©) {
 +	copy.clear();
 +	ALARM *i;
 +	EnterCriticalSection(&alarm_cs);
 +	for(alarms.reset(); i = alarms.current(); alarms.next()) {
 +		copy.push_back(i);
 +	}
 +	LeaveCriticalSection(&alarm_cs);
 +}
 +
 +void copy_list(AlarmList ©, SYSTEMTIME &start, SYSTEMTIME &end) {
 +	copy.clear();
 +	ALARM *i;
 +	EnterCriticalSection(&alarm_cs);
 +	for(alarms.reset(); i = alarms.current(); alarms.next()) {
 +		if (IsBetween(i->time, start, end))
 +			copy.push_back(i);
 +	}
 +	LeaveCriticalSection(&alarm_cs);
 +}
 +
 +void set_list(AlarmList ©) {
 +	EnterCriticalSection(&alarm_cs);
 +	alarms.clear();
 +	ALARM *i;
 +	for(copy.reset(); i = copy.current(); copy.next()) {
 +		alarms.push_back(i);
 +	}
 +	LeaveCriticalSection(&alarm_cs);
 +
 +	SaveAlarms();
 +}
 +
 +void append_to_list(ALARM *alarm) {
 +	EnterCriticalSection(&alarm_cs);
 +	if (!alarm->id)
 +		alarm->id = next_alarm_id++;
 +	alarms.push_back(alarm);
 +	LeaveCriticalSection(&alarm_cs);
 +
 +	SaveAlarms();
 +}
 +
 +void alter_alarm_list(ALARM *alarm) {
 +	bool found = false;
 +	EnterCriticalSection(&alarm_cs);
 +	if (alarm->id != 0) {
 +		ALARM *i;
 +		for(alarms.reset(); i = alarms.current(); alarms.next()) {
 +			if (i->id == alarm->id) {
 +				copy_alarm_data(i, alarm);
 +				found = true;
 +				break;
 +			}
 +		}
 +	}
 +	if (!found) {
 +		if (!alarm->id)
 +			alarm->id = next_alarm_id++;
 +		alarms.push_back(alarm);
 +	}
 +
 +	LeaveCriticalSection(&alarm_cs);
 +
 +	SaveAlarms();
 +}
 +
 +void remove(unsigned short alarm_id) {
 +	EnterCriticalSection(&alarm_cs);
 +	ALARM *i;
 +	for(alarms.reset(); i = alarms.current(); alarms.next()) {
 +		if (i->id == alarm_id) {
 +			if (i->trigger_id != 0 && ServiceExists(MS_TRIGGER_REPORTEVENT)) {
 +				REPORTINFO ri = {0};
 +				ri.cbSize = sizeof(ri);
 +				ri.triggerID = i->trigger_id;
 +				ri.flags = TRG_CLEANUP;
 +				CallService(MS_TRIGGER_REPORTEVENT, 0, (LPARAM)&ri);
 +			}
 +			alarms.erase();
 +			break;
 +		}
 +	}
 +	LeaveCriticalSection(&alarm_cs);
 +
 +	SaveAlarms();
 +}
 +
 +void suspend(unsigned short alarm_id) {
 +	EnterCriticalSection(&alarm_cs);
 +	ALARM *i;
 +	for(alarms.reset(); i = alarms.current(); alarms.next()) {
 +		if (i->id == alarm_id && i->occurrence != OC_ONCE) {
 +			i->flags |= ALF_SUSPENDED;
 +			break;
 +		}
 +	}
 +	LeaveCriticalSection(&alarm_cs);
 +
 +	SaveAlarms();
 +}
 +
 +static int CALLBACK PopupAlarmDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 +{
 +	switch(message) {
 +		case WM_COMMAND: // snooze
 +			if (HIWORD(wParam) == STN_CLICKED) { //It was a click on the Popup.
 +				ALARM *mpd = NULL;
 +				mpd = (ALARM *)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd,(LPARAM)mpd);
 +
 +				if (mpd->flags & ALF_NOSNOOZE)
 +					return TRUE;
 +
 +				// add snooze minutes to current time
 +				FILETIME ft;
 +				GetLocalTime(&mpd->time);
 +				SystemTimeToFileTime(&mpd->time, &ft);
 +				ULARGE_INTEGER uli;
 +				uli.LowPart = ft.dwLowDateTime;
 +				uli.HighPart = ft.dwHighDateTime;
 +
 +				uli.QuadPart += mult.QuadPart * options.snooze_minutes;
 +
 +				ft.dwHighDateTime = uli.HighPart;
 +				ft.dwLowDateTime = uli.LowPart;
 +
 +				FileTimeToSystemTime(&ft, &mpd->time);
 +
 +				mpd->occurrence = OC_ONCE;
 +				mpd->snoozer = true;
 +				mpd->flags = mpd->flags & ~(ALF_NOSTARTUP);
 +
 +				mpd->id = next_alarm_id++;
 +
 +				append_to_list(mpd);
 +			}
 +
 +			PUDeletePopUp(hWnd);
 +			return TRUE;
 +		case WM_CONTEXTMENU: 
 +			PUDeletePopUp(hWnd);
 +			return TRUE;
 +		case UM_FREEPLUGINDATA: 
 +			{
 +				ALARM *mpd = NULL;
 +				mpd = (ALARM *)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd,(LPARAM)mpd);
 +				if (mpd > 0) {
 +					free_alarm_data(mpd);
 +					delete mpd;
 +				}
 +				return TRUE;
 +			}
 +		default:
 +			break;
 +	}
 +	return DefWindowProc(hWnd, message, wParam, lParam);
 +}
 +
 +void ShowPopup(ALARM *alarm) {
 +	if (ServiceExists(MS_POPUP_ADDPOPUP)) {
 +		ALARM *data = new ALARM;
 +		memset(data, 0, sizeof(ALARM));
 +		copy_alarm_data(data, alarm);
 +
 +		POPUPDATAT ppd;
 +
 +		ZeroMemory(&ppd, sizeof(ppd)); 
 +		ppd.lchContact = 0; 
 +		ppd.lchIcon = hIconMenuSet;
 +
 +		lstrcpy(ppd.lptzContactName, data->szTitle);
 +		lstrcpy(ppd.lptzText, data->szDesc);
 +		ppd.colorBack = 0;
 +		ppd.colorText = 0;
 +		ppd.PluginWindowProc = (WNDPROC)PopupAlarmDlgProc;
 +		ppd.PluginData = data;
 +		ppd.iSeconds = -1;
 +
 +		//Now that every field has been filled, we want to see the popup.
 +		CallService(MS_POPUP_ADDPOPUPEX, (WPARAM)&ppd, 0);
 +	}
 +}
 +
 +void DoAlarm(ALARM *alarm) {
 +	ALARMINFO alarminfo;
 +	alarminfo.szTitle = alarm->szTitle;
 +	alarminfo.szDesc = alarm->szDesc;
 +	alarminfo.szCommand = alarm->szCommand;
 +	alarminfo.szCommandParams = alarm->szCommandParams;
 +	alarminfo.occurrence = alarm->occurrence;
 +	alarminfo.snoozer = alarm->snoozer;
 +	alarminfo.time = alarm->time;
 +	alarminfo.flags = alarm->flags;
 +	alarminfo.action = alarm->action;
 +	alarminfo.sound_num = alarm->sound_num;
 +
 +	if (!NotifyEventHooks(hAlarmTriggeredEvent, 0, (LPARAM)&alarminfo)) {
 +
 +		if (alarm->action & AAF_SOUND) {
 +			if (alarm->sound_num > 0 && alarm->sound_num <= 3) {
 +				char buff[128];
 +				sprintf(buff, "Triggered%d", alarm->sound_num);
 +				SkinPlaySound(buff);
 +			} else if (alarm->sound_num == 4) {
 +				if (alarm->szTitle != NULL && alarm->szTitle[0] != '\0') {
 +					if (ServiceExists("Speak/Say")) {
 +						CallService("Speak/Say", 0, (LPARAM)alarm->szTitle);
 +					}
 +				}
 +			}
 +		}
 +		if (alarm->action & AAF_POPUP) {
 +			if (options.use_popup_module && ServiceExists(MS_POPUP_ADDPOPUP)) 
 +				ShowPopup(alarm);
 +			else {
 +				HWND hwndDlg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_ALARM), GetDesktopWindow(), DlgProcAlarm);
 +				WindowList_Add(hAlarmWindowList, hwndDlg, 0);
 +
 +				ALARM *data = new ALARM;
 +				memset(data, 0, sizeof(ALARM));
 +				copy_alarm_data(data, alarm);
 +				SendMessage(hwndDlg, WMU_SETALARM, 0, (LPARAM)data);
 +				if (is_idle || !options.aw_dontstealfocus)
 +					ShowWindow(hwndDlg, SW_SHOW);
 +				else
 +					ShowWindow(hwndDlg, SW_SHOWNOACTIVATE);
 +				SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 +			}
 +		}
 +
 +		if (alarm->trigger_id != 0 && ServiceExists(MS_TRIGGER_REPORTEVENT)) {
 +			REPORTINFO ri = {0};
 +			ri.cbSize = sizeof(ri);
 +			ri.triggerID = alarm->trigger_id;
 +			ri.flags = TRG_PERFORM;
 +			if (alarm->occurrence == OC_ONCE)
 +				ri.flags |= TRG_CLEANUP;
 +			CallService(MS_TRIGGER_REPORTEVENT, 0, (LPARAM)&ri);
 +		}
 +		
 +		if (alarm->action & AAF_COMMAND) {
 +			ShellExecute(0, 0, alarm->szCommand, alarm->szCommandParams, 0, SW_NORMAL);
 +		}
 +
 +		if (alarm->action & AAF_SYSTRAY)
 +		{
 +			CLISTEVENT cle = {0};
 +			cle.cbSize = sizeof(cle);
 +			cle.hContact = 0;
 +			cle.hIcon = hIconSystray;
 +			cle.ptszTooltip = alarm->szTitle;
 +			cle.flags = CLEF_ONLYAFEW | CLEF_TCHAR;
 +			CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle);
 +		}
 +	}
 +}
 +
 +void WriteLastCheckTime() {
 +	// save last-check time
 +	DBCONTACTWRITESETTING dbcws;
 +	dbcws.szModule = MODULE;
 +	dbcws.szSetting = "LastCheck";
 +	dbcws.value.type = DBVT_BLOB;
 +	dbcws.value.cpbVal = sizeof(SYSTEMTIME);
 +	dbcws.value.pbVal = (BYTE *)&last_check;
 +	CallService(MS_DB_CONTACT_WRITESETTING, 0, (LPARAM)&dbcws);
 +
 +	last_saved_check = last_check;
 +}
 +
 +void CheckAlarms() {
 +	SYSTEMTIME time;
 +	GetLocalTime(&time);
 +
 +	// put triggered alarms in another list - so we don't keep the critical section locked for longer than necessary
 +	AlarmList triggered_list, remove_list;
 +
 +	EnterCriticalSection(&alarm_cs);
 +	ALARM *i;
 +	for(alarms.reset(); i = alarms.current(); alarms.next()) {
 +		if (!UpdateAlarm(i->time, i->occurrence)) { 
 +			// somehow an expired one-off alarm is in our list
 +			remove_list.push_back(i);
 +			continue;
 +		}
 +
 +		switch(i->occurrence) {
 +		case OC_ONCE:
 +			if (IsBetween(i->time, last_check, time)) {
 +				if (!startup || !(i->flags & ALF_NOSTARTUP)) triggered_list.push_back(i);
 +				// erase and fix iterator - alarm has now been triggered and has therefore expired
 +				remove_list.push_back(i);
 +			}
 +			break;
 +		default:
 +			if (IsBetween(i->time, last_check, time)) {
 +				if (i->flags & ALF_SUSPENDED)
 +					i->flags = i->flags & ~ALF_SUSPENDED;
 +				else
 +					if (!startup || !(i->flags & ALF_NOSTARTUP)) triggered_list.push_back(i);
 +			}
 +			break;
 +		}
 +	}
 +	
 +	last_check = time;
 +	WriteLastCheckTime();
 +
 +	startup = false;
 +	LeaveCriticalSection(&alarm_cs);
 +
 +	for(triggered_list.reset(); i = triggered_list.current(); triggered_list.next())
 +		DoAlarm(i);
 +	for(remove_list.reset(); i = remove_list.current(); remove_list.next())
 +		remove(i->id);
 +
 +
 +}
 +
 +VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {
 +	CheckAlarms();
 +}
 +
 +
 +INT_PTR AddAlarmService(WPARAM wParam, LPARAM lParam)
 +{
 +	ALARMINFO *alarm_info = (ALARMINFO *)lParam;
 +	ALARM alarm = {0};
 +	alarm.action = alarm_info->action;
 +	alarm.flags = alarm_info->flags;
 +	alarm.id = next_alarm_id++;
 +	alarm.occurrence = alarm_info->occurrence;
 +	alarm.snoozer = alarm_info->snoozer;
 +	alarm.sound_num = alarm_info->sound_num;
 +	alarm.szCommand = mir_tstrdup(alarm_info->szCommand);
 +	alarm.szCommandParams = mir_tstrdup(alarm_info->szCommandParams);
 +	alarm.szDesc = mir_tstrdup(alarm_info->szDesc);
 +	alarm.szTitle = mir_tstrdup(alarm_info->szTitle);
 +	alarm.time = alarm_info->time;
 +
 +	append_to_list(&alarm);
 +	return 0;
 +}
 +
 +int IdleChanged(WPARAM wParam, LPARAM lParam)
 +{
 +	is_idle = (lParam & IDF_ISIDLE);
 +	return 0;
 +}
 +
 +void InitList()
 +{
 +	InitializeCriticalSection(&alarm_cs);
 +
 +	SkinAddNewSoundEx("Triggered1", LPGEN("Alarms"), LPGEN("Alert 1"));
 +	SkinAddNewSoundEx("Triggered2", LPGEN("Alarms"), LPGEN("Alert 2"));
 +	SkinAddNewSoundEx("Triggered3", LPGEN("Alarms"), LPGEN("Alert 3"));
 +
 +	// load last checked time	
 +	DBCONTACTGETSETTING dbcgs;
 +	DBVARIANT dbv;
 +	dbcgs.szModule = MODULE;
 +	dbcgs.szSetting = "LastCheck";
 +	dbcgs.pValue = &dbv;
 +	dbv.type = DBVT_BLOB;
 +	dbv.cpbVal = sizeof(SYSTEMTIME);
 +
 +	if (!CallService(MS_DB_CONTACT_GETSETTING, 0, (LPARAM)&dbcgs)) {
 +		memcpy(&last_check, dbv.pbVal, sizeof(SYSTEMTIME));
 +		DBFreeVariant(&dbv);
 +	} else {
 +		GetLocalTime(&last_check);
 +	}
 +
 +	last_saved_check = last_check;
 +
 +	LoadAlarms();
 +
 +	hAlarmTriggeredEvent = CreateHookableEvent(ME_ALARMS_TRIGGERED);
 +	hAddAlarmService = CreateServiceFunction(MS_ALARMS_ADDALARM, AddAlarmService);
 +
 +	InitAlarmWin();
 +
 +	timer_id = SetTimer(0, 0, TIMER_PERIOD, TimerProc);
 +
 +	HookEvent(ME_IDLE_CHANGED, IdleChanged);
 +}
 +
 +
 +void DeinitList() {
 +
 +	DeinitAlarmWin();
 +
 +	// i don't think this should be necessary, but...
 +	EnterCriticalSection(&alarm_cs);
 +	KillTimer(0, timer_id);
 +	LeaveCriticalSection(&alarm_cs);
 +
 +	DestroyHookableEvent(hAlarmTriggeredEvent);
 +	DestroyServiceFunction(hAddAlarmService);
 +
 +	SaveAlarms(); // we may have erased some 'cause they were once-offs that were triggered
 +
 +	//WriteLastCheckTime(); // moved to the CheckAlarms function - for virt db and general crash problems
 +
 +	// delete this after save alarms above
 +	DeleteCriticalSection(&alarm_cs);
 +
 +}
 +
 diff --git a/plugins/Alarms/src/alarmlist.h b/plugins/Alarms/src/alarmlist.h new file mode 100644 index 0000000000..af8e90b666 --- /dev/null +++ b/plugins/Alarms/src/alarmlist.h @@ -0,0 +1,148 @@ +#ifndef _ALARMLIST_INC
 +#define _ALARMLIST_INC
 +
 +#include "options.h"
 +#include "time_utils.h"
 +#include "alarm_win.h"
 +
 +#include "m_alarms.h"
 +
 +void free_alarm_data(ALARM *alarm);
 +
 +void copy_alarm_data(ALARM *dest, ALARM *src);
 +
 +int MinutesInFuture(SYSTEMTIME time, Occurrence occ);
 +void TimeForMinutesInFuture(int mins, SYSTEMTIME *time);
 +
 +static bool operator<(const ALARM &a1, const ALARM &a2) {
 +	return MinutesInFuture(a1.time, a1.occurrence) < MinutesInFuture(a2.time, a2.occurrence); // less-than inverted 'cause we want ascending order
 +}
 +
 +class AlarmList {
 +public:
 +	AlarmList(): head(0), tail(0), count(0) {}
 +
 +	virtual ~AlarmList() {clear();}
 +
 +	void sort() {
 +		if (count < 2) return;
 +
 +		Node *c1 = head, *c2;
 +		// bubble sort...hey, i'm lazy :)
 +		while(c1) {
 +			c2 = c1->next;
 +			while(c2) {
 +				if (c2->alarm < c1->alarm) {
 +					swap (c1, c2);
 +				}
 +				c2 = c2->next;
 +			}
 +			c1 = c1->next;
 +		}
 +	}
 +
 +	void clear() {
 +		Node *current;
 +		while(head) {
 +			current = head;
 +			head = head->next;
 +			free_alarm_data(¤t->alarm);
 +			delete current;
 +		}
 +		count = 0;
 +		tail = 0;
 +		reset();
 +	}
 +
 +	int size() {return count;}
 +
 +	ALARM &at(int index) {
 +		int i = 0;
 +		Node *current = head;
 +		while(i < index && i < count && current) {
 +			current = current->next;
 +			i++;
 +		}
 +		return current->alarm;
 +	}
 +
 +	void reset() {it_current = head;}
 +	ALARM *current() {return (it_current ? &it_current->alarm : 0);}
 +	void next() {it_current = it_current->next;}
 +	void erase() {
 +		if (it_current) {
 +			if (it_current->next) it_current->next->prev = it_current->prev;
 +			if (it_current->prev) it_current->prev->next = it_current->next;
 +
 +			if (tail == it_current) tail = tail->prev;
 +			if (head == it_current) head = head->next;
 +
 +			free_alarm_data(&it_current->alarm);
 +			delete it_current;
 +			count--;
 +			reset();
 +		}
 +	}
 +
 +	// copies the alarm into the list
 +	void push_back(ALARM *alarm) {
 +		Node *nn = new Node;
 +		memset(&nn->alarm, 0, sizeof(ALARM));
 +		copy_alarm_data(&nn->alarm, alarm);
 +
 +		nn->prev = tail;
 +		if (tail) tail->next = nn;
 +		tail = nn;
 +
 +		if (!head) head = tail;
 +		count++;
 +	}
 +
 +protected:
 +	class Node {
 +	public:
 +		Node(): next(0), prev(0) {}
 +		ALARM alarm;
 +		Node *next, *prev;
 +	};
 +
 +	Node *head, *tail, *it_current;
 +	int count;
 +
 +	void swap(Node *n1, Node *n2) {
 +		ALARM temp = n1->alarm;
 +		n1->alarm = n2->alarm;
 +		n2->alarm = temp;
 +	}
 +};
 +
 +//extern AlarmList alarms;
 +
 +void LoadAlarms();
 +void SaveAlarms();
 +
 +void InitList();
 +void DeinitList();
 +
 +void copy_list(AlarmList ©);
 +void copy_list(AlarmList ©, SYSTEMTIME &start, SYSTEMTIME &end);
 +
 +void set_list(AlarmList ©);
 +
 +void append_to_list(ALARM *alarm);
 +void alter_alarm_list(ALARM *alarm);
 +void remove(unsigned short alarm_id);
 +
 +void suspend(unsigned short alarm_id);
 +
 +void GetPluginTime(SYSTEMTIME *t);
 +
 +// increase 'time' to next occurrence
 +bool UpdateAlarm(SYSTEMTIME &time, Occurrence occ);
 +
 +
 +const ULARGE_INTEGER mult = { 600000000, 0}; // number of 100 microsecond blocks in a minute
 +
 +extern unsigned short next_alarm_id;
 +
 +#endif
 diff --git a/plugins/Alarms/src/alarms.cpp b/plugins/Alarms/src/alarms.cpp new file mode 100644 index 0000000000..c9305afce2 --- /dev/null +++ b/plugins/Alarms/src/alarms.cpp @@ -0,0 +1,326 @@ +/*
 +Miranda plugin template, originally by Richard Hughes
 +http://miranda-icq.sourceforge.net/
 +
 +This file is placed in the public domain. Anybody is free to use or
 +modify it as they wish with no restriction.
 +There is no warranty.
 +*/
 +
 +#include "common.h"
 +#include "alarms.h"
 +
 +
 +#define SERVICENAME _T("mp")
 +#define COMMANDPREFIX _T("/") SERVICENAME
 +
 +#define WMP_PAUSE	32808
 +#define WMP_NEXT	0x497B
 +
 +TCHAR szGamePrefix[] = COMMANDPREFIX;
 +
 +HINSTANCE hInst;
 +int hLangpack;
 +
 +HANDLE hTopToolbarButton;
 +
 +typedef LRESULT (CALLBACK *WNDPROC)(HWND, UINT, WPARAM, LPARAM);
 +
 +//bool right_window = false;
 +WNDPROC old_clist_wndproc;
 +
 +PLUGININFOEX pluginInfo={
 +	sizeof(PLUGININFOEX),
 +	__PLUGIN_NAME,
 +	PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
 +	__DESCRIPTION,
 +	__AUTHOR,
 +	__AUTHOREMAIL,
 +	__COPYRIGHT,
 +	__AUTHORWEB,
 +	UNICODE_AWARE,
 +	{ 0x4dd7762b, 0xd612, 0x4f84, { 0xaa, 0x86, 0x6, 0x8f, 0x17, 0x85, 0x9b, 0x6d } } // {4DD7762B-D612-4f84-AA86-068F17859B6D}
 +};
 +
 +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
 +{
 +	hInst=hinstDLL;
 +	return TRUE;
 +}
 +
 +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
 +{
 +	return &pluginInfo;
 +}
 +
 +static const MUUID interfaces[] = {MIID_ALARMS, MIID_LAST};
 +extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
 +{
 +	return interfaces;
 +}
 +
 +static int CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 +{
 +	switch(message) {
 +		case WM_COMMAND:
 +			if (HIWORD(wParam) == STN_CLICKED) { //It was a click on the Popup.
 +				PUDeletePopUp(hWnd);
 +				return TRUE;
 +			}
 +			break;
 +		case UM_FREEPLUGINDATA: {
 +			//MY_PLUGIN_DATA * mpd = NULL;
 +			//mpd = (MY_PLUGIN_DATA*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd,(LPARAM)mpd);
 +			//if (mdp > 0) free(mpd);
 +			return TRUE; //TRUE or FALSE is the same, it gets ignored.
 +		}
 +		default:
 +			break;
 +	}
 +	return DefWindowProc(hWnd, message, wParam, lParam);
 +}
 +
 +void ShowPopup(HANDLE hContact, const TCHAR *msg) {
 +	if (ServiceExists(MS_POPUP_ADDPOPUP)) {
 +		POPUPDATAT ppd;
 +		TCHAR *lpzContactName;
 +
 +		ZeroMemory(&ppd, sizeof(ppd)); //This is always a good thing to do.
 +		ppd.lchContact = hContact; //Be sure to use a GOOD handle, since this will not be checked.
 +		ppd.lchIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
 +
 +		lpzContactName = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR);
 +	
 +		lstrcpy(ppd.lptzContactName, lpzContactName);
 +		lstrcpy(ppd.lptzText, msg);
 +		ppd.colorBack = GetSysColor(COLOR_BTNFACE);;
 +		ppd.colorText = RGB(0,0,0);
 +		ppd.PluginWindowProc = (WNDPROC)PopupDlgProc;
 +		ppd.PluginData = 0;
 +		ppd.iSeconds = 3;
 +
 +		//Now that every field has been filled, we want to see the popup.
 +		CallService(MS_POPUP_ADDPOPUPEX, (WPARAM)&ppd, 0);
 +	}
 +}
 +
 +static int PluginSendMessage(WPARAM wParam,LPARAM lParam) {
 +	CCSDATA css;
 +	css.hContact = (HANDLE)wParam;
 +	css.szProtoService = PSS_MESSAGE;
 +	css.wParam = 0;
 +	css.lParam = lParam;
 +
 +	CallService(MS_PROTO_CALLCONTACTSERVICE, 0, (LPARAM)&css);
 +	return 0;
 +}
 +
 +static int PluginMessageReceived(WPARAM wParam,LPARAM lParam)
 +{
 +	CCSDATA *pccsd = (CCSDATA *)lParam;
 +	PROTORECVEVENT *ppre = ( PROTORECVEVENT * )pccsd->lParam;
 +	TCHAR *savedMsg;
 +	HWND hWnd;
 +	TCHAR response[256];
 +	
 +	TCHAR msg[1024], buff[1024];
 +
 +	if (_tcsncmp(ppre->tszMessage, szGamePrefix, _tcslen(szGamePrefix)))
 +		return CallService( MS_PROTO_CHAINRECV, wParam, lParam );
 +
 +	_tcscpy(msg, ppre->tszMessage + _tcslen(szGamePrefix));
 +
 +	savedMsg = ppre->tszMessage;
 +	
 +	if (!_tcscmp(msg, _T(" ffw"))) {
 +		mir_sntprintf(buff, SIZEOF(buff), _T("%s"), _T("Fast forward!"));
 +		
 +		hWnd = FindWindow(0, _T("Windows Media Player"));
 +		PostMessage(hWnd, WM_COMMAND, WMP_NEXT, 0);
 +	} else {
 +		mir_sntprintf(buff, SIZEOF(buff), _T("Unknown command issued: \"%s\""), msg);
 +	}
 +	
 +	/*
 +	ppre->szMessage = (char *)Translate(buff);
 +	retval = CallService( MS_PROTO_CHAINRECV, wParam, lParam );
 +	ppre->szMessage = savedMsg;
 +	*/
 +
 +	ShowPopup(pccsd->hContact, buff);
 +
 +	_tcscpy(response, buff);
 +	PluginSendMessage((WPARAM)pccsd->hContact, (LPARAM)response);
 +
 +	return 0;
 +}
 +
 +HBITMAP LoadBmpFromIcon(int IdRes)
 +{
 +	HBITMAP hBmp, hoBmp;
 +    HDC hdc, hdcMem;
 +    HBRUSH hBkgBrush;
 +	HICON hIcon;
 +
 +	hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IdRes));
 +
 +    RECT rc;
 +    BITMAPINFOHEADER bih = {0};
 +    int widthBytes;
 +
 +    hBkgBrush = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
 +    bih.biSize = sizeof(bih);
 +    bih.biBitCount = 24;
 +    bih.biPlanes = 1;
 +    bih.biCompression = BI_RGB;
 +    bih.biHeight = 16;
 +    bih.biWidth = 20; 
 +    widthBytes = ((bih.biWidth*bih.biBitCount + 31) >> 5) * 4;
 +    rc.top = rc.left = 0;
 +    rc.right = bih.biWidth;
 +    rc.bottom = bih.biHeight;
 +    hdc = GetDC(NULL);
 +    hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight);
 +    hdcMem = CreateCompatibleDC(hdc);
 +    hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp);
 +    FillRect(hdcMem, &rc, hBkgBrush);
 +    DrawIconEx(hdcMem, 2, 0, hIcon, 16, 16, 0, NULL, DI_NORMAL);
 +
 +
 +    SelectObject(hdcMem, hoBmp);
 +	DeleteDC(hdcMem);
 +	ReleaseDC(NULL, hdc);
 +	DeleteObject(hBkgBrush);
 +
 +	DeleteObject(hIcon);
 +
 +	return hBmp;
 +}
 +
 +static int InitTopToolbarButton(WPARAM wParam, LPARAM lParam)
 +{
 +	TTBButton ttb = {0};
 +
 +	ttb.cbSize = sizeof(ttb);
 +	ttb.hIconUp = LoadIcon(hInst, MAKEINTRESOURCE(IDI_TBUP));
 +	ttb.hIconDn = LoadIcon(hInst, MAKEINTRESOURCE(IDI_TBDN));
 +	ttb.pszService = MODULE "/NewAlarm";
 +	ttb.dwFlags = TTBBF_VISIBLE;// | TTBBF_DRAWBORDER;
 +	ttb.name = Translate("Set Alarm");
 +	
 +	hTopToolbarButton = (HANDLE)CallService(MS_TTB_ADDBUTTON, (WPARAM)&ttb, 0);
 +	CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTopToolbarButton, (LPARAM)TTBST_RELEASED);
 +
 +	return 0;
 +}
 +
 +static int MainInit(WPARAM wparam,LPARAM lparam) {
 +	if (ServiceExists(MS_UPDATE_REGISTER)) {
 +		// register with updater
 +		Update update = {0};
 +		char szVersion[16];
 +
 +		update.cbSize = sizeof(Update);
 +
 +		update.szComponentName = pluginInfo.shortName;
 +		update.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szVersion);
 +		update.cpbVersion = (int)strlen((char *)update.pbVersion);
 +
 +		update.szUpdateURL = UPDATER_AUTOREGISTER;
 +		
 +		// these are the three lines that matter - the archive, the page containing the version string, and the text (or data) 
 +		// before the version that we use to locate it on the page
 +		// (note that if the update URL and the version URL point to standard file listing entries, the backend xml
 +		// data will be used to check for updates rather than the actual web page - this is not true for beta urls)
 +		update.szBetaUpdateURL = "http://www.scottellis.com.au/miranda_plugins/alarms.zip";
 +		update.szBetaVersionURL = "http://www.scottellis.com.au/miranda_plugins/ver_alarms.html";
 +		update.pbBetaVersionPrefix = (BYTE *)" version ";
 +		
 +		update.cpbBetaVersionPrefix = (int)strlen((char *)update.pbBetaVersionPrefix);
 +
 +		CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update);
 +	}
 +
 +	/*
 +	PROTOCOLDESCRIPTOR pd;
 +	HANDLE hContact;
 +
 +	memset( &pd, 0, sizeof( PROTOCOLDESCRIPTOR ));
 +	pd.cbSize = sizeof( PROTOCOLDESCRIPTOR );
 +	pd.szName = SERVICENAME;
 +	//pd.type = PROTOTYPE_ENCRYPTION - 9;
 +	pd.type = PROTOTYPE_FILTER;
 +	CallService( MS_PROTO_REGISTERMODULE, 0, ( LPARAM ) &pd );
 +
 +	CreateServiceFunction( SERVICENAME PSR_MESSAGE, PluginMessageReceived );
 +
 +	hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
 +
 +	while( hContact )
 +	{
 +		if ( !CallService( MS_PROTO_ISPROTOONCONTACT, ( WPARAM )hContact, ( LPARAM )SERVICENAME ))
 +			CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact, ( LPARAM )SERVICENAME );
 +
 +		hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 );
 +	}
 +	*/
 +
 +	// initialize icons
 +	InitIcons();
 +
 +	// Hotkey
 +	/*
 +	SKINHOTKEYDESCEX hk;
 +	hk.cbSize = sizeof(hk);
 +	hk.pszName = Translate("Set Alarm");
 +	hk.pszDescription = Translate("Set a new alarm");
 +	hk.pszSection = Translate("Alarms");
 +	hk.pszService = MODULE "/NewAlarm";
 +	hk.DefHotKey = (WORD)'A' + HOTKEYF_ALT * 256;
 +	CallService(MS_SKIN_ADDHOTKEY, 0, (LPARAM)&hk);
 +	*/
 +
 +	// TopToolbar support
 +	HookEvent(ME_TTB_MODULELOADED, InitTopToolbarButton);
 +
 +	InitFrames();
 +
 +	// TriggerPlugin support
 +	LoadTriggerSupport();
 +
 +	return 0;
 +}
 +
 +static int MainDeInit(WPARAM wParam, LPARAM lParam)
 +{
 +	DeinitFrames();
 +	DeinitList();
 +	return 0;
 +}
 +
 +extern "C" int __declspec(dllexport) Load(void)
 +{
 +	mir_getLP(&pluginInfo);
 +
 +	// ensure datetime picker is loaded
 +	INITCOMMONCONTROLSEX ccx;
 +	ccx.dwSize = sizeof(ccx);
 +	ccx.dwICC = ICC_DATE_CLASSES;
 +	InitCommonControlsEx(&ccx);
 +
 +	HookEvent(ME_SYSTEM_MODULESLOADED,MainInit);
 +	HookEvent(ME_SYSTEM_PRESHUTDOWN, MainDeInit);
 +
 +	LoadOptions();
 +	InitList();
 +
 +	HookEvent(ME_OPT_INITIALISE, OptInit );
 +
 +	return 0;
 +}
 +
 +extern "C" int __declspec(dllexport) Unload(void)
 +{
 +	return 0;
 +}
 +
 diff --git a/plugins/Alarms/src/alarms.h b/plugins/Alarms/src/alarms.h new file mode 100644 index 0000000000..94b171d867 --- /dev/null +++ b/plugins/Alarms/src/alarms.h @@ -0,0 +1,11 @@ +#ifndef _TESTPLUG_INC
 +#define _TESTPLUG_INC
 +
 +//#include "win.h"
 +#include "alarmlist.h"
 +#include "options.h"
 +#include "frame.h"
 +#include "trigger.h"
 +
 +
 +#endif
 diff --git a/plugins/Alarms/src/common.h b/plugins/Alarms/src/common.h new file mode 100644 index 0000000000..36ac58ea3b --- /dev/null +++ b/plugins/Alarms/src/common.h @@ -0,0 +1,71 @@ +#ifndef _COMMON_INC
 +#define _COMMON_INC
 +
 +
 +#define _WIN32_WINNT 	0x0500
 +#define _WIN32_IE 		0x0400
 +
 +#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
 +#define VC_EXTRALEAN
 +
 +#include <windows.h>
 +#include <shellapi.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <commctrl.h>
 +
 +#include <newpluginapi.h>
 +#include <m_system.h>
 +#include <m_database.h>
 +#include <m_options.h>
 +#include <m_skin.h>
 +#include <m_contacts.h>
 +#include <m_protomod.h>
 +#include <m_protosvc.h>
 +#include <m_langpack.h>
 +#include <m_popup.h>
 +#include <m_utils.h>
 +#include <m_idle.h>
 +#include <m_clist.h>
 +#include <m_clui.h>
 +#include <m_clc.h>
 +#include <m_cluiframes.h>
 +#include <m_genmenu.h>
 +#include <m_fontservice.h>
 +#include <m_icolib.h>
 +#include <win2k.h>
 +
 +#include <m_toptoolbar.h>
 +#include <m_trigger.h>
 +#include <m_updater.h>
 +#include <m_alarms.h>
 +
 +#include "resource.h"
 +#include "version.h"
 +
 +#define MODULE	"Alarm"
 +
 +extern HINSTANCE hInst;
 +
 +extern HANDLE hTopToolbarButton;
 +
 +typedef struct ALARM_tag {
 +	unsigned short id;
 +	TCHAR *szTitle;
 +	TCHAR *szDesc;
 +	Occurrence occurrence;
 +	BOOL snoozer;
 +	SYSTEMTIME time;
 +	unsigned short action;
 +	TCHAR *szCommand;
 +	TCHAR *szCommandParams;
 +	BYTE sound_num;
 +	int flags;
 +	DWORD trigger_id;
 +} ALARM;
 +
 +#ifndef MIID_ALARMS
 +#define MIID_ALARMS		{0x60ebaad1, 0x8d95, 0x4966, { 0x8b, 0xe3, 0xb1, 0xed, 0xaf, 0xa2, 0x11, 0xab}}
 +#endif
 +
 +#endif
 diff --git a/plugins/Alarms/src/frame.cpp b/plugins/Alarms/src/frame.cpp new file mode 100644 index 0000000000..6ebb459026 --- /dev/null +++ b/plugins/Alarms/src/frame.cpp @@ -0,0 +1,667 @@ +#include "common.h"
 +#include "frame.h"
 +
 +HWND hwnd_plugin = 0;
 +HWND hwnd_frame = 0;
 +HWND hwnd_list = 0;
 +
 +int frame_id = -1;
 +
 +FontID font_id;
 +ColourID framebk_colour_id;
 +HFONT hFont = 0;
 +COLORREF fontColour, framebk;
 +HBRUSH bk_brush = 0;
 +
 +AlarmList alarm_list;
 +CRITICAL_SECTION list_cs;
 +
 +HANDLE hMenuShowReminders = 0;
 +
 +#define ID_FRAME_UPDATE_TIMER						1011
 +#define ID_FRAME_SHOWHIDE_TIMER						1012
 +
 +#define WMU_FILL_LIST		(WM_USER + 10)
 +#define WMU_SIZE_LIST		(WM_USER + 11)
 +#define WMU_INITIALIZE		(WM_USER + 12)
 +
 +void FixMainMenu();
 +
 +int height_client_to_frame(int client_height, LONG style, LONG ex_style) {
 +	RECT tr;
 +	tr.top = tr.right = tr.left = 0;
 +	tr.bottom = client_height;
 +	if (AdjustWindowRectEx(&tr, style, FALSE, ex_style))
 +		return tr.bottom - tr.top;
 +	return 0;
 +}
 +
 +LRESULT CALLBACK FrameContainerWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
 +	switch(msg) {
 +		case WM_CREATE:
 +			return TRUE;
 +		case WM_SHOWWINDOW:
 +			if ((BOOL)wParam) {
 +				DBWriteContactSettingByte(0, MODULE, "ReminderFrameVisible", 1);
 +				Utils_RestoreWindowPosition(hwnd, 0, MODULE, "reminders_window");
 +				PostMessage(hwnd, WM_SIZE, 0, 0);
 +			} else {
 +				DBWriteContactSettingByte(0, MODULE, "ReminderFrameVisible", 0);
 +				Utils_SaveWindowPosition(hwnd, 0, MODULE, "reminders_window");
 +			}
 +			break;
 +		case WM_SIZE:
 +			{
 +				HWND child = (HWND)GetWindowLongPtr(hwnd, GWLP_USERDATA);
 +				RECT r;
 +				GetClientRect(hwnd, &r);
 +
 +				SetWindowPos(child, 0, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE);
 +				InvalidateRect(child, 0, TRUE);
 +				InvalidateRect(hwnd, 0, TRUE);
 +			}
 +			break;
 +
 +		case WM_CLOSE:
 +			Utils_SaveWindowPosition(hwnd, 0, MODULE, "reminders_window");
 +			ShowWindow(hwnd, SW_HIDE);
 +			FixMainMenu();
 +			return TRUE;
 +	}
 +
 +	return DefWindowProc(hwnd, msg, wParam, lParam);
 +}
 +
 +bool FrameIsFloating() {
 +	if (frame_id == -1) 
 +		return true; // no frames, always floating
 +	
 +	return (CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLOATING, frame_id), 0) != 0);
 +}
 +
 +ALARM context_menu_alarm = {0};
 +
 +LRESULT CALLBACK FrameWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
 +	MEASUREITEMSTRUCT *mis;
 +	DRAWITEMSTRUCT *dis;
 +	SIZE textSize;
 +	SIZE timeSize;
 +
 +	switch(msg) {
 +
 +		case WM_CREATE: 
 +			{
 +				hwnd_list = CreateWindow(_T("LISTBOX"), _T(""),
 +					(WS_VISIBLE | WS_CHILD | LBS_NOINTEGRALHEIGHT | LBS_STANDARD | LBS_NOTIFY | LBS_OWNERDRAWFIXED) & ~LBS_SORT
 +					& ~WS_BORDER, 0, 0, 0, 0, hwnd, NULL, hInst,0);		
 +			}
 +			return FALSE;
 +		case WMU_INITIALIZE:
 +			PostMessage(hwnd, WMU_FILL_LIST, 0, 0);
 +			SetTimer(hwnd, ID_FRAME_UPDATE_TIMER, 5000, 0);
 +			SetTimer(hwnd, ID_FRAME_SHOWHIDE_TIMER, 200, 0);
 +			return TRUE;
 +
 +		case WM_MEASUREITEM:
 +			mis = (MEASUREITEMSTRUCT *)lParam;
 +			mis->itemHeight = options.row_height;
 +			return TRUE;
 +
 +		case WM_DRAWITEM:
 +			dis = (DRAWITEMSTRUCT *)lParam;
 +			if (dis->itemID != (DWORD)-1) {
 +				ALARM alarm = {0};
 +				EnterCriticalSection(&list_cs);
 +				ALARM &list_alarm = alarm_list.at(dis->itemData);
 +				copy_alarm_data(&alarm, &list_alarm);
 +				LeaveCriticalSection(&list_cs);
 +
 +				RECT r;
 +				GetClientRect(hwnd, &r);
 +
 +				int min = MinutesInFuture(alarm.time, alarm.occurrence);
 +
 +				FillRect(dis->hDC, &dis->rcItem, bk_brush);
 +
 +				dis->rcItem.left += options.indent;
 +
 +				SetBkMode(dis->hDC, TRANSPARENT);
 +				SetTextColor(dis->hDC, fontColour);
 +
 +				HICON hIcon = (min <= 5 ? hIconList2 : hIconList1);
 +				//DrawIconEx(dis->hDC,dis->rcItem.left,(dis->rcItem.top + dis->rcItem.bottom -GetSystemMetrics(SM_CYSMICON))>>1,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
 +				DrawIconEx(dis->hDC,dis->rcItem.left,(dis->rcItem.top + dis->rcItem.bottom - 16)>>1,hIcon,0, 0, 0, NULL, DI_NORMAL);
 +
 +				GetTextExtentPoint32(dis->hDC,alarm.szTitle,lstrlen(alarm.szTitle),&textSize);
 +
 +				TCHAR buff[100];
 +				if (min >= 60) {
 +					mir_sntprintf(buff, 100, TranslateT("%dh %dm"), min / 60, min % 60);
 +				} else {
 +					mir_sntprintf(buff, 100, TranslateT("%dm"), min);
 +				}
 +
 +				GetTextExtentPoint32(dis->hDC,buff,lstrlen(buff),&timeSize);
 +
 +				if (textSize.cx > (dis->rcItem.right - dis->rcItem.left) - (GetSystemMetrics(SM_CXSMICON) + 4) - timeSize.cx - 2 - 4) {
 +					// need elipsis
 +					TCHAR titlebuff[512];
 +					int len = lstrlen(alarm.szTitle);
 +					if (len > 511) len = 511;
 +					while(len > 0 && textSize.cx > (dis->rcItem.right - dis->rcItem.left) - (GetSystemMetrics(SM_CXSMICON) + 4) - timeSize.cx - 2 - 4) {
 +						len--;
 +						_tcsncpy(titlebuff, alarm.szTitle, len);
 +						titlebuff[len] = 0;
 +						_tcscat(titlebuff, _T("..."));
 +						GetTextExtentPoint32(dis->hDC,titlebuff,lstrlen(titlebuff),&textSize);
 +					}
 +					TextOut(dis->hDC,dis->rcItem.left + 16 + 4,(dis->rcItem.top + dis->rcItem.bottom - textSize.cy)>>1,titlebuff,lstrlen(titlebuff));
 +					TextOut(dis->hDC,dis->rcItem.right - timeSize.cx - 2,(dis->rcItem.top + dis->rcItem.bottom - timeSize.cy)>>1, buff,lstrlen(buff));
 +				} else {				
 +					TextOut(dis->hDC,dis->rcItem.left + 16 + 4,(dis->rcItem.top + dis->rcItem.bottom - textSize.cy)>>1,alarm.szTitle,lstrlen(alarm.szTitle));
 +					TextOut(dis->hDC,dis->rcItem.right - timeSize.cx - 2,(dis->rcItem.top + dis->rcItem.bottom - timeSize.cy)>>1, buff,lstrlen(buff));
 +				}
 +
 +				SetBkMode(dis->hDC, OPAQUE);
 +
 +				free_alarm_data(&alarm);
 +			} else {				
 +				FillRect(dis->hDC, &dis->rcItem, bk_brush);
 +			}
 +			return TRUE;
 +
 +		case WM_CTLCOLORLISTBOX:
 +			break;
 +		case WM_ERASEBKGND:
 +			{
 +				HDC hdc = (HDC)wParam;
 +				RECT r;
 +				GetClientRect(hwnd, &r);
 +				FillRect(hdc, &r, bk_brush);
 +			}
 +			return TRUE;
 +
 +		case WM_PRINTCLIENT:
 +			{
 +				/*
 +				HDC hdc = (HDC)wParam;
 +				RECT r;
 +				GetClientRect(hwnd, &r);
 +				*/
 +			}
 +			return TRUE;
 +
 +		case WM_PAINT:
 +			{
 +				RECT r;
 +				if (GetUpdateRect(hwnd, &r, FALSE)) {
 +					PAINTSTRUCT ps;
 +					HDC hdc = BeginPaint(hwnd, &ps);
 +					SendMessage(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, (LPARAM)(PRF_CLIENT | PRF_CHILDREN));
 +					EndPaint(hwnd, &ps);
 +				}
 +			}
 +			return TRUE;
 +
 +		case WM_SHOWWINDOW:
 +			if ((BOOL)wParam) PostMessage(hwnd, WMU_SIZE_LIST, 0, 0);
 +			break;
 +
 +		case WM_SIZE:
 +			if (IsWindowVisible(hwnd)) {
 +				SendMessage(hwnd, WMU_SIZE_LIST, 0, 0);
 +			
 +				if (frame_id != -1) {
 +					//CallService(MS_CLIST_FRAMES_UPDATEFRAME, (WPARAM)frame_id, (LPARAM)(FU_TBREDRAW | FU_FMREDRAW));
 +					CallService(MS_CLIST_FRAMES_UPDATEFRAME, (WPARAM)frame_id, (LPARAM)FU_TBREDRAW);
 +				}
 +				InvalidateRect(hwnd, 0, TRUE);
 +			}
 +			break;
 +
 +		case WMU_SIZE_LIST:
 +			{
 +				if (SendMessage(hwnd_list, LB_GETITEMHEIGHT, 0, 0) != options.row_height)
 +					SendMessage(hwnd_list, LB_SETITEMHEIGHT, 0, options.row_height);
 +
 +				int itemheight = SendMessage(hwnd_list, LB_GETITEMHEIGHT, 0, 0),
 +					count = SendMessage(hwnd_list, LB_GETCOUNT, 0, 0);
 +				
 +				if (options.auto_size_vert && IsWindowVisible(hwnd)) {
 +					if (FrameIsFloating()) {
 +						
 +#define CLUIFrameTitleBarClassName				"CLUIFrameTitleBar"
 +						
 +						int height = height_client_to_frame(itemheight * count, GetWindowLongPtr(GetParent(hwnd), GWL_STYLE), GetWindowLongPtr(GetParent(hwnd), GWL_EXSTYLE));
 +						HWND titleBarHwnd = FindWindowEx(GetParent(hwnd), 0, _T(CLUIFrameTitleBarClassName), 0);
 +						if (titleBarHwnd) {
 +							RECT tbr;
 +							GetWindowRect(titleBarHwnd, &tbr);
 +							height += (tbr.bottom - tbr.top);
 +						}
 +						RECT rp_window;
 +						GetWindowRect(GetParent(hwnd), &rp_window);
 +						SetWindowPos(GetParent(hwnd), 0, 0, 0, rp_window.right - rp_window.left, height, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
 +
 +						/*
 +						RECT rp_client, rp_window, r_window;
 +						GetClientRect(GetParent(hwnd), &rp_client);
 +						GetWindowRect(GetParent(hwnd), &rp_window);
 +						GetWindowRect(hwnd, &r_window);
 +						int diff = (rp_window.bottom - rp_window.top) - (rp_client.bottom - rp_client.top);
 +						if (ServiceExists(MS_CLIST_FRAMES_ADDFRAME))
 +							diff += rp_window.top - r_window.top;
 +						SetWindowPos(GetParent(hwnd), 0, 0, 0, rp_window.right - rp_window.left, count * itemheight + diff, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
 +						*/
 +					} else if (ServiceExists(MS_CLIST_FRAMES_ADDFRAME) && frame_id != -1) {
 +						int flags = CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, frame_id), 0);
 +						CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS, MAKEWPARAM(FO_HEIGHT, frame_id), (LPARAM)(count * itemheight));
 +						CallService(MS_CLIST_FRAMES_UPDATEFRAME, (WPARAM)frame_id, (LPARAM)(FU_TBREDRAW | FU_FMREDRAW | FU_FMPOS));
 +					}
 +				}
 +
 +				RECT r, r2;
 +				GetClientRect(hwnd, &r);
 +				GetClientRect(hwnd_list, &r2);
 +				int width, height, winheight;
 +
 +				width = r.right - r.left;
 +				winheight = r.bottom - r.top;
 +
 +				height = min(count * itemheight, winheight - (winheight % itemheight));
 +				if (r2.right - r2.left != width || (r.bottom - r.top > 0 && r2.bottom - r2.top != height)) {
 +					SetWindowPos(hwnd_list, 0, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
 +					InvalidateRect(hwnd_list, 0, FALSE);
 +				}
 +				
 +				if (options.auto_showhide) {
 +					if (ServiceExists(MS_CLIST_FRAMES_SHFRAME) && frame_id != -1) {
 +						if (IsWindowVisible(hwnd) && count == 0) {
 +							CallService(MS_CLIST_FRAMES_SHFRAME, (WPARAM)frame_id, 0);
 +						} else if (!IsWindowVisible(hwnd) && count > 0) {
 +							// we have reminders - show if not linked to clist or if clist is visible
 +							if ((!options.hide_with_clist && FrameIsFloating()) || IsWindowVisible((HWND)CallService(MS_CLUI_GETHWND, 0, 0))) {
 +								CallService(MS_CLIST_FRAMES_SHFRAME, (WPARAM)frame_id, 0);						
 +								CallService(MS_CLIST_FRAMES_UPDATEFRAME, (WPARAM)frame_id, (LPARAM)(FU_FMREDRAW | FU_FMPOS));
 +							}
 +						}
 +					} else {
 +						if (IsWindowVisible(hwnd) && count == 0)
 +							SetReminderFrameVisible(false);
 +						else if (!IsWindowVisible(hwnd) && count > 0)
 +							// we have reminders - show if not linked to clist or if clist is visible
 +							if (!options.hide_with_clist || IsWindowVisible((HWND)CallService(MS_CLUI_GETHWND, 0, 0)))
 +								SetReminderFrameVisible(true);
 +					}
 +				}
 +				
 +			}
 +			return TRUE;
 +		case WMU_FILL_LIST:
 +			{
 +				// calculate the period to display alarms for
 +				SYSTEMTIME t1, t2;
 +				GetLocalTime(&t1);
 +				TimeForMinutesInFuture(60 * options.reminder_period, &t2);
 +
 +				int sel = SendMessage(hwnd_list, LB_GETCURSEL, 0, 0),
 +					top = SendMessage(hwnd_list, LB_GETTOPINDEX, 0, 0);
 +
 +				SendMessage(hwnd_list, WM_SETREDRAW, (WPARAM)FALSE, 0);
 +
 +				EnterCriticalSection(&list_cs);
 +				SendMessage(hwnd_list, LB_RESETCONTENT, 0, 0);
 +				copy_list(alarm_list, t1, t2);
 +				alarm_list.sort();
 +				int index = 0;
 +				ALARM *i;
 +				for(alarm_list.reset(); i = alarm_list.current(); alarm_list.next(), index++) {
 +					if (i->flags & (ALF_HIDDEN | ALF_SUSPENDED | ALF_NOREMINDER))
 +						continue;
 +					SendMessage(hwnd_list, LB_ADDSTRING, 0, (LPARAM)index);
 +				}
 +				LeaveCriticalSection(&list_cs);
 +
 +				SendMessage(hwnd, WMU_SIZE_LIST, 0, 0);
 +				SendMessage(hwnd_list, WM_SETREDRAW, (WPARAM)TRUE, 0);
 +
 +				if (sel != LB_ERR && sel < index) SendMessage(hwnd_list, LB_SETCURSEL, (WPARAM)sel, 0);
 +				if (top != LB_ERR && top < index) SendMessage(hwnd_list, LB_SETTOPINDEX, (WPARAM)top, 0);
 +
 +			}
 +			return TRUE;
 +		
 +		case WM_TIMER:
 +			if (wParam == ID_FRAME_UPDATE_TIMER)
 +				SendMessage(hwnd, WMU_FILL_LIST, 0, 0);
 +			else if (wParam == ID_FRAME_SHOWHIDE_TIMER && options.hide_with_clist) { // link show/hide with clist
 +				// hide if we're visible and clist isn't (possible only when floating if frames are present)
 +				if (!IsWindowVisible((HWND)CallService(MS_CLUI_GETHWND, 0, 0)) && IsWindowVisible(hwnd)) {
 +					if (ServiceExists(MS_CLIST_FRAMES_SHFRAME))
 +						CallService(MS_CLIST_FRAMES_SHFRAME, (WPARAM)frame_id, 0);
 +					else
 +						SetReminderFrameVisible(false);
 +				}
 +				// we're not visible but clist is - show depending on hide_with_clist and auto_showhide options
 +				if (!IsWindowVisible(hwnd) && IsWindowVisible((HWND)CallService(MS_CLUI_GETHWND, 0, 0))) {
 +					// if not auto show/hide, show (reminders or not) if we're not visible and the clist is
 +					// otherwise, show only if there are reminders
 +					int count = SendMessage(hwnd_list, LB_GETCOUNT, 0, 0);
 +					if (!options.auto_showhide || count > 0) {
 +						if (ServiceExists(MS_CLIST_FRAMES_SHFRAME))
 +							CallService(MS_CLIST_FRAMES_SHFRAME, (WPARAM)frame_id, 0);
 +						else
 +							SetReminderFrameVisible(true);
 +					}
 +				}
 +			}
 +			return TRUE;
 +
 +		case WM_CONTEXTMENU:
 +			{
 +				/*
 +				*/
 +				POINT pt;
 +				GetCursorPos(&pt);
 +				ScreenToClient(hwnd_list, &pt);
 +
 +				EnterCriticalSection(&list_cs);
 +				DWORD item = SendMessage(hwnd_list, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y));
 +
 +				HMENU menu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1)), submenu = GetSubMenu(menu, 0);
 +				TranslateMenu(submenu);
 +	
 +				if (HIWORD(item) == 0) {
 +					int sel = LOWORD(item);
 +					if (sel >= 0) {
 +						// one-off alarms can't be suspended
 +						int index = SendMessage(hwnd_list, LB_GETITEMDATA, (WPARAM)sel, 0);
 +						ALARM &list_alarm = alarm_list.at(index);
 +						copy_alarm_data(&context_menu_alarm, &list_alarm);
 +						if (context_menu_alarm.occurrence == OC_ONCE)
 +							EnableMenuItem(submenu, ID_REMINDERFRAMECONTEXT_SUSPEND, MF_BYCOMMAND | MF_GRAYED);
 +
 +					}
 +				} else {
 +					EnableMenuItem(submenu, ID_REMINDERFRAMECONTEXT_SUSPEND, MF_BYCOMMAND | MF_GRAYED);
 +					EnableMenuItem(submenu, ID_REMINDERFRAMECONTEXT_EDIT, MF_BYCOMMAND | MF_GRAYED);
 +					EnableMenuItem(submenu, ID_REMINDERFRAMECONTEXT_DELETE, MF_BYCOMMAND | MF_GRAYED);
 +				}
 +				LeaveCriticalSection(&list_cs);
 +
 +				//ClientToScreen(hwnd_list, &pt);
 +				GetCursorPos(&pt);
 +				
 +				BOOL ret = TrackPopupMenu(submenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL);
 +				DestroyMenu(menu);
 +				if (ret) PostMessage(hwnd, WM_COMMAND, ret, 0);
 +			}
 +			return TRUE;
 +
 +		case WM_COMMAND:
 +			switch(LOWORD(wParam)) {
 +				case ID_REMINDERFRAMECONTEXT_OPTIONS:
 +					{
 +						OPENOPTIONSDIALOG oop;
 +						oop.cbSize = sizeof(oop);
 +						oop.pszGroup = Translate("Events");
 +						oop.pszPage = Translate("Alarms");
 +						oop.pszTab = 0;
 +						CallService(MS_OPT_OPENOPTIONS, 0, (LPARAM)&oop);
 +					}
 +					break;
 +				case ID_REMINDERFRAMECONTEXT_SUSPEND:
 +					if (context_menu_alarm.occurrence != OC_ONCE) {
 +						suspend(context_menu_alarm.id);
 +						PostMessage(hwnd, WMU_FILL_LIST, 0, 0);
 +						if (hwndOptionsDialog) {
 +							// refresh options list
 +							PostMessage(hwndOptionsDialog, WMU_INITOPTLIST, 0, 0);
 +						}
 +					}
 +					break;
 +				case ID_REMINDERFRAMECONTEXT_EDIT:
 +					EditNonModal(context_menu_alarm);
 +					break;
 +				case ID_REMINDERFRAMECONTEXT_DELETE:
 +					remove(context_menu_alarm.id);
 +					PostMessage(hwnd, WMU_FILL_LIST, 0, 0);
 +					if (hwndOptionsDialog) {
 +						// refresh options list
 +						PostMessage(hwndOptionsDialog, WMU_INITOPTLIST, 0, 0);
 +					}
 +					break;
 +
 +				case ID_REMINDERFRAMECONTEXT_NEWALARM:
 +					NewAlarmMenuFunc(0, 0);
 +					break;
 +			}			
 +			return TRUE;
 +
 +		case WM_DESTROY:
 +			KillTimer(hwnd, ID_FRAME_UPDATE_TIMER);
 +			KillTimer(hwnd, ID_FRAME_SHOWHIDE_TIMER);
 +			free_alarm_data(&context_menu_alarm);
 +			break;
 +	}
 +
 +	return DefWindowProc(hwnd, msg, wParam, lParam);
 +}
 +
 +int ReloadFont(WPARAM wParam, LPARAM lParam)
 +{
 +	DeleteObject(hFont);
 +
 +	LOGFONT log_font;
 +	fontColour = CallService(MS_FONT_GET, (WPARAM)&font_id, (LPARAM)&log_font);
 +	hFont = CreateFontIndirect(&log_font);
 +	SendMessage(hwnd_list, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);
 +
 +	DeleteObject(bk_brush);
 +	bk_brush = CreateSolidBrush(DBGetContactSettingDword(0, "Alarm", "clFrameBack", GetSysColor(COLOR_3DFACE)));
 +	RefreshReminderFrame();
 +
 +	return 0;
 +}
 +
 +void FixMainMenu()
 +{
 +	CLISTMENUITEM mi = {0};
 +	mi.cbSize = sizeof(CLISTMENUITEM);
 +	if (!ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) {
 +		if (options.hide_with_clist || options.auto_showhide)
 +			mi.flags = CMIM_FLAGS | CMIF_GRAYED;
 +		else {
 +			mi.flags = CMIM_NAME | CMIM_FLAGS;
 +
 +			if (ReminderFrameVisible())
 +				mi.pszName = Translate("Hide Reminders");
 +			else
 +				mi.pszName = Translate("Show Reminders");
 +		}
 +	}
 +	CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuShowReminders, (LPARAM)&mi);
 +}
 +
 +/////////////////////////
 +// only used when no multiwindow functionality is available
 +bool ReminderFrameVisible()
 +{
 +	return IsWindowVisible(hwnd_frame) ? true : false;
 +}
 +
 +void SetReminderFrameVisible(bool visible)
 +{
 +	if (frame_id == -1 && hwnd_frame != 0) 
 +		ShowWindow(hwnd_frame, visible ? SW_SHOW : SW_HIDE);
 +}
 +
 +INT_PTR ShowHideMenuFunc(WPARAM wParam, LPARAM lParam)
 +{
 +	if (ReminderFrameVisible())
 +		SendMessage(hwnd_frame, WM_CLOSE, 0, 0);
 +	else
 +		ShowWindow(hwnd_frame, SW_SHOW);
 +
 +	FixMainMenu();
 +	return 0;
 +}
 +//////////////////////////////
 +
 +int CreateFrame() 
 +{
 +	WNDCLASS wndclass;
 +	wndclass.style         = 0;
 +	wndclass.lpfnWndProc   = FrameWindowProc;
 +	wndclass.cbClsExtra    = 0;
 +	wndclass.cbWndExtra    = 0;
 +	wndclass.hInstance     = hInst;
 +	wndclass.hIcon         = NULL;
 +	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
 +	wndclass.hbrBackground = 0; //(HBRUSH)(COLOR_3DFACE+1);
 +	wndclass.lpszMenuName  = NULL;
 +	wndclass.lpszClassName = _T("AlarmsFrame");
 +	RegisterClass(&wndclass);
 +
 +	if (ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) {
 +
 +		hwnd_plugin = CreateWindow(_T("AlarmsFrame"), TranslateT("Alarms"), 
 +			WS_CHILD | WS_CLIPCHILDREN, 
 +			0,0,10,10, (HWND)CallService(MS_CLUI_GETHWND, 0, 0), NULL,hInst,NULL);
 +
 +		CLISTFrame Frame = {0};
 +		
 +		Frame.cbSize=sizeof(CLISTFrame);
 +		Frame.name = Frame.TBname = Translate("Alarms");
 +		Frame.hWnd=hwnd_plugin;
 +		Frame.align=alBottom;
 +		Frame.Flags=F_VISIBLE|F_SHOWTB|F_SHOWTBTIP;
 +		Frame.height=30;
 +
 +		frame_id=CallService(MS_CLIST_FRAMES_ADDFRAME,(WPARAM)&Frame,0);
 +	} else {
 +		wndclass.style         = 0;//CS_HREDRAW | CS_VREDRAW;
 +		wndclass.lpfnWndProc   = FrameContainerWindowProc;
 +		wndclass.cbClsExtra    = 0;
 +		wndclass.cbWndExtra    = 0;
 +		wndclass.hInstance     = hInst;
 +		wndclass.hIcon         = NULL;
 +		wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
 +		wndclass.hbrBackground = 0; //(HBRUSH)(COLOR_3DFACE+1);
 +		wndclass.lpszMenuName  = NULL;
 +		wndclass.lpszClassName = _T("AlarmsFrameContainer");
 +		RegisterClass(&wndclass);
 +
 +		hwnd_frame = CreateWindowEx(WS_EX_TOOLWINDOW, _T("AlarmsFrameContainer"), TranslateT("Alarms"), 
 +			(WS_POPUPWINDOW | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN) & ~WS_VISIBLE,
 +			0,0,200,100, (HWND)CallService(MS_CLUI_GETHWND, 0, 0), NULL,hInst,NULL);
 +			//0,0,200,100, GetDesktopWindow(), NULL,hInst,NULL);
 +	
 +		hwnd_plugin = CreateWindow(_T("AlarmsFrame"), TranslateT("Alarms"), 
 +			WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
 +			0,0,10,10, hwnd_frame, NULL,hInst,NULL);
 +
 +		SetWindowLongPtr(hwnd_frame, GWLP_USERDATA, (LONG)hwnd_plugin);
 +
 +		///////////////////////
 +		// create menu item
 +		CreateServiceFunction(MODULE "/ShowHideReminders", ShowHideMenuFunc);
 +
 +		CLISTMENUITEM mi = {0};
 +
 +		mi.cbSize=sizeof(mi);
 +		mi.flags = CMIM_ALL;
 +
 +		mi.hIcon=hIconMenuShowHide;
 +		mi.pszName = Translate("Show Reminders");
 +		mi.pszService= MODULE "/ShowHideReminders";
 +		mi.pszPopupName = Translate("Alarms");
 +		mi.position = 500010000;
 +		hMenuShowReminders = Menu_AddMainMenuItem(&mi);
 +		/////////////////////
 +
 +		if (!options.auto_showhide) {
 +			if (options.hide_with_clist) {
 +				if (IsWindowVisible((HWND)CallService(MS_CLUI_GETHWND, 0, 0))) {
 +					ShowWindow(hwnd_frame, SW_SHOW);
 +					RefreshReminderFrame();
 +				} else {
 +					ShowWindow(hwnd_frame, SW_HIDE);
 +				}
 +			} else {
 +				if (DBGetContactSettingByte(0, MODULE, "ReminderFrameVisible", 1) == 1) {
 +					ShowWindow(hwnd_frame, SW_SHOW);
 +					RefreshReminderFrame();
 +				} else {
 +					ShowWindow(hwnd_frame, SW_HIDE);
 +				}
 +			}
 +		}
 +
 +		FixMainMenu();
 +	}
 +
 +	SendMessage(hwnd_plugin, WMU_INITIALIZE, 0, 0);
 +
 +	font_id.cbSize = sizeof(font_id);
 +	strncpy(font_id.group, LPGEN("Frames"), sizeof(font_id.group));
 +	strncpy(font_id.name, LPGEN("Alarm Reminders"), sizeof(font_id.name));
 +	strncpy(font_id.dbSettingsGroup, MODULE, sizeof(font_id.dbSettingsGroup));
 +	strncpy(font_id.prefix, "Font", sizeof(font_id.prefix));
 +	font_id.order = 0;
 +	FontRegister(&font_id);
 +
 +	framebk_colour_id.cbSize = sizeof(ColourID);
 +	strcpy(framebk_colour_id.dbSettingsGroup, MODULE);
 +	strcpy(framebk_colour_id.group, LPGEN("Frames"));
 +	strcpy(framebk_colour_id.name, LPGEN("Alarm Reminders"));
 +	strcpy(framebk_colour_id.setting, "clFrameBack");
 +	framebk_colour_id.defcolour = GetSysColor(COLOR_3DFACE);
 +	framebk_colour_id.flags = 0;
 +	framebk_colour_id.order = 0;
 +	ColourRegister(&framebk_colour_id);
 +
 +	LOGFONT log_font;
 +	fontColour = CallService(MS_FONT_GET, (WPARAM)&font_id, (LPARAM)&log_font);
 +	hFont = CreateFontIndirect(&log_font);
 +	SendMessage(hwnd_list, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);
 +	
 +	HookEvent(ME_FONT_RELOAD, ReloadFont);
 +
 +	// create the brush used for the background in the absence of clist_modern skinning features - match clist
 +	bk_brush = CreateSolidBrush(DBGetContactSettingDword(0, "Alarm", "clFrameBack", GetSysColor(COLOR_3DFACE)));
 +
 +	SendMessage(hwnd_list, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);
 +
 +	return 0;
 +}
 +
 +void RefreshReminderFrame() {
 +	SendMessage(hwnd_plugin, WMU_FILL_LIST, 0, 0);
 +
 +	if (frame_id == -1) {
 +		InvalidateRect(hwnd_frame, 0, TRUE);
 +	} else
 +		InvalidateRect(hwnd_plugin, 0, TRUE);
 +
 +}
 +
 +void InitFrames()
 +{
 +	InitializeCriticalSection(&list_cs);
 +	CreateFrame();
 +}
 +
 +void DeinitFrames()
 +{
 +	if (ServiceExists(MS_CLIST_FRAMES_REMOVEFRAME)) {
 +		CallService(MS_CLIST_FRAMES_REMOVEFRAME, (WPARAM)frame_id, 0);
 +	}
 +	DestroyWindow(hwnd_plugin);
 +	if (hwnd_frame) DestroyWindow(hwnd_frame);
 +
 +	DeleteObject(bk_brush);
 +
 +	DeleteCriticalSection(&list_cs);
 +}
 +
 diff --git a/plugins/Alarms/src/frame.h b/plugins/Alarms/src/frame.h new file mode 100644 index 0000000000..9333c31b7d --- /dev/null +++ b/plugins/Alarms/src/frame.h @@ -0,0 +1,20 @@ +#ifndef _FRAME_INC
 +#define _FRAME_INC
 +
 +#include "alarmlist.h"
 +#include "icons.h"
 +#include "options.h"
 +
 +void RefreshReminderFrame();
 +
 +void InitFrames();
 +void DeinitFrames();
 +
 +// update 'show/hide reminder frame' menu item
 +void FixMainMenu();
 +
 +// used when no multiwindow functionality avaiable
 +bool ReminderFrameVisible();
 +void SetReminderFrameVisible(bool visible);
 +
 +#endif
 diff --git a/plugins/Alarms/src/icons.cpp b/plugins/Alarms/src/icons.cpp new file mode 100644 index 0000000000..5a07541e27 --- /dev/null +++ b/plugins/Alarms/src/icons.cpp @@ -0,0 +1,71 @@ +#include "common.h"
 +#include "icons.h"
 +
 +HANDLE hIcoLibIconsChanged;
 +
 +HICON hIconMenuSet, hIconList1, hIconList2, hIconMenuShowHide, hIconSystray;
 +
 +int ReloadIcons(WPARAM wParam, LPARAM lParam)
 +{
 +	hIconMenuSet = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"alarms_menu_set");
 +	hIconList1 = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"alarms_list1");
 +	hIconList2 = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"alarms_list2");
 +	if (!ServiceExists(MS_CLIST_FRAMES_ADDFRAME))
 +		hIconMenuShowHide = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"alarms_menu_showhide");
 +
 +	RefreshReminderFrame();
 +	return 0;
 +}
 +
 +void InitIcons()
 +{
 +	SKINICONDESC sid = {0};
 +
 +	sid.cbSize = sizeof(SKINICONDESC);
 +	sid.pszSection = "Alarms";
 +
 +	sid.pszDescription = "Menu: Set Alarm";
 +	sid.pszName = "alarms_menu_set";
 +	sid.pszDefaultFile = "alarms.dll";
 +	sid.iDefaultIndex = 0;
 +	sid.hDefaultIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_MAINMENU), IMAGE_ICON, 16, 16, 0);
 +	Skin_AddIcon(&sid);
 +
 +	sid.pszDescription = "Reminder: Soon";
 +	sid.pszName = "alarms_list1";
 +	sid.pszDefaultFile = "alarms.dll";
 +	sid.iDefaultIndex = 1;
 +	sid.hDefaultIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_LIST1), IMAGE_ICON, 16, 16, 0);//LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS );	Skin_AddIcon(&sid);
 +
 +	sid.pszDescription = "Reminder: Very Soon";
 +	sid.pszName = "alarms_list2";
 +	sid.pszDefaultFile = "alarms.dll";
 +	sid.iDefaultIndex = 2;
 +	sid.hDefaultIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_LIST2), IMAGE_ICON, 16, 16, 0);//LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS );
 +	Skin_AddIcon(&sid);
 +
 +	sid.pszDescription = "Alarm: System Tray";
 +	sid.pszName = "alarms_systray";
 +	sid.pszDefaultFile = "alarms.dll";
 +	sid.iDefaultIndex = 3;
 +	sid.hDefaultIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_MAINMENU), IMAGE_ICON, 16, 16, 0);//LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS );
 +	Skin_AddIcon(&sid);
 +
 +	if (!ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) {
 +		sid.pszDescription = "Menu: Show/Hide Reminders";
 +		sid.pszName = "alarms_menu_showhide";
 +		sid.pszDefaultFile = "alarms.dll";
 +		sid.iDefaultIndex = 4;
 +		sid.hDefaultIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_MAINMENU), IMAGE_ICON, 16, 16, 0);
 +		Skin_AddIcon(&sid);
 +
 +		hIconMenuShowHide = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"alarms_menu_showhide");
 +	}
 +
 +	hIconMenuSet = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"alarms_menu_set");
 +	hIconList1 = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"alarms_list1");
 +	hIconList2 = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"alarms_list2");
 +	hIconSystray = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"alarms_systray");
 +
 +	hIcoLibIconsChanged = HookEvent(ME_SKIN2_ICONSCHANGED, ReloadIcons);
 +}
 diff --git a/plugins/Alarms/src/icons.h b/plugins/Alarms/src/icons.h new file mode 100644 index 0000000000..d47228f952 --- /dev/null +++ b/plugins/Alarms/src/icons.h @@ -0,0 +1,11 @@ +#ifndef _ICONS_INC
 +#define _ICONS_INC
 +
 +#include "frame.h"
 +
 +extern HICON hIconMenuSet, hIconList1, hIconList2, hIconMenuShowHide, hIconSystray;
 +
 +void InitIcons();
 +
 +#endif
 +
 diff --git a/plugins/Alarms/src/options.cpp b/plugins/Alarms/src/options.cpp new file mode 100644 index 0000000000..96dbf664fd --- /dev/null +++ b/plugins/Alarms/src/options.cpp @@ -0,0 +1,1217 @@ +#include "common.h"
 +#include "options.h"
 +
 +Options options;
 +
 +#define		WMU_OPTSETALARM		(WM_USER + 10)
 +#define		WMU_UPDATETIME		(WM_USER + 11)
 +#define		WMU_SETTIME			(WM_USER + 12)
 +#define		WMU_MYDESTROY		(WM_USER + 13)
 +
 +// defined in header
 +//#define		WMU_INITOPTLIST		(WM_USER + 20)
 +
 +typedef struct AddEditParam_tag {
 +	ALARM *alarm_ptr;
 +	BOOL edit;
 +	BOOL self_add;
 +} AddEditParam;
 +
 +HANDLE hMainMenuItem = 0, hGroupMenuItem;
 +
 +// store options dialog window handle statically so it can be refreshed by non-modal add alarm dialog
 +HWND hwndOptionsDialog = 0;
 +
 +static INT_PTR CALLBACK DlgProcAddEdit(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	ALARM *add_edit_alarm = (ALARM *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +	HWND hw;
 +
 +	switch ( msg ) {
 +	case WM_INITDIALOG:
 +		TranslateDialogDefault( hwndDlg );
 +
 +		SendDlgItemMessage(hwndDlg, IDC_DAY, CB_INSERTSTRING, 0, (LPARAM)Translate("Sunday"));
 +		SendDlgItemMessage(hwndDlg, IDC_DAY, CB_INSERTSTRING, 1, (LPARAM)Translate("Monday"));
 +		SendDlgItemMessage(hwndDlg, IDC_DAY, CB_INSERTSTRING, 2, (LPARAM)Translate("Tuesday"));
 +		SendDlgItemMessage(hwndDlg, IDC_DAY, CB_INSERTSTRING, 3, (LPARAM)Translate("Wednesday"));
 +		SendDlgItemMessage(hwndDlg, IDC_DAY, CB_INSERTSTRING, 4, (LPARAM)Translate("Thursday"));
 +		SendDlgItemMessage(hwndDlg, IDC_DAY, CB_INSERTSTRING, 5, (LPARAM)Translate("Friday"));
 +		SendDlgItemMessage(hwndDlg, IDC_DAY, CB_INSERTSTRING, 6, (LPARAM)Translate("Saturday"));
 +		SendDlgItemMessage(hwndDlg, IDC_DAY, CB_SETCURSEL, 0, 0);
 +		{
 +			char buff[10];
 +			for(int i = 1; i <= 31; i++) {
 +				SendDlgItemMessage(hwndDlg, IDC_DAYNUM, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)itoa(i, buff, 10));
 +			}
 +			SendDlgItemMessage(hwndDlg, IDC_DAYNUM, CB_SETCURSEL, 0, 0);
 +			{
 +				HWND hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, FALSE);
 +			}
 +
 +			if (!ServiceExists("Speak/Say"))
 +				EnableWindow(GetDlgItem(hwndDlg, IDC_RAD_SPK), FALSE);
 +
 +			AddEditParam *param = (AddEditParam *)lParam;
 +			SendMessage(hwndDlg, WMU_OPTSETALARM, (WPARAM)param->edit, (LPARAM)param->alarm_ptr);
 +
 +			// use invisible checkbox to store 'self_add' setting - naughty hack
 +			CheckDlgButton(hwndDlg, IDC_CHK_INVIS, param->self_add);
 +
 +			delete param;
 +
 +			Utils_RestoreWindowPositionNoSize(hwndDlg, 0, MODULE, "AddEdit");
 +
 +			if (GetDlgCtrlID((HWND)wParam) != IDC_TITLE) { 
 +				SetFocus(GetDlgItem(hwndDlg, IDC_TITLE)); 
 +				return FALSE; 
 +			}
 +		}
 +		return TRUE;
 +
 +	case WMU_OPTSETALARM:
 +		{
 +			BOOL edit = (BOOL)wParam;
 +			add_edit_alarm = (ALARM *)lParam;
 +			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG)add_edit_alarm);
 +
 +			if (edit) {
 +				SetDlgItemText(hwndDlg, IDC_TITLE, add_edit_alarm->szTitle);
 +				SetDlgItemText(hwndDlg, IDC_DESC, add_edit_alarm->szDesc);
 +				switch(add_edit_alarm->occurrence) {
 +				case OC_DAILY:
 +					CheckDlgButton(hwndDlg, IDC_RAD_DAILY, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_BTN_CAL);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DATE);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DAY);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +					EnableWindow(hw, TRUE);
 +					break;
 +
 +				case OC_WEEKDAYS:
 +					CheckDlgButton(hwndDlg, IDC_RAD_WEEKDAYS, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_BTN_CAL);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DATE);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DAY);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_RELMIN);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +					EnableWindow(hw, TRUE);
 +					break;
 +	
 +				case OC_ONCE:
 +					CheckDlgButton(hwndDlg, IDC_RAD_ONCE, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_DAY);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +					EnableWindow(hw, FALSE);
 +					break;
 +	
 +				case OC_WEEKLY:
 +					CheckDlgButton(hwndDlg, IDC_RAD_WEEKLY, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_BTN_CAL);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DATE);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_RELMIN);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +					EnableWindow(hw, TRUE);
 +					break;
 +			
 +				case OC_MONTHLY:
 +					CheckDlgButton(hwndDlg, IDC_RAD_MONTHLY, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_BTN_CAL);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DATE);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DAY);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_RELMIN);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +					EnableWindow(hw, TRUE);
 +					break;
 +	
 +				case OC_YEARLY:
 +					CheckDlgButton(hwndDlg, IDC_RAD_YEARLY, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_DAY);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +					EnableWindow(hw, TRUE);
 +					break;
 +				}
 +				
 +				CheckDlgButton(hwndDlg, IDC_CHK_SUSPEND, (add_edit_alarm->flags & ALF_SUSPENDED) ? TRUE : FALSE);
 +				CheckDlgButton(hwndDlg, IDC_CHK_NOSTARTUP, (add_edit_alarm->flags & ALF_NOSTARTUP) ? TRUE : FALSE);
 +				CheckDlgButton(hwndDlg, IDC_CHK_NOREMINDER, (add_edit_alarm->flags & ALF_NOREMINDER) ? TRUE : FALSE);
 +				
 +				SendDlgItemMessage(hwndDlg, IDC_DAY, CB_SETCURSEL, add_edit_alarm->time.wDayOfWeek, 0);
 +				SendDlgItemMessage(hwndDlg, IDC_TIME, DTM_SETSYSTEMTIME, (WPARAM)GDT_VALID, (LPARAM)&add_edit_alarm->time);
 +				SendDlgItemMessage(hwndDlg, IDC_DATE, DTM_SETSYSTEMTIME, (WPARAM)GDT_VALID, (LPARAM)&add_edit_alarm->time);
 +				SendDlgItemMessage(hwndDlg, IDC_DAYNUM, CB_SETCURSEL, add_edit_alarm->time.wDay - 1, 0);
 +				SetDlgItemInt(hwndDlg, IDC_RELMIN, MinutesInFuture(add_edit_alarm->time, add_edit_alarm->occurrence), FALSE);
 +
 +				if (add_edit_alarm->action & AAF_SOUND) {
 +					CheckDlgButton(hwndDlg, IDC_CHK_ASOUND, TRUE);
 +					switch(add_edit_alarm->sound_num) {
 +						case 1:
 +							CheckDlgButton(hwndDlg, IDC_RAD_SND1, TRUE);
 +							break;
 +						case 2:
 +							CheckDlgButton(hwndDlg, IDC_RAD_SND2, TRUE);
 +							break;
 +						case 3:
 +							CheckDlgButton(hwndDlg, IDC_RAD_SND3, TRUE);
 +							break;
 +						case 4:
 +							if (!ServiceExists("Speak/Say")) {
 +								add_edit_alarm->sound_num = 1;
 +								CheckDlgButton(hwndDlg, IDC_RAD_SND1, TRUE);
 +							} else
 +								CheckDlgButton(hwndDlg, IDC_RAD_SPK, TRUE);
 +							
 +							break;
 +					}
 +				} 
 +				else {
 +					HWND hw = GetDlgItem(hwndDlg, IDC_RAD_SND1);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_RAD_SND2);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_RAD_SND3);
 +					EnableWindow(hw, FALSE);
 +				}
 +				if (add_edit_alarm->action & AAF_POPUP)
 +					CheckDlgButton(hwndDlg, IDC_CHK_APOPUP, TRUE);
 +				if (add_edit_alarm->action & AAF_COMMAND) {
 +					CheckDlgButton(hwndDlg, IDC_CHK_ACOMMAND, TRUE);
 +					SetDlgItemText(hwndDlg, IDC_ED_COMMAND, add_edit_alarm->szCommand);
 +					SetDlgItemText(hwndDlg, IDC_ED_PARAMS, add_edit_alarm->szCommandParams);
 +				}
 +				else {
 +					HWND hw = GetDlgItem(hwndDlg, IDC_ED_COMMAND);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_ED_PARAMS);
 +					EnableWindow(hw, FALSE);
 +				}
 +			}
 +			else {
 +				SYSTEMTIME now;
 +				GetPluginTime(&now);
 +				
 +				// set time to 10 mins in future to help prevent 'alarm in past' error
 +				TimeForMinutesInFuture(10, &now);
 +				
 +				CheckDlgButton(hwndDlg, IDC_RAD_ONCE, TRUE);
 +				HWND hw = GetDlgItem(hwndDlg, IDC_DAY);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +				EnableWindow(hw, FALSE);
 +				SendDlgItemMessage(hwndDlg, IDC_DAY, CB_SETCURSEL, now.wDayOfWeek, 0);
 +				SendDlgItemMessage(hwndDlg, IDC_TIME, DTM_SETSYSTEMTIME, (WPARAM)GDT_VALID, (LPARAM)&now);
 +				SendDlgItemMessage(hwndDlg, IDC_DATE, DTM_SETSYSTEMTIME, (WPARAM)GDT_VALID, (LPARAM)&now);
 +				SendDlgItemMessage(hwndDlg, IDC_DAYNUM, CB_SETCURSEL, now.wDay - 1, 0);
 +				SetDlgItemInt(hwndDlg, IDC_RELMIN, MinutesInFuture(now, OC_ONCE), FALSE);
 +
 +				CheckDlgButton(hwndDlg, IDC_CHK_ASOUND, TRUE);
 +				CheckDlgButton(hwndDlg, IDC_RAD_SND1, TRUE);
 +				CheckDlgButton(hwndDlg, IDC_CHK_APOPUP, TRUE);
 +
 +				hw = GetDlgItem(hwndDlg, IDC_ED_COMMAND);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_ED_PARAMS);
 +				EnableWindow(hw, FALSE);
 +			}
 +		}
 +		return TRUE;
 +
 +	case WMU_UPDATETIME: 
 +		if (IsDlgButtonChecked(hwndDlg, IDC_RAD_ONCE))
 +			add_edit_alarm->occurrence = OC_ONCE;
 +		else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_DAILY))
 +			add_edit_alarm->occurrence = OC_DAILY;
 +		else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_WEEKDAYS))
 +			add_edit_alarm->occurrence = OC_WEEKDAYS;
 +		else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_WEEKLY))
 +			add_edit_alarm->occurrence = OC_WEEKLY;
 +		else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_MONTHLY))
 +			add_edit_alarm->occurrence = OC_MONTHLY;
 +		else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_YEARLY)) {
 +			add_edit_alarm->occurrence = OC_YEARLY;
 +				
 +			// set date range to 1 year (now to 1 year in future)
 +			SYSTEMTIME r[2];
 +			GetPluginTime(&r[0]);
 +			TimeForMinutesInFuture(365 * 24 * 60, &r[1]);
 +			SendDlgItemMessage(hwndDlg, IDC_DATE, DTM_SETRANGE, (WPARAM)(GDTR_MIN | GDTR_MAX), (LPARAM)r);
 +		}
 +
 +		if (add_edit_alarm->occurrence == OC_ONCE || add_edit_alarm->occurrence == OC_YEARLY)
 +			SendDlgItemMessage(hwndDlg, IDC_DATE, DTM_GETSYSTEMTIME, 0, (LPARAM)&add_edit_alarm->time);
 +
 +		if (add_edit_alarm->occurrence == OC_WEEKLY)
 +			add_edit_alarm->time.wDayOfWeek = (unsigned short)SendDlgItemMessage(hwndDlg, IDC_DAY, CB_GETCURSEL, 0, 0);
 +
 +		if (add_edit_alarm->occurrence == OC_MONTHLY)
 +			add_edit_alarm->time.wDay = (WORD)SendDlgItemMessage(hwndDlg, IDC_DAYNUM, CB_GETCURSEL, 0, 0) + 1;
 +
 +		SYSTEMTIME temp_time;
 +		SendDlgItemMessage(hwndDlg, IDC_TIME, DTM_GETSYSTEMTIME, 0, (LPARAM)&temp_time);
 +		add_edit_alarm->time.wHour = temp_time.wHour;
 +		add_edit_alarm->time.wMinute = temp_time.wMinute;
 +		add_edit_alarm->time.wSecond = temp_time.wSecond;
 +
 +		UpdateAlarm(add_edit_alarm->time, add_edit_alarm->occurrence);
 +		return TRUE;
 +
 +	case WMU_SETTIME:
 +		{
 +			SYSTEMTIME temp_time;
 +			SendDlgItemMessage(hwndDlg, IDC_DATE, MCM_GETCURSEL, 0, (LPARAM)&temp_time);
 +			if (memcmp(&temp_time, &add_edit_alarm->time, sizeof(SYSTEMTIME)) != 0)
 +				SendDlgItemMessage(hwndDlg, IDC_DATE, MCM_SETCURSEL, 0, (LPARAM)&add_edit_alarm->time);
 +
 +			SendDlgItemMessage(hwndDlg, IDC_DAY, CB_SETCURSEL, add_edit_alarm->time.wDayOfWeek, 0);
 +			SendDlgItemMessage(hwndDlg, IDC_TIME, DTM_SETSYSTEMTIME, (WPARAM)GDT_VALID, (LPARAM)&add_edit_alarm->time);
 +			SendDlgItemMessage(hwndDlg, IDC_DAYNUM, CB_SETCURSEL, add_edit_alarm->time.wDay - 1, 0);
 +			SetDlgItemInt(hwndDlg, IDC_RELMIN, MinutesInFuture(add_edit_alarm->time, add_edit_alarm->occurrence), FALSE);
 +		}
 +		return TRUE;
 +
 +	case WM_NOTIFY:
 +		if ( ((LPNMHDR)lParam)->code == DTN_DATETIMECHANGE) {
 +			switch( ((LPNMHDR)lParam)->idFrom ) {
 +			case IDC_TIME: 
 +				hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, TRUE);
 +
 +				SendMessage(hwndDlg, WMU_UPDATETIME, 0, 0);
 +				SendMessage(hwndDlg, WMU_SETTIME, 0, 0);
 +				break;
 +
 +			case IDC_DATE: 
 +				hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, TRUE);
 +
 +				SendMessage(hwndDlg, WMU_UPDATETIME, 0, 0);
 +				SendMessage(hwndDlg, WMU_SETTIME, 0, 0);
 +				break;
 +			}
 +			return TRUE;
 +		}
 +		break;
 +
 +	case WM_COMMAND:
 +		if ( HIWORD(wParam) == CBN_SELCHANGE ) {
 +			switch( LOWORD(wParam)) {
 +			case IDC_DAY: 
 +			case IDC_DAYNUM:
 +				hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, TRUE);
 +
 +				SendMessage(hwndDlg, WMU_UPDATETIME, 0, 0);
 +				SendMessage(hwndDlg, WMU_SETTIME, 0, 0);
 +				break;
 +			}
 +			return TRUE;
 +		}
 +		if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus()) {
 +			switch( LOWORD( wParam )) {
 +			case IDC_RELMIN: 
 +				{
 +					BOOL translated;
 +					int mins;
 +					mins = GetDlgItemInt(hwndDlg, IDC_RELMIN, &translated, FALSE);
 +					SYSTEMTIME newtime;
 +					TimeForMinutesInFuture(mins, &newtime);
 +
 +					SendDlgItemMessage(hwndDlg, IDC_TIME, DTM_SETSYSTEMTIME, (WPARAM)GDT_VALID, (LPARAM)&newtime);
 +					SendDlgItemMessage(hwndDlg, IDC_DATE, DTM_SETSYSTEMTIME, (WPARAM)GDT_VALID, (LPARAM)&newtime);
 +					SendDlgItemMessage(hwndDlg, IDC_DAY, CB_SETCURSEL, newtime.wDayOfWeek, 0);
 +					SendDlgItemMessage(hwndDlg, IDC_DAYNUM, CB_SETCURSEL, newtime.wDay - 1, 0);
 +
 +					add_edit_alarm->time = newtime;
 +						
 +					SendMessage(hwndDlg, WMU_UPDATETIME, 0, 0);
 +				}
 +					// drop through
 +			case IDC_TITLE:
 +			case IDC_DESC:
 +			case IDC_ED_COMMAND:
 +			case IDC_ED_PARAMS:
 +				HWND hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, TRUE);
 +			}
 +			return TRUE;
 +		}
 +		if ( HIWORD( wParam ) == BN_CLICKED ) {
 +			switch( LOWORD( wParam )) {
 +			case IDC_RAD_ONCE:
 +				hw = GetDlgItem(hwndDlg, IDC_DAY);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_BTN_CAL);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_DATE);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_RELMIN);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +				EnableWindow(hw, FALSE);
 +				SendMessage(hwndDlg, WMU_UPDATETIME, 0, 0);
 +				SendMessage(hwndDlg, WMU_SETTIME, 0, 0);
 +				break;
 +
 +			case IDC_RAD_DAILY:
 +				hw = GetDlgItem(hwndDlg, IDC_BTN_CAL);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_DAY);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_DATE);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_RELMIN);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +				EnableWindow(hw, TRUE);
 +				SendMessage(hwndDlg, WMU_UPDATETIME, 0, 0);
 +				SendMessage(hwndDlg, WMU_SETTIME, 0, 0);
 +				break;
 +
 +			case IDC_RAD_WEEKLY:
 +				hw = GetDlgItem(hwndDlg, IDC_BTN_CAL);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_DATE);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_DAY);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_RELMIN);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +				EnableWindow(hw, TRUE);
 +				SendMessage(hwndDlg, WMU_UPDATETIME, 0, 0);
 +				SendMessage(hwndDlg, WMU_SETTIME, 0, 0);
 +				break;
 +
 +			case IDC_RAD_WEEKDAYS:
 +				hw = GetDlgItem(hwndDlg, IDC_BTN_CAL);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_DATE);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_DAY);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_RELMIN);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +				EnableWindow(hw, TRUE);
 +				SendMessage(hwndDlg, WMU_UPDATETIME, 0, 0);
 +				SendMessage(hwndDlg, WMU_SETTIME, 0, 0);
 +				break;
 +
 +			case IDC_RAD_MONTHLY:
 +				hw = GetDlgItem(hwndDlg, IDC_BTN_CAL);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_DATE);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_DAY);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_RELMIN);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +				EnableWindow(hw, TRUE);
 +				SendMessage(hwndDlg, WMU_UPDATETIME, 0, 0);
 +				SendMessage(hwndDlg, WMU_SETTIME, 0, 0);
 +				break;
 +				
 +			case IDC_RAD_YEARLY:
 +				hw = GetDlgItem(hwndDlg, IDC_DAY);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_BTN_CAL);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_DATE);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_DAYNUM);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_RELMIN);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_CHK_SUSPEND);
 +				EnableWindow(hw, TRUE);
 +				SendMessage(hwndDlg, WMU_UPDATETIME, 0, 0);
 +				SendMessage(hwndDlg, WMU_SETTIME, 0, 0);
 +				break;
 +				
 +			case IDC_CHK_ACOMMAND:
 +				if (IsDlgButtonChecked(hwndDlg, IDC_CHK_ACOMMAND)) {
 +					HWND hw = GetDlgItem(hwndDlg, IDC_ED_COMMAND);
 +					EnableWindow(hw, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_ED_PARAMS);
 +					EnableWindow(hw, TRUE);
 +				} else {
 +					HWND hw = GetDlgItem(hwndDlg, IDC_ED_COMMAND);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_ED_PARAMS);
 +					EnableWindow(hw, FALSE);
 +				}
 +
 +			// drop through
 +			case IDC_CHK_ASOUND:
 +				if (IsDlgButtonChecked(hwndDlg, IDC_CHK_ASOUND)) {
 +					hw = GetDlgItem(hwndDlg, IDC_RAD_SND1);
 +					EnableWindow(hw, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_RAD_SND2);
 +					EnableWindow(hw, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_RAD_SND3);
 +					EnableWindow(hw, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_RAD_SPK);
 +					EnableWindow(hw, TRUE);
 +				} 
 +				else {
 +					hw = GetDlgItem(hwndDlg, IDC_RAD_SND1);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_RAD_SND2);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_RAD_SND3);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_RAD_SPK);
 +					EnableWindow(hw, FALSE);
 +				}
 +
 +			// drop though
 +			case IDC_RAD_SND1:
 +			case IDC_RAD_SND2:
 +			case IDC_RAD_SND3:
 +			case IDC_RAD_SPK:
 +			case IDC_CHK_SUSPEND:
 +			case IDC_CHK_NOSTARTUP:
 +			case IDC_CHK_NOREMINDER:
 +			case IDC_CHK_APOPUP:
 +				hw = GetDlgItem(hwndDlg, IDOK);
 +				EnableWindow(hw, TRUE);
 +				break;
 +				
 +			case IDOK: 
 +				{
 +					TCHAR buff[MAX_PATH];
 +					GetDlgItemText(hwndDlg, IDC_TITLE, buff, MAX_PATH);
 +					if (add_edit_alarm->szTitle) free(add_edit_alarm->szTitle);
 +					add_edit_alarm->szTitle = mir_tstrdup(buff);
 +
 +					GetDlgItemText(hwndDlg, IDC_DESC, buff, MAX_PATH);
 +					if (add_edit_alarm->szDesc) free(add_edit_alarm->szDesc);
 +					add_edit_alarm->szDesc = mir_tstrdup(buff);
 +
 +					if (add_edit_alarm->szTitle == 0 || _tcslen(add_edit_alarm->szTitle) == 0) {
 +						MessageBox(hwndDlg, TranslateT("Please enter a title for this alarm."), TranslateT("Error"), MB_OK | MB_ICONERROR);
 +						return TRUE;
 +					}
 +
 +					SendMessage(hwndDlg, WMU_UPDATETIME, 0, 0);
 +
 +					if (!UpdateAlarm(add_edit_alarm->time, add_edit_alarm->occurrence)) {
 +						MessageBox(hwndDlg, TranslateT("The alarm time you have selected is in the past."), TranslateT("Error"), MB_OK | MB_ICONERROR);
 +						return TRUE;
 +					}
 +
 +					add_edit_alarm->action = (IsDlgButtonChecked(hwndDlg, IDC_CHK_ASOUND) ? AAF_SOUND : 0);
 +					add_edit_alarm->action |= (IsDlgButtonChecked(hwndDlg, IDC_CHK_APOPUP) ? AAF_POPUP : 0);
 +					add_edit_alarm->action |= (IsDlgButtonChecked(hwndDlg, IDC_CHK_ACOMMAND) ? AAF_COMMAND : 0);
 +
 +					add_edit_alarm->flags = add_edit_alarm->flags & ~(ALF_SUSPENDED | ALF_NOSTARTUP | ALF_NOREMINDER);
 +					if (add_edit_alarm->occurrence != OC_ONCE) {
 +						add_edit_alarm->flags |= IsDlgButtonChecked(hwndDlg, IDC_CHK_SUSPEND) ? ALF_SUSPENDED : 0;
 +					}
 +					add_edit_alarm->flags |= IsDlgButtonChecked(hwndDlg, IDC_CHK_NOSTARTUP) ? ALF_NOSTARTUP : 0;
 +					add_edit_alarm->flags |= IsDlgButtonChecked(hwndDlg, IDC_CHK_NOREMINDER) ? ALF_NOREMINDER: 0;
 +
 +					if (add_edit_alarm->action & AAF_COMMAND) {
 +						GetDlgItemText(hwndDlg, IDC_ED_COMMAND, buff, MAX_PATH);
 +						if (add_edit_alarm->szCommand) free(add_edit_alarm->szCommand);
 +						add_edit_alarm->szCommand = mir_tstrdup(buff);
 +						GetDlgItemText(hwndDlg, IDC_ED_PARAMS, buff, MAX_PATH);
 +						if (add_edit_alarm->szCommandParams) free(add_edit_alarm->szCommandParams);
 +						add_edit_alarm->szCommandParams = mir_tstrdup(buff);
 +					}
 +
 +					if (add_edit_alarm->action & AAF_SOUND) {
 +						if (IsDlgButtonChecked(hwndDlg, IDC_RAD_SND1))
 +							add_edit_alarm->sound_num = 1;
 +						else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_SND2))
 +							add_edit_alarm->sound_num = 2;
 +						else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_SND3))
 +							add_edit_alarm->sound_num = 3;
 +						else if (IsDlgButtonChecked(hwndDlg, IDC_RAD_SPK))
 +							add_edit_alarm->sound_num = 4;
 +					} else
 +						add_edit_alarm->sound_num = 0;
 +
 +
 +					Utils_SaveWindowPosition(hwndDlg, 0, MODULE, "AddEdit");
 +
 +					// self-add (setting stored in invisible checkbox - see comments in WM_INITDIALOG
 +					if (IsDlgButtonChecked(hwndDlg, IDC_CHK_INVIS)) {
 +						alter_alarm_list(add_edit_alarm);
 +						RefreshReminderFrame();
 +						if (hwndOptionsDialog) {
 +							// refresh options list
 +							PostMessage(hwndOptionsDialog, WMU_INITOPTLIST, 0, 0);
 +						}
 +					}
 +
 +					// self-add (setting stored in invisible checkbox - see comments in WM_INITDIALOG
 +					if (IsDlgButtonChecked(hwndDlg, IDC_CHK_INVIS)) {
 +						free_alarm_data(add_edit_alarm);
 +						delete add_edit_alarm;
 +					}
 +
 +					// inform options dialog of change
 +
 +					// deal with modal and non-modal modes
 +					PostMessage(hwndDlg, WMU_MYDESTROY, 0, 0);
 +					EndDialog(hwndDlg, IDOK);
 +				}
 +				break;
 +				
 +			case IDCANCEL:
 +				// self-add (setting stored in invisible checkbox - see comments in WM_INITDIALOG
 +				if (IsDlgButtonChecked(hwndDlg, IDC_CHK_INVIS)) {
 +					ALARM *add_edit_alarm = (ALARM *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 +					free_alarm_data(add_edit_alarm);
 +					delete add_edit_alarm;
 +				}
 +						
 +				Utils_SaveWindowPosition(hwndDlg, 0, MODULE, "AddEdit");
 +	
 +				// deal with modal and non-modal modes
 +				PostMessage(hwndDlg, WMU_MYDESTROY, 0, 0);
 +				EndDialog(hwndDlg, IDCANCEL);
 +				break;
 +		
 +			default:
 +				return TRUE;
 +			}
 +		}
 +		break;
 +
 +	case WMU_MYDESTROY:
 +		DestroyWindow(hwndDlg);
 +		return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +BOOL Edit(HWND hwnd, ALARM &alarm, bool modal)
 +{
 +	AddEditParam *param = new AddEditParam;
 +	param->alarm_ptr = &alarm;
 +	param->edit = TRUE;
 +
 +	if (modal) {
 +		param->self_add = FALSE;
 +		if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_DIALOG2), hwnd, DlgProcAddEdit, (LPARAM)param) == IDOK) {
 +			return TRUE;
 +		}
 +	}
 +	else {
 +		param->self_add = TRUE;
 +		HWND hwndDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG2), hwnd, DlgProcAddEdit, (LPARAM)param);
 +
 +		//SetActiveWindow(hwndDlg);
 +		//SetWindowPos(hwndDlg, 
 +		SetForegroundWindow(hwndDlg);
 +		return TRUE;
 +	}
 +	return FALSE;
 +}
 +
 +BOOL New(HWND hwnd, ALARM &alarm, bool modal)
 +{
 +	AddEditParam *param = new AddEditParam;
 +	param->alarm_ptr = &alarm;
 +	param->edit = FALSE;
 +
 +	if (modal) {
 +		param->self_add = FALSE;
 +		if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_DIALOG2), hwnd, DlgProcAddEdit, (LPARAM)param) == IDOK)
 +			return TRUE;
 +	}
 +	else {
 +		param->self_add = TRUE;
 +		HWND hwndDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG2), hwnd, DlgProcAddEdit, (LPARAM)param);
 +
 +		//SetActiveWindow(hwndDlg);
 +		//SetWindowPos(hwndDlg, 
 +		SetForegroundWindow(hwndDlg);
 +		if (ServiceExists(MS_TTB_SETBUTTONSTATE)) {
 +			Sleep(100);
 +			CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTopToolbarButton, (LPARAM)TTBST_RELEASED);
 +		}
 +
 +		return TRUE;
 +	}
 +	return FALSE;
 +}
 +
 +void AddMenuItem()
 +{
 +	if (hMainMenuItem) return;
 +
 +	CLISTMENUITEM mi = {0};
 +	mi.cbSize = sizeof(mi);
 +	mi.flags = CMIM_ALL;
 +	mi.hIcon = hIconMenuSet;
 +	mi.pszName = "Set Alarm";
 +	mi.pszService = MODULE "/NewAlarm";
 +	mi.position = 500010000;
 +	if (!ServiceExists(MS_CLIST_FRAMES_ADDFRAME))
 +		mi.pszPopupName = "Alarms";
 +	if (ServiceExists(MS_CLIST_REMOVEGROUPMENUITEM)) {
 +		GroupMenuParam gmp = {0};
 +		hGroupMenuItem = Menu_AddGroupMenuItem(&gmp, &mi);
 +	}
 +	hMainMenuItem = Menu_AddMainMenuItem(&mi);
 +}
 +
 +///////////////////////
 +// create menu item
 +
 +int OptionsModulesLoaded(WPARAM wParam, LPARAM lParam)
 +{
 +	CreateServiceFunction(MODULE "/NewAlarm", NewAlarmMenuFunc);
 +
 +	AddMenuItem();
 +
 +	return 0;
 +}
 +
 +AlarmList temp_list, added_list, modified_list;		// we need to keep track of added and modified alarms, since if the non-modal dialog
 +													// refreshes the list before changes are applied, we loose them
 +
 +class ShortList {
 +public:
 +	class Node {
 +	public:
 +		Node(): next(0) {}
 +		unsigned short value;
 +		Node *next;
 +	};
 +
 +
 +	ShortList(): head(0) {}
 +	virtual ~ShortList() {clear();}
 +
 +	void clear() {
 +		Node *current;
 +		while(head) {
 +			current = head;
 +			head = head->next;
 +			delete current;
 +		}
 +	}
 +
 +	void push_back(unsigned short s) {Node *n = new Node; n->value = s; n->next = head; head = n;}
 +
 +	Node *get_head() {return head;}
 +
 +protected:
 +
 +	Node *head;
 +};
 +
 +ShortList deleted_list;			// same with deleted items
 +
 +Options temp_options;
 +static INT_PTR CALLBACK DlgProcOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	int sel;
 +
 +	switch ( msg ) {
 +	case WM_INITDIALOG:
 +		hwndOptionsDialog = hwndDlg;
 +		added_list.clear();
 +		modified_list.clear();
 +		deleted_list.clear();
 +
 +		TranslateDialogDefault( hwndDlg );
 +
 +		temp_options = options;
 +
 +		PostMessage(hwndDlg, WMU_INITOPTLIST, 0, 0);
 +		return TRUE;
 +
 +	case WMU_INITOPTLIST:
 +		copy_list(temp_list);
 +		{
 +			// add added alarms, in case this is a list refresh from non-modal add alarm dialog
 +			ALARM *i, *j;
 +			for(added_list.reset(); i = added_list.current(); added_list.next()) {
 +				temp_list.push_back(i);
 +			}
 +			// modify modified alarms, in case this is a list refresh from non-modal add alarm dialog
 +			for(temp_list.reset(); i = temp_list.current(); temp_list.next()) {
 +				for(modified_list.reset(); j = modified_list.current(); modified_list.next()) {
 +					if (i->id == j->id) {
 +						copy_alarm_data(i, j);
 +					}
 +				}
 +			}
 +			// remove deleted alarms, in case this is a list refresh from non-modal add alarm dialog
 +
 +			ShortList::Node *k = deleted_list.get_head();
 +			while(k) {
 +				for(temp_list.reset(); i = temp_list.current(); temp_list.next()) {
 +					if (i->id == k->value) {
 +						temp_list.erase();
 +						break;
 +					}
 +				}
 +				k = k->next;
 +			}
 +
 +			SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_RESETCONTENT, 0, 0);
 +
 +			if (temp_list.size() > 0) {
 +				int pos = -1;
 +				ALARM *i;
 +				for(temp_list.reset(); i = temp_list.current(); temp_list.next()) {
 +					if (!(i->flags & ALF_HIDDEN)) {
 +						pos = SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_ADDSTRING, 0, (LPARAM)i->szTitle);
 +						SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_SETITEMDATA, pos, (LPARAM)i->id);
 +					}
 +				}
 +				SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_SETCURSEL, pos, 0);
 +				HWND hw;
 +				hw = GetDlgItem(hwndDlg, IDC_EDIT);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_DEL);
 +				EnableWindow(hw, TRUE);
 +			} else {
 +				HWND hw;
 +				hw = GetDlgItem(hwndDlg, IDC_EDIT);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_DEL);
 +				EnableWindow(hw, FALSE);
 +			}
 +
 +			if (ServiceExists(MS_POPUP_ADDPOPUP)) {
 +				CheckDlgButton(hwndDlg, IDC_CHK_POPUPS, temp_options.use_popup_module ? TRUE : FALSE);
 +				if (options.use_popup_module) {
 +					HWND hw = GetDlgItem(hwndDlg, IDC_CHK_LOOPSOUND);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_AWROUND);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_AWNOACTIVATE);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_SPIN_TRANS);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_ED_TRANS);
 +					EnableWindow(hw, FALSE);
 +					hw = GetDlgItem(hwndDlg, IDC_BTN_PREVIEW);
 +					EnableWindow(hw, FALSE);
 +				} else {
 +					CheckDlgButton(hwndDlg, IDC_CHK_LOOPSOUND, temp_options.loop_sound ? TRUE : FALSE);
 +					HWND hw = GetDlgItem(hwndDlg, IDC_CHK_LOOPSOUND);
 +					EnableWindow(hw, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_AWROUND);
 +					EnableWindow(hw, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_AWNOACTIVATE);
 +					EnableWindow(hw, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_SPIN_TRANS);
 +					EnableWindow(hw, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_ED_TRANS);
 +					EnableWindow(hw, TRUE);
 +					hw = GetDlgItem(hwndDlg, IDC_BTN_PREVIEW);
 +					EnableWindow(hw, TRUE);
 +				}
 +			} else {
 +				HWND hw = GetDlgItem(hwndDlg, IDC_CHK_POPUPS);
 +				EnableWindow(hw, FALSE);
 +				CheckDlgButton(hwndDlg, IDC_CHK_LOOPSOUND, temp_options.loop_sound ? TRUE : FALSE);
 +			
 +				hw = GetDlgItem(hwndDlg, IDC_CHK_LOOPSOUND);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_CHK_AWROUND);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_CHK_AWNOACTIVATE);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_SPIN_TRANS);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_ED_TRANS);
 +				EnableWindow(hw, TRUE);
 +				hw = GetDlgItem(hwndDlg, IDC_BTN_PREVIEW);
 +				EnableWindow(hw, TRUE);
 +			}
 +
 +			SendMessage(GetDlgItem(hwndDlg, IDC_SPIN_SNOOZE), UDM_SETRANGE, 0, (LPARAM)MAKELONG(360, 0));
 +			SendMessage(GetDlgItem(hwndDlg, IDC_SPIN_SNOOZE), UDM_SETPOS, 0, temp_options.snooze_minutes);
 +
 +			SendMessage(GetDlgItem(hwndDlg, IDC_SPIN_ROWHEIGHT), UDM_SETRANGE, 0, (LPARAM)MAKELONG(100, 5));
 +			SendMessage(GetDlgItem(hwndDlg, IDC_SPIN_ROWHEIGHT), UDM_SETPOS, 0, temp_options.row_height);
 +
 +			SendMessage(GetDlgItem(hwndDlg, IDC_SPIN_INDENT), UDM_SETRANGE, 0, (LPARAM)MAKELONG(100, 0));
 +			SendMessage(GetDlgItem(hwndDlg, IDC_SPIN_INDENT), UDM_SETPOS, 0, temp_options.indent);
 +
 +			SendMessage(GetDlgItem(hwndDlg, IDC_SPIN_TRANS), UDM_SETRANGE, 0, (LPARAM)MAKELONG(100, 0));
 +			SendMessage(GetDlgItem(hwndDlg, IDC_SPIN_TRANS), UDM_SETPOS, 0, temp_options.aw_trans);
 +			if (!TransparencyEnabled()) {
 +				HWND hw = GetDlgItem(hwndDlg, IDC_SPIN_TRANS);
 +				EnableWindow(hw, FALSE);
 +				hw = GetDlgItem(hwndDlg, IDC_ED_TRANS);
 +				EnableWindow(hw, FALSE);
 +			}
 +		}
 +
 +		CheckDlgButton(hwndDlg, IDC_SHOWHIDE, temp_options.auto_showhide ? TRUE : FALSE);
 +		CheckDlgButton(hwndDlg, IDC_SHOWHIDE2, temp_options.hide_with_clist ? TRUE : FALSE);
 +		CheckDlgButton(hwndDlg, IDC_AUTOSIZEVERT, temp_options.auto_size_vert ? TRUE : FALSE);
 +
 +		CheckDlgButton(hwndDlg, IDC_CHK_AWROUND, temp_options.aw_roundcorners ? TRUE : FALSE);
 +		CheckDlgButton(hwndDlg, IDC_CHK_AWNOACTIVATE, temp_options.aw_dontstealfocus ? TRUE : FALSE);
 +
 +		SendMessage(GetDlgItem(hwndDlg, IDC_SPIN_PERIOD), UDM_SETRANGE, 0, (LPARAM)MAKELONG(72, 1));
 +		SendMessage(GetDlgItem(hwndDlg, IDC_SPIN_PERIOD), UDM_SETPOS, 0, temp_options.reminder_period);
 +
 +		SendMessage( GetParent( hwndDlg ), PSM_UNCHANGED, 0, 0 ); 
 +		return TRUE;
 +
 +	case WM_COMMAND:
 +		if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus())
 +			SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
 +
 +		if ( HIWORD( wParam ) == BN_CLICKED ) {
 +			switch( LOWORD( wParam )) {
 +			case IDC_BTN_PREVIEW:
 +				{
 +					HWND hwndDlgPrev = CreateDialog(hInst, MAKEINTRESOURCE(IDD_ALARM), GetDesktopWindow(), DlgProcAlarm);
 +					WindowList_Add(hAlarmWindowList, hwndDlgPrev, 0);
 +					SendMessage(hwndDlgPrev, WMU_FAKEALARM, 0, 0);
 +					SendMessage(hwndDlgPrev, WMU_SETOPT, 0, (LPARAM)&temp_options);
 +					ShowWindow(hwndDlgPrev, SW_SHOW);
 +					SetWindowPos(hwndDlgPrev, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 +				}
 +				break;
 +			case IDC_SHOWHIDE:
 +				temp_options.auto_showhide = IsDlgButtonChecked(hwndDlg, IDC_SHOWHIDE) ? true : false;
 +				SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
 +				break;
 +			case IDC_SHOWHIDE2:
 +				temp_options.hide_with_clist = IsDlgButtonChecked(hwndDlg, IDC_SHOWHIDE2) ? true : false;
 +				SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
 +				break;
 +			case IDC_AUTOSIZEVERT:
 +				temp_options.auto_size_vert = IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZEVERT) ? true : false;
 +				SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
 +				break;
 +			case IDC_NEW: 
 +				{
 +					ALARM new_alarm = {0};
 +					GetPluginTime(&new_alarm.time);
 +					new_alarm.id = next_alarm_id++;
 +					if (New(hwndDlg, new_alarm, true)) {
 +						new_alarm.id = next_alarm_id++;
 +						temp_list.push_back(&new_alarm);
 +						added_list.push_back(&new_alarm);
 +						int pos = SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_ADDSTRING, (WPARAM)-1, (LPARAM)new_alarm.szTitle);
 +						SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_SETITEMDATA, pos, new_alarm.id);
 +						SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_SETCURSEL, pos, 0);
 +						HWND hw;
 +						hw = GetDlgItem(hwndDlg, IDC_EDIT);
 +						EnableWindow(hw, TRUE);
 +						hw = GetDlgItem(hwndDlg, IDC_DEL);
 +						EnableWindow(hw, TRUE);
 +						SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
 +
 +						free_alarm_data(&new_alarm);
 +					}
 +				}
 +				break;
 +
 +			case IDC_EDIT: 
 +				sel = SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_GETCURSEL, 0, 0);
 +				if (sel != -1) {
 +					unsigned short id = (unsigned short)SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_GETITEMDATA, sel, 0);
 +					ALARM *i;
 +					for(temp_list.reset(); i = temp_list.current(); temp_list.next()) {
 +						if (i->id == id) {
 +							ALARM a = {0};
 +							copy_alarm_data(&a, i);
 +							if (Edit(hwndDlg, a, true)) {
 +								modified_list.push_back(&a);
 +								SendMessage(hwndDlg, WMU_INITOPTLIST, 0, 0);
 +								SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_SETCURSEL, sel, 0);
 +								SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
 +							}
 +							free_alarm_data(&a);
 +							break;
 +						}
 +					}
 +				}
 +				break;
 +
 +			case IDC_DEL:
 +				sel = SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_GETCURSEL, 0, 0);
 +				if (sel != -1) {
 +					unsigned short id = (unsigned short)SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_GETITEMDATA, sel, 0);
 +
 +					ALARM *i;
 +					for(temp_list.reset(); i = temp_list.current(); temp_list.next()) {
 +						if (i->id == id) {
 +							deleted_list.push_back(i->id);
 +							//temp_list.erase();
 +							break;
 +						}
 +					}
 +							
 +					SendMessage( hwndDlg, WMU_INITOPTLIST, 0, 0 );
 +					SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
 +				}
 +				break;
 +				
 +			case IDC_CHK_POPUPS: 
 +				{
 +					BOOL chk = IsDlgButtonChecked(hwndDlg, IDC_CHK_POPUPS);
 +					if (chk) CheckDlgButton(hwndDlg, IDC_CHK_LOOPSOUND, FALSE);
 +					else CheckDlgButton(hwndDlg, IDC_CHK_LOOPSOUND, temp_options.loop_sound);
 +
 +					HWND hw = GetDlgItem(hwndDlg, IDC_CHK_LOOPSOUND);
 +					EnableWindow(hw, !chk);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_AWROUND);
 +					EnableWindow(hw, !chk);
 +					hw = GetDlgItem(hwndDlg, IDC_CHK_AWNOACTIVATE);
 +					EnableWindow(hw, !chk);
 +					hw = GetDlgItem(hwndDlg, IDC_SPIN_TRANS);
 +					EnableWindow(hw, !chk);
 +					hw = GetDlgItem(hwndDlg, IDC_ED_TRANS);
 +					EnableWindow(hw, !chk);
 +					hw = GetDlgItem(hwndDlg, IDC_BTN_PREVIEW);
 +					EnableWindow(hw, !chk);
 +
 +					temp_options.use_popup_module = IsDlgButtonChecked(hwndDlg, IDC_CHK_POPUPS) ? true : false;
 +					SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); 
 +				}
 +				break;
 +				
 +			case IDC_CHK_LOOPSOUND:
 +				temp_options.loop_sound = IsDlgButtonChecked(hwndDlg, IDC_CHK_LOOPSOUND) ? true : false;
 +				SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); 
 +				break;
 +
 +			case IDC_CHK_AWROUND:
 +				temp_options.aw_roundcorners = IsDlgButtonChecked(hwndDlg, IDC_CHK_AWROUND) ? true : false;
 +				SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); 										
 +				break;
 +
 +			case IDC_CHK_AWNOACTIVATE:
 +				temp_options.aw_dontstealfocus = IsDlgButtonChecked(hwndDlg, IDC_CHK_AWNOACTIVATE) ? true : false;
 +				SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); 										
 +				break;
 +			}
 +			return TRUE;
 +		}
 +
 +		if (HIWORD( wParam ) == LBN_SELCHANGE) {
 +			HWND hw;
 +			hw = GetDlgItem(hwndDlg, IDC_EDIT);
 +			EnableWindow(hw, TRUE);
 +			hw = GetDlgItem(hwndDlg, IDC_DEL);
 +			EnableWindow(hw, TRUE);
 +
 +			//SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +			return TRUE;
 +		}
 +
 +		if (HIWORD( wParam ) == LBN_DBLCLK) {
 +			int sel = SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_GETCURSEL, 0, 0);
 +			if (sel != -1) {
 +				unsigned short id = (unsigned short)SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_GETITEMDATA, sel, 0);
 +				ALARM *i;
 +				for(temp_list.reset(); i = temp_list.current(); temp_list.next()) {
 +					if (i->id == id) {
 +						ALARM a = {0};
 +						copy_alarm_data(&a, i);
 +						if (Edit(hwndDlg, a, true)) {
 +							modified_list.push_back(&a);
 +							SendMessage(hwndDlg, WMU_INITOPTLIST, 0, 0);
 +							SendDlgItemMessage(hwndDlg, IDC_ALIST, LB_SETCURSEL, sel, 0);
 +							SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
 +						}
 +						free_alarm_data(&a);
 +						break;
 +					}
 +				}
 +			}
 +		}
 +		break;
 +
 +	case WM_NOTIFY:
 +		if (((LPNMHDR)lParam)->code == UDN_DELTAPOS ) {
 +			BOOL translated;
 +			int trans = GetDlgItemInt(hwndDlg, IDC_ED_TRANS, &translated, FALSE);
 +			if (translated) temp_options.aw_trans = trans;
 +			SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
 +			return TRUE;
 +		}
 +		if ((int)((LPNMHDR)lParam)->code == PSN_APPLY ) {
 +			set_list(temp_list);
 +			SaveAlarms();
 +
 +			BOOL translated;
 +			int snooze_mins = GetDlgItemInt(hwndDlg, IDC_ED_SNOOZE, &translated, FALSE);
 +			if (translated) temp_options.snooze_minutes = snooze_mins;
 +			int row_height = GetDlgItemInt(hwndDlg, IDC_ED_ROWHEIGHT, &translated, FALSE);
 +			if (translated) temp_options.row_height = row_height;
 +			int indent = GetDlgItemInt(hwndDlg, IDC_ED_INDENT, &translated, FALSE);
 +			if (translated) temp_options.indent = indent;
 +			int trans = GetDlgItemInt(hwndDlg, IDC_ED_TRANS, &translated, FALSE);
 +			if (translated) temp_options.aw_trans = trans;
 +
 +			temp_options.use_popup_module = IsDlgButtonChecked(hwndDlg, IDC_CHK_POPUPS) ? true : false;
 +			temp_options.auto_showhide = IsDlgButtonChecked(hwndDlg, IDC_SHOWHIDE) ? true : false;
 +			temp_options.hide_with_clist = IsDlgButtonChecked(hwndDlg, IDC_SHOWHIDE2) ? true : false;
 +			temp_options.auto_size_vert = IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZEVERT) ? true : false;
 +			temp_options.aw_roundcorners = IsDlgButtonChecked(hwndDlg, IDC_CHK_AWROUND) ? true : false;
 +			temp_options.aw_dontstealfocus = IsDlgButtonChecked(hwndDlg, IDC_CHK_AWNOACTIVATE) ? true : false;
 +
 +			int reminder_period = GetDlgItemInt(hwndDlg, IDC_ED_PERIOD, &translated, FALSE);
 +			if (translated) temp_options.reminder_period = reminder_period;
 +
 +			if (!ServiceExists(MS_POPUP_ADDPOPUP) || !options.use_popup_module)
 +				temp_options.loop_sound = IsDlgButtonChecked(hwndDlg, IDC_CHK_LOOPSOUND) ? true : false;
 +
 +			options = temp_options;
 +			SaveOptions();
 +			FixMainMenu();
 +			RefreshReminderFrame();
 +			SetAlarmWinOptions();
 +
 +			added_list.clear();
 +			modified_list.clear();
 +			deleted_list.clear();
 +			return TRUE;
 +		}
 +
 +		break;
 +
 +	case WM_DESTROY:
 +		hwndOptionsDialog = 0;
 +		added_list.clear();
 +		modified_list.clear();
 +		deleted_list.clear();
 +		break;
 +	}
 +
 +	return FALSE;
 +}
 +
 +
 +int OptInit(WPARAM wParam,LPARAM lParam)
 +{
 +	OPTIONSDIALOGPAGE odp = { 0 };
 +	odp.cbSize = sizeof(odp);
 +	odp.position = -790000000;
 +	odp.hInstance = hInst;
 +	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT1);
 +	odp.pszTitle = LPGEN("Alarms");
 +	odp.pszGroup = LPGEN("Events");
 +	odp.flags = ODPF_BOLDGROUPS;
 +	odp.pfnDlgProc = DlgProcOpts;
 +	Options_AddPage(wParam, &odp);
 +
 +	return 0;
 +}
 +
 +void LoadOptions()
 +{
 +	options.use_popup_module = (DBGetContactSettingByte(0, MODULE, "UsePopupModule", 0) == 1);
 +	options.snooze_minutes = (int)DBGetContactSettingDword(0, MODULE, "SnoozeMinutes", 10);
 +	options.row_height = (int)DBGetContactSettingDword(0, MODULE, "RowHeight", 20);
 +	options.indent = (int)DBGetContactSettingDword(0, MODULE, "Indent", 5);
 +	options.aw_trans = (int)DBGetContactSettingByte(0, MODULE, "Transparency", 0);
 +	options.aw_roundcorners = (DBGetContactSettingByte(0, MODULE, "RoundCorners", 1) == 1);
 +	options.aw_dontstealfocus = (DBGetContactSettingByte(0, MODULE, "DontStealFocus", 1) == 1);
 +	options.auto_showhide = (DBGetContactSettingByte(0, MODULE, "AutoShowHide", 0) == 1);
 +	options.hide_with_clist = (DBGetContactSettingByte(0, MODULE, "HideWithClist", 0) == 1);
 +	options.loop_sound = (DBGetContactSettingByte(0, MODULE, "LoopSound", 1) == 1);
 +	options.auto_size_vert = (DBGetContactSettingByte(0, MODULE, "AutoSize", 0) == 1);
 +	options.reminder_period = (int)DBGetContactSettingDword(0, MODULE, "ReminderPeriod", 8);
 +
 +	HookEvent(ME_SYSTEM_MODULESLOADED, OptionsModulesLoaded);
 +}
 +
 +void SaveOptions()
 +{
 +	DBWriteContactSettingByte(0, MODULE, "UsePopupModule", options.use_popup_module ? 1 : 0);
 +	DBWriteContactSettingDword(0, MODULE, "SnoozeMinutes", options.snooze_minutes);
 +	DBWriteContactSettingDword(0, MODULE, "RowHeight", options.row_height);
 +	DBWriteContactSettingDword(0, MODULE, "Indent", options.indent);
 +	DBWriteContactSettingByte(0, MODULE, "Transparency", options.aw_trans);
 +	DBWriteContactSettingByte(0, MODULE, "RoundCorners", options.aw_roundcorners ? 1 : 0);
 +	DBWriteContactSettingByte(0, MODULE, "DontStealFocus", options.aw_dontstealfocus ? 1 : 0);
 +	DBWriteContactSettingByte(0, MODULE, "AutoShowHide", options.auto_showhide ? 1 : 0);
 +	DBWriteContactSettingByte(0, MODULE, "HideWithClist", options.hide_with_clist ? 1 : 0);
 +	DBWriteContactSettingByte(0, MODULE, "LoopSound", options.loop_sound ? 1 : 0);
 +	DBWriteContactSettingByte(0, MODULE, "AutoSize", options.auto_size_vert ? 1 : 0);
 +	DBWriteContactSettingDword(0, MODULE, "ReminderPeriod", options.reminder_period);
 +}
 +
 +INT_PTR NewAlarmMenuFunc(WPARAM wParam, LPARAM lParam)
 +{
 +	ALARM *new_alarm = new ALARM;
 +	memset(new_alarm, 0, sizeof(ALARM));
 +	new_alarm->id = next_alarm_id++;
 +	GetPluginTime(&new_alarm->time);
 +
 +	//New((HWND)CallService(MS_CLUI_GETHWND, 0, 0), *new_alarm, false);
 +	New(GetDesktopWindow(), *new_alarm, false);
 +
 +	return 0;
 +}
 +
 +void EditNonModal(ALARM &alarm)
 +{
 +	ALARM *new_alarm = new ALARM;
 +	memset(new_alarm, 0, sizeof(ALARM));
 +	copy_alarm_data(new_alarm, &alarm);
 +
 +	Edit(GetDesktopWindow(), *new_alarm, false);
 +}
 diff --git a/plugins/Alarms/src/options.h b/plugins/Alarms/src/options.h new file mode 100644 index 0000000000..030ccb77ba --- /dev/null +++ b/plugins/Alarms/src/options.h @@ -0,0 +1,41 @@ +#ifndef _OPTIONS_INC
 +#define _OPTIONS_INC
 +
 +#include <commctrl.h>
 +#include "m_alarms.h"
 +#include "alarmlist.h"
 +#include "icons.h"
 +#include "frame.h"
 +#include "alarm_win.h"
 +
 +typedef struct Options_tag {
 +	bool use_popup_module;
 +	int snooze_minutes;
 +	int row_height;
 +	int indent;
 +	int aw_trans;
 +	bool aw_roundcorners;
 +	bool aw_dontstealfocus;
 +	bool auto_showhide;
 +	bool hide_with_clist;
 +	bool loop_sound;
 +	bool auto_size_vert;
 +	int reminder_period;
 +} Options;
 +
 +extern Options options;
 +
 +int OptInit(WPARAM wParam,LPARAM lParam);
 +
 +void LoadOptions();
 +void SaveOptions();
 +
 +INT_PTR NewAlarmMenuFunc(WPARAM wParam, LPARAM lParam);
 +void EditNonModal(ALARM &alarm);
 +
 +// provide access the options window, for refresh (== 0 when not displayed)
 +extern HWND hwndOptionsDialog;
 +#define		WMU_INITOPTLIST		(WM_USER + 20)
 +
 +
 +#endif
 diff --git a/plugins/Alarms/src/resource.h b/plugins/Alarms/src/resource.h new file mode 100644 index 0000000000..bff9b1a19c --- /dev/null +++ b/plugins/Alarms/src/resource.h @@ -0,0 +1,91 @@ +//{{NO_DEPENDENCIES}}
 +// Microsoft Visual C++ generated include file.
 +// Used by resource.rc
 +//
 +#define IDD_DIALOG1                     101
 +#define IDD_OPT1                        102
 +#define IDD_DIALOG2                     103
 +#define IDI_MAINMENU                    105
 +#define IDD_ALARM                       106
 +#define IDI_ICON1                       109
 +#define IDB_CLOCKDOWN                   112
 +#define IDB_CLOCKUP                     113
 +#define IDI_LIST2                       114
 +#define IDI_LIST1                       115
 +#define IDR_MENU1                       116
 +#define IDI_TBUP                        123
 +#define IDI_TBDN                        124
 +#define IDD_OPTTRIGGER                  125
 +#define IDC_ALIST                       1006
 +#define IDC_TIME                        1007
 +#define IDC_TITLE                       1010
 +#define IDC_DESC                        1011
 +#define IDC_RAD_ONCE                    1012
 +#define IDC_RAD_WEEKLY                  1013
 +#define IDC_RAD_DAILY                   1014
 +#define IDC_RAD_WEEKDAYS                1015
 +#define IDC_RAD_MONTHLY                 1016
 +#define IDC_DAY                         1017
 +#define IDC_DAYNUM                      1018
 +#define IDC_RAD_YEARLY                  1019
 +#define IDC_NEW                         1020
 +#define IDC_DEL                         1021
 +#define IDC_EDIT                        1022
 +#define IDC_CHK_POPUPS                  1023
 +#define IDC_ED_SNOOZE                   1024
 +#define IDC_SPIN1                       1025
 +#define IDC_SPIN_SNOOZE                 1025
 +#define IDC_SNOOZE                      1026
 +#define IDC_CHK_ASOUND                  1028
 +#define IDC_CHK_ACOMMAND                1029
 +#define IDC_ED_COMMAND                  1030
 +#define IDC_ED_PARAMS                   1031
 +#define IDC_CHK_INVIS                   1032
 +#define IDC_SNOOZELIST                  1033
 +#define IDC_RAD_SND1                    1034
 +#define IDC_RAD_SND2                    1035
 +#define IDC_RAD_SND3                    1036
 +#define IDC_RAD_SPK                     1037
 +#define IDC_RELMIN                      1038
 +#define IDC_ED_ROWHEIGHT                1039
 +#define IDC_SPIN_ROWHEIGHT              1040
 +#define IDC_ED_INDENT                   1041
 +#define IDC_SPIN_INDENT                 1042
 +#define IDC_SHOWHIDE                    1043
 +#define IDC_ED_PERIOD                   1044
 +#define IDC_SPIN_PERIOD                 1045
 +#define IDC_DISMISS                     1045
 +#define IDC_SHOWHIDE2                   1046
 +#define IDC_AUTOSIZEVERT                1047
 +#define IDC_ED_TRANS                    1048
 +#define IDC_SPIN_TRANS                  1049
 +#define IDC_CHK_AWROUND                 1050
 +#define IDC_CHK_AWNOACTIVATE            1051
 +#define IDC_BTN_PREVIEW                 1052
 +#define IDC_LST_TRIGLIST                1053
 +#define IDC_BTN_CAL                     1055
 +#define IDC_CHK_APOPUP                  1060
 +#define IDC_SNOOZE2                     1061
 +#define IDC_CHK_SUSPEND                 1062
 +#define IDC_CHK_NOSTARTUP               1063
 +#define IDC_CHK_NOREMINDER              1064
 +#define IDC_CHK_LOOPSOUND               1065
 +#define IDC_ED_DESC                     1066
 +#define IDC_DATE                        1071
 +#define ID_REMINDERFRAMECONTEXT_SUSPEND 40003
 +#define ID_REMINDERFRAMECONTEXT_EDIT    40004
 +#define ID_REMINDERFRAMECONTEXT_DELETE  40005
 +#define ID_REMINDERFRAMECONTEXT_OPTIONS 40006
 +#define ID_REMINDERFRAMECONTEXT_NEWALARM 40007
 +#define IDC_STATIC                      -1
 +
 +// Next default values for new objects
 +// 
 +#ifdef APSTUDIO_INVOKED
 +#ifndef APSTUDIO_READONLY_SYMBOLS
 +#define _APS_NEXT_RESOURCE_VALUE        127
 +#define _APS_NEXT_COMMAND_VALUE         40008
 +#define _APS_NEXT_CONTROL_VALUE         1072
 +#define _APS_NEXT_SYMED_VALUE           101
 +#endif
 +#endif
 diff --git a/plugins/Alarms/src/time_utils.cpp b/plugins/Alarms/src/time_utils.cpp new file mode 100644 index 0000000000..69f45612f8 --- /dev/null +++ b/plugins/Alarms/src/time_utils.cpp @@ -0,0 +1,25 @@ +#include "common.h"
 +#include "time_utils.h"
 +
 +SYSTEMTIME last_check;
 +
 +bool IsBetween(SYSTEMTIME &time, SYSTEMTIME &start, SYSTEMTIME &end) {
 +
 +	FILETIME ft_time, ft_start, ft_end;
 +
 +	SystemTimeToFileTime(&time, &ft_time);
 +	SystemTimeToFileTime(&start, &ft_start);
 +	SystemTimeToFileTime(&end, &ft_end);
 +
 +	return (CompareFileTime(&ft_time, &ft_start) > 0 && CompareFileTime(&ft_time, &ft_end) <= 0);
 +}
 +
 +bool IsBefore(SYSTEMTIME &time, SYSTEMTIME &start) {
 +	FILETIME ft_time, ft_start;
 +
 +	SystemTimeToFileTime(&time, &ft_time);
 +	SystemTimeToFileTime(&start, &ft_start);
 +
 +	return (CompareFileTime(&ft_time, &ft_start) < 0);
 +}
 +
 diff --git a/plugins/Alarms/src/time_utils.h b/plugins/Alarms/src/time_utils.h new file mode 100644 index 0000000000..9bae092b63 --- /dev/null +++ b/plugins/Alarms/src/time_utils.h @@ -0,0 +1,7 @@ +#ifndef _TIME_UTILS_INC
 +#define _TIME_UTILS_INC
 +
 +bool IsBefore(SYSTEMTIME &time, SYSTEMTIME &start);
 +bool IsBetween(SYSTEMTIME &time, SYSTEMTIME &start, SYSTEMTIME &end);
 +
 +#endif
 diff --git a/plugins/Alarms/src/trigger.cpp b/plugins/Alarms/src/trigger.cpp new file mode 100644 index 0000000000..532b98920c --- /dev/null +++ b/plugins/Alarms/src/trigger.cpp @@ -0,0 +1,106 @@ +#include "common.h"
 +#include "trigger.h"
 +
 +AlarmList alist;
 +//SPECIFICTRIGGERINFO sti;
 +TRIGGERDATA td;
 +
 +unsigned short last_selected_id = 0;
 +
 +static INT_PTR CALLBACK DlgProcTriggerOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	switch(msg) {
 +	case WM_INITDIALOG:
 +		TranslateDialogDefault(hwndDlg);
 +		{
 +			copy_list(alist);
 +			ALARM *i;
 +			for(alist.reset(); i = alist.current(); alist.next()) {
 +				int pos = SendDlgItemMessage(hwndDlg, IDC_LST_TRIGLIST, LB_ADDSTRING, (WPARAM)-1, (LPARAM)i->szTitle);
 +				SendDlgItemMessage(hwndDlg, IDC_LST_TRIGLIST, LB_SETITEMDATA, (WPARAM)pos, (LPARAM)i->id);
 +				if (i->trigger_id == (unsigned int)lParam)
 +					SendDlgItemMessage(hwndDlg, IDC_LST_TRIGLIST, LB_SETCURSEL, (WPARAM)pos, 0);
 +			}
 +		}
 +		return FALSE;
 +
 +	case WM_COMMAND:
 +		if (HIWORD( wParam ) == LBN_SELCHANGE) {
 +			int pos = SendDlgItemMessage(hwndDlg, IDC_LST_TRIGLIST, LB_GETCURSEL, 0, 0);
 +			if (pos != LB_ERR) {
 +				last_selected_id = (unsigned short)SendDlgItemMessage(hwndDlg, IDC_LST_TRIGLIST, LB_GETITEMDATA, pos, 0);
 +			}
 +			return TRUE;
 +		}
 +		break;
 +	case TM_GETTRIGGERINFO:
 +		{
 +			//memset(&sti, sizeof(sti), 0);
 +			memset(&td, sizeof(td), 0);
 +
 +			ALARM *i;
 +			for(alist.reset(); i = alist.current(); alist.next()) {
 +				if (i->trigger_id == wParam) {
 +					//sti.cbSize = sizeof(sti);
 +					//sti.triggerID = wParam;
 +					//sti.pszSummary = i->szTitle;
 +					//sti.td = &td;
 +
 +					td.cbSize = sizeof(td);
 +					td.dFlags = DF_TEXT;
 +					td.tszText = i->szDesc;
 +					//*(SPECIFICTRIGGERINFO **)lParam = &sti;
 +					break;
 +				}
 +			}
 +		}
 +		return TRUE;
 +	case TM_ADDTRIGGER:
 +		{
 +			ALARM *i;
 +			for(alist.reset(); i = alist.current(); alist.next()) {
 +				if (i->id == last_selected_id) {
 +					i->trigger_id = wParam;
 +					alter_alarm_list(i);
 +					break;
 +				}
 +			}
 +		}
 +		return TRUE;
 +	case TM_DELTRIGGER:
 +		{
 +			ALARM *i;
 +			for(alist.reset(); i = alist.current(); alist.next()) {
 +				if (i->trigger_id == wParam) {
 +					i->trigger_id = 0;
 +					alter_alarm_list(i);
 +					break;
 +				}
 +			}
 +		}
 +		return TRUE;
 +
 +	case WM_DESTROY:
 +		// it seems this is called before the TM_ADDTRIGGER messsage is passed to us....tsk,tsk :P
 +		//alist.clear();
 +		break;
 +
 +	}
 +	return FALSE;
 +}
 +
 +int LoadTriggerSupport() {
 +	if (ServiceExists(MS_TRIGGER_REGISTERTRIGGER)) {
 +		TRIGGERREGISTER treg = {0};
 +	
 +		treg.cbSize = sizeof(treg);
 +		treg.pszName = Translate("Alarms");
 +		treg.hInstance = hInst;
 +		treg.pfnDlgProc = DlgProcTriggerOptions;
 +		treg.pszTemplate = MAKEINTRESOURCEA(IDD_OPTTRIGGER);
 +
 +		CallService(MS_TRIGGER_REGISTERTRIGGER, 0, (LPARAM)&treg);
 +	}
 +
 +	return 0;
 +}
 diff --git a/plugins/Alarms/src/trigger.h b/plugins/Alarms/src/trigger.h new file mode 100644 index 0000000000..3b326e78a4 --- /dev/null +++ b/plugins/Alarms/src/trigger.h @@ -0,0 +1,11 @@ +#ifndef _TRIGGER_INC
 +#define _TRIGGER_INC
 +
 +#include "alarmlist.h"
 +
 +
 +int LoadTriggerSupport();
 +
 +
 +#endif
 +
  | 
