soc.2009.vulture: a1526d1e: Conversation container window.

gdick at soc.pidgin.im gdick at soc.pidgin.im
Sat Jun 13 17:35:38 EDT 2009


-----------------------------------------------------------------
Revision: a1526d1e3e37b26642695e75bbb8421623200a08
Ancestor: 6fb975b923d6e2e210e6795129813a65e4dd698d
Author: gdick at soc.pidgin.im
Date: 2009-06-12T21:08:15
Branch: im.pidgin.soc.2009.vulture
URL: http://d.pidgin.im/viewmtn/revision/info/a1526d1e3e37b26642695e75bbb8421623200a08

Added files:
        vulture/purpleconv.c vulture/purpleconv.h
        vulture/vultureconv.c vulture/vultureconv.h
Modified files:
        vulture/Makefile.mingw vulture/purplemain.c
        vulture/purplemain.h vulture/purplequeue.c
        vulture/purplequeue.h vulture/resource.h
        vulture/vulture-res.rc vulture/vulture.c
        vulture/vultureblist.c vulture/vultureblist.h

ChangeLog: 

Conversation container window.

-------------- next part --------------
============================================================
--- vulture/purpleconv.c	8200ec4fee1c440e896338dcada0280e9231e1a3
+++ vulture/purpleconv.c	8200ec4fee1c440e896338dcada0280e9231e1a3
@@ -0,0 +1,83 @@
+/*
+ * Vulture - Win32 libpurple client
+ *
+ * purpleconv.c: Conversation back-end.
+ *
+ * Copyright (C) 2009, Gregor Dick <gdick at soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include <windows.h>
+#include <glib.h>
+
+#include "vulture.h"
+#include "purple.h"
+#include "purpleconv.h"
+#include "vultureconv.h"
+#include "purplemain.h"
+
+
+
+/**
+ * PurpleConversationUiOps::create_conversation callback. Called when a new
+ * conversation is created.
+ *
+ * @param	lpconv	New conversation.
+ */
+void PurpleNewConversation(PurpleConversation *lpconv)
+{
+	/* The UI will eventually free this. */
+	VULTURE_CONVERSATION *lpvconv = g_new(VULTURE_CONVERSATION, 1);
+	
+	lpconv->ui_data = lpvconv;
+
+	lpvconv->lpconv = lpconv;
+	lpvconv->hwndContainer = lpvconv->hwndConv = NULL;
+
+	InitializeCriticalSection(&lpvconv->sync.cs);
+	lpvconv->sync.szTitle = VultureUTF8ToTCHAR(purple_conversation_get_title(lpconv));
+
+	VulturePostUIMessage(g_hwndMain, VUIMSG_NEWCONVERSATION, lpvconv);
+}
+
+
+/**
+ * Called by the UI to free the data allocated by PurpleNewConversation when
+ * the UI is done with it.
+ *
+ * @param	lpvconv		Data to free.
+ */
+void VultureFreeConversation(VULTURE_CONVERSATION *lpvconv)
+{
+	g_free(lpvconv->sync.szTitle);
+	DeleteCriticalSection(&lpvconv->sync.cs);
+	g_free(lpvconv);
+}
+
+
+/**
+ * PurpleConversationUiOps::destroy_conversation callback. Called when a
+ * conversation is being destroyed by the core. This should inform the
+ * front-end to dismantle its UI. The sequence for an interactive request to
+ * close a conversation is therefore: UI requests core to destroy convo, core
+ * tells UI to destroy itself.
+ *
+ * @param	lpconv	Dying conversation.
+ */
+void PurpleDestroyConversation(PurpleConversation *lpconv)
+{
+	VulturePostUIMessage(g_hwndMain, VUIMSG_DESTROYEDCONVERSATION, (VULTURE_CONVERSATION*)lpconv->ui_data);
+}
============================================================
--- vulture/purpleconv.h	07e0efebaf293bbdbe5b9d539c5483915e3002df
+++ vulture/purpleconv.h	07e0efebaf293bbdbe5b9d539c5483915e3002df
@@ -0,0 +1,34 @@
+/*
+ * Vulture - Win32 libpurple client
+ *
+ * purpleconv.h: Conversation back-end.
+ *
+ * Copyright (C) 2009, Gregor Dick <gdick at soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _VULTURE_PURPLECONV_H_
+#define _VULTURE_PURPLECONV_H_
+
+#include "purple.h"
+#include "vultureconv.h"
+
+void PurpleNewConversation(PurpleConversation *lpconv);
+void VultureFreeConversation(VULTURE_CONVERSATION *lpvconv);
+void PurpleDestroyConversation(PurpleConversation *lpconv);
+
+
+#endif
============================================================
--- vulture/vultureconv.c	6a58a82ec94ae3e84c985c2241511db200ef0430
+++ vulture/vultureconv.c	6a58a82ec94ae3e84c985c2241511db200ef0430
@@ -0,0 +1,301 @@
+/*
+ * Vulture - Win32 libpurple client
+ *
+ * vultureconv.c: Conversation UI.
+ *
+ * Copyright (C) 2009, Gregor Dick <gdick at soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+#include <glib.h>
+
+#include "vulture.h"
+#include "resource.h"
+#include "vultureconv.h"
+#include "purpleconv.h"
+#include "vultureblist.h"
+#include "purplemain.h"
+#include "purplequeue.h"
+
+
+#define CONVCONTAINERCLASS	TEXT("VULTURECONVCONTAINER")
+
+
+typedef struct _CONVCONTAINERDATA
+{
+	HWND	hwndTabDlg;
+} CONVCONTAINERDATA;
+
+
+static LRESULT CALLBACK ConvContainerWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
+static INT_PTR CALLBACK ConvContTabDlgProc(HWND hwndDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam);
+static void RecalcTabIndices(HWND hwndTabs);
+
+
+/**
+ * Registers the window class for conversation containers.
+ *
+ * @return Zero on success; non-zero on error.
+ */
+int VultureRegisterConvContainerWindowClass(void)
+{
+	WNDCLASSEX wndclassex;
+
+	wndclassex.cbClsExtra = 0;
+	wndclassex.cbSize = sizeof(wndclassex);
+	wndclassex.cbWndExtra = 0;
+	wndclassex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
+	wndclassex.hCursor = LoadCursor(NULL, IDC_ARROW);
+	wndclassex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+	wndclassex.hIconSm = LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR | LR_SHARED);
+	wndclassex.hInstance = g_hInstance;
+	wndclassex.lpfnWndProc = ConvContainerWndProc;
+	wndclassex.lpszClassName = CONVCONTAINERCLASS;
+	wndclassex.lpszMenuName = MAKEINTRESOURCE(IDM_CONV);
+	wndclassex.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
+
+	if(!RegisterClassEx(&wndclassex))
+		return 1;
+
+	return 0;
+}
+
+
+/**
+ * Creates a conversation-container window.
+ *
+ * @return Window handle, or NULL on error.
+ */
+HWND VultureCreateConvContainer(void)
+{
+	return CreateWindowEx(
+		WS_EX_WINDOWEDGE,
+		CONVCONTAINERCLASS,
+		cg_szAppName,
+		WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+
+		/* TODO: Read geometry from preferences. */
+		CW_USEDEFAULT, CW_USEDEFAULT,
+		480, 640,
+
+		NULL, 
+		NULL,
+		g_hInstance,
+		NULL);
+}
+
+
+/**
+ * Window procedure for conversation containers.
+ *
+ * @param	hwnd	Buddy-list handle.
+ * @param	uiMsg	Message ID.
+ * @param	wParam	Message-specific.
+ * @param	lParam	Message-specific.
+ *
+ * @return Message-specific.
+ */
+static LRESULT CALLBACK ConvContainerWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+	CONVCONTAINERDATA *lpccd;
+
+	switch(uiMsg)
+	{
+	case WM_CREATE:
+		{
+			RECT rcClient;
+
+			lpccd = (CONVCONTAINERDATA*)ProcHeapAlloc(sizeof(CONVCONTAINERDATA));
+			SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)lpccd);
+
+			/* Create the tab control. */
+			GetClientRect(hwnd, &rcClient);
+			lpccd->hwndTabDlg = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_CONVCONT), hwnd, ConvContTabDlgProc);
+		}
+
+		return 0;
+
+	case WM_PURPLEUIMSG:
+
+		lpccd = (CONVCONTAINERDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+		switch(wParam)
+		{
+		case VUIMSG_NEWCONVERSATION:
+			{
+				VULTURE_CONVERSATION *lpvconv = (VULTURE_CONVERSATION*)lParam;
+				TCITEM tcitem;
+				HWND hwndTabs = GetDlgItem(lpccd->hwndTabDlg, IDC_TAB_CONVERSATIONS);
+
+				lpvconv->hwndContainer = hwnd;
+
+				/* Create a new tab. */
+				tcitem.mask = TCIF_TEXT | TCIF_PARAM;
+				tcitem.lParam = lParam;
+
+				EnterCriticalSection(&lpvconv->sync.cs);
+					tcitem.pszText = lpvconv->sync.szTitle;
+					lpvconv->iTabIndex = TabCtrl_InsertItem(hwndTabs, TabCtrl_GetItemCount(hwndTabs), &tcitem);
+				LeaveCriticalSection(&lpvconv->sync.cs);
+			}
+
+			break;
+
+		case VUIMSG_DESTROYEDCONVERSATION:
+			{
+				/* Core is getting rid of conversation. Remove
+				 * the UI.
+				 */
+
+				VULTURE_CONVERSATION *lpvconv = (VULTURE_CONVERSATION*)lParam;
+				HWND hwndTabs = GetDlgItem(lpccd->hwndTabDlg, IDC_TAB_CONVERSATIONS);
+
+				TabCtrl_DeleteItem(hwndTabs, lpvconv->iTabIndex);
+				if(lpvconv->hwndConv) DestroyWindow(lpvconv->hwndConv);
+
+				VultureFreeConversation(lpvconv);
+				
+
+				/* If we were the last conversation, take down
+				 * the container, too.
+				 */
+				if(TabCtrl_GetItemCount(hwndTabs) == 0)
+					DestroyWindow(hwnd);
+				else
+					RecalcTabIndices(hwndTabs);
+			}
+
+			break;
+		}
+
+		return 0;
+
+	case WM_SIZE:
+		lpccd = (CONVCONTAINERDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+		SetWindowPos(
+			lpccd->hwndTabDlg,
+			NULL,
+			0,
+			0,
+			LOWORD(lParam),
+			HIWORD(lParam),
+			SWP_NOZORDER | SWP_NOACTIVATE);
+
+		return 0;
+
+
+	case WM_CLOSE:
+		{
+			HWND hwndTabs;
+			int i, iCount;
+			TCITEM tcitem;
+
+			lpccd = (CONVCONTAINERDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+			hwndTabs = GetDlgItem(lpccd->hwndTabDlg, IDC_TAB_CONVERSATIONS);
+			iCount = TabCtrl_GetItemCount(hwndTabs);
+
+			tcitem.mask = TCIF_PARAM;
+
+			for(i = 0; i < iCount; i++)
+			{
+				TabCtrl_GetItem(hwndTabs, i, &tcitem);
+				VultureEnqueueAsyncPurpleCall(PC_DESTROYCONVERSATION, (void*)tcitem.lParam);
+			}
+
+			/* We're not going to be around much longer, but ignore
+			 * the user in the meantime.
+			 */
+			EnableWindow(hwnd, FALSE);
+		}
+		return 0;
+
+
+	case WM_DESTROY:
+
+		lpccd = (CONVCONTAINERDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+		if(lpccd->hwndTabDlg) DestroyWindow(lpccd->hwndTabDlg);
+
+		g_lpglistConvContainers = g_list_remove(g_lpglistConvContainers, hwnd);
+
+		ProcHeapFree(lpccd);
+
+		return 0;
+	}
+
+	return DefWindowProc(hwnd, uiMsg, wParam, lParam);
+}
+
+
+
+#define CONV_CONT_TAB_MARGIN	4
+
+/**
+ * Dialogue procedure for conversation tabs.
+ *
+ * @param	hwndDlg		Dialogue window handle.
+ * @param	uiMsg		Message ID.
+ * @param	wParam		Message-specific.
+ * @param	lParam		Message-specific.
+ *
+ * @return Usually TRUE if message processed and FALSE otherwise. There are
+ * some exceptions for particular messages.
+ */
+static INT_PTR CALLBACK ConvContTabDlgProc(HWND hwndDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+	switch(uiMsg)
+	{
+	case WM_INITDIALOG:
+		/* Let the system set the focus. */
+		return TRUE;
+
+	case WM_SIZE:
+		SetWindowPos(
+			GetDlgItem(hwndDlg, IDC_TAB_CONVERSATIONS),
+			NULL,
+			CONV_CONT_TAB_MARGIN,
+			CONV_CONT_TAB_MARGIN,
+			LOWORD(lParam) - 2 * CONV_CONT_TAB_MARGIN,
+			HIWORD(lParam) - 2 * CONV_CONT_TAB_MARGIN,
+			SWP_NOZORDER | SWP_NOACTIVATE);
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+/**
+ * Reclaculates tab indices cached in conversation structures.
+ *
+ * @param	hwndTabs	Tab control.
+ */
+static void RecalcTabIndices(HWND hwndTabs)
+{
+	int i, iCount = TabCtrl_GetItemCount(hwndTabs);
+	TCITEM tcitem;
+
+	tcitem.mask = TCIF_PARAM;
+
+	for(i = 0; i < iCount; i++)
+	{
+		TabCtrl_GetItem(hwndTabs, i, &tcitem);
+		((VULTURE_CONVERSATION*)tcitem.lParam)->iTabIndex = i;
+	}
+}
============================================================
--- vulture/vultureconv.h	f192aa9fab088f18d858207c6c9d17b88c3a4ae8
+++ vulture/vultureconv.h	f192aa9fab088f18d858207c6c9d17b88c3a4ae8
@@ -0,0 +1,50 @@
+/*
+ * Vulture - Win32 libpurple client
+ *
+ * vultureconv.h: Conversation UI.
+ *
+ * Copyright (C) 2009, Gregor Dick <gdick at soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _VULTURE_VULTURECONV_H_
+#define _VULTURE_VULTURECONV_H_
+
+#include <windows.h>
+
+#include "purple.h"
+
+
+typedef struct _VULTURE_CONVERSATION
+{
+	PurpleConversation	*lpconv;
+	HWND			hwndConv;
+	HWND			hwndContainer;
+	int			iTabIndex;
+
+	/* Data still needed by the core thread after initialisation. */
+	struct
+	{
+		CRITICAL_SECTION	cs;
+		LPTSTR			szTitle;
+	} sync;
+} VULTURE_CONVERSATION;
+
+
+int VultureRegisterConvContainerWindowClass(void);
+HWND VultureCreateConvContainer(void);
+
+#endif
============================================================
--- vulture/Makefile.mingw	cad6e8bd69b84b6dd9145566dc52a72d5fdfc26b
+++ vulture/Makefile.mingw	6cdb7e7cfb24327a2dd53402a15fb0080f641c5b
@@ -60,7 +60,9 @@ VULTURE_C_SRC =	\
 			purplestatus.c \
 			acctmanager.c \
 			purpleacct.c \
-			purpleblist.c
+			purpleblist.c \
+			vultureconv.c \
+			purpleconv.c
 
 VULTURE_RC_SRC = vulture-res.rc
 VULTURE_OBJECTS = $(VULTURE_C_SRC:%.c=%.o) $(VULTURE_RC_SRC:%.rc=%.o)
============================================================
--- vulture/purplemain.c	f61110988de2a0c597d781ae7dd9f57e2516f814
+++ vulture/purplemain.c	84021b5f5116b47535b389fcf6dd81ea49b35df3
@@ -47,11 +47,13 @@
 #include "purpleevloop.h"
 #include "cmdline.h"
 #include "purpleblist.h"
+#include "purpleconv.h"
 
 
 static UINT CALLBACK PurpleThread(void *lpvData);
 static int InitLibpurple(void);
 static void InitUI(void);
+static void Quitting(void);
 
 
 
@@ -131,9 +133,14 @@ static int InitLibpurple(void)
 {
 	static PurpleCoreUiOps s_coreuiops = 
 	{
-		NULL, NULL, InitUI, NULL,
-		/* padding */
-		NULL, NULL, NULL, NULL
+		NULL,
+		NULL,
+		InitUI,
+		Quitting,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
 	};
 
 	gchar *szCustomUserDir;
@@ -173,9 +180,43 @@ static void InitUI(void)
 		NULL, NULL, NULL, NULL
 	};
 
+	static PurpleConversationUiOps s_convuiops = 
+	{
+		PurpleNewConversation,		/* create_conversation	*/
+		PurpleDestroyConversation,	/* destroy_conversation	*/
+		NULL,				/* write_chat		*/
+		NULL,				/* write_im		*/
+		NULL,				/* write_conv		*/
+		NULL,				/* chat_add_users	*/
+		NULL,				/* chat_rename_user	*/
+		NULL,				/* chat_remove_users	*/
+		NULL,				/* chat_update_user	*/
+		NULL,				/* present		*/
+		NULL,				/* has_focus		*/
+		NULL,				/* custom_smiley_add	*/
+		NULL,				/* custom_smiley_write	*/
+		NULL,				/* custom_smiley_close	*/
+		NULL,				/* send_confirm		*/
+		NULL,				/* reserved		*/
+		NULL,				/* reserved		*/
+		NULL,				/* reserved		*/
+		NULL,				/* reserved		*/
+	};
+
 	purple_blist_set_ui_ops(&s_blistuiops);
+	purple_conversations_set_ui_ops(&s_convuiops);
 
 	/* Create and load libpurple's buddy-list. */
 	purple_set_blist(purple_blist_new());
 	purple_blist_load();
 }
+
+
+/**
+ * PurpleCoreUiOps::quit callback.
+ */
+static void Quitting(void)
+{
+	/* The core is on its way out, so tell the UI to destroy itself. */
+	VulturePostUIMessage(g_hwndMain, VUIMSG_QUIT, NULL);
+}
============================================================
--- vulture/purplemain.h	58c9cc8b58772a7c3bf48fd8613ad93768fd8821
+++ vulture/purplemain.h	316f5581e87d3f0a41943b45096a2aeaaf98527b
@@ -39,6 +39,14 @@ enum ENUM_VULTURE_UI_MESSAGES
 	VUIMSG_UPDATEBLISTNODE,
 
 	VUIMSG_PURPLEINITCOMPLETE,
+
+	/* (VULTURE_CONVERSATION*) */
+	VUIMSG_NEWCONVERSATION,
+
+	/* (VULTURE_CONVERSATION*) */
+	VUIMSG_DESTROYEDCONVERSATION,
+
+	VUIMSG_QUIT,
 };
 
 
============================================================
--- vulture/purplequeue.c	da54d82063dd5ae8994f9140e9785a7fca4e20d4
+++ vulture/purplequeue.c	b9518c2ba9a6cc5bce22c1dad72a500fbe4cb1d2
@@ -28,6 +28,7 @@
 #include "purplequeue.h"
 #include "purplestatus.h"
 #include "purpleacct.h"
+#include "vultureconv.h"
 
 
 /** Queue node representing a libpurple call. */
@@ -186,7 +187,12 @@ static void DispatchPurpleCall(PURPLE_CA
 		purple_savedstatus_activate(((VULTURE_SAVED_STATUS*)lppurplecall->lpvParam)->lppss);
 		break;
 
+	case PC_DESTROYCONVERSATION:
+		purple_conversation_destroy(((VULTURE_CONVERSATION*)lppurplecall->lpvParam)->lpconv);
+		break;
+
 	case PC_QUIT:
+		purple_core_quit();
 		g_main_loop_quit(g_lpgmainloop);
 		break;
 	}
============================================================
--- vulture/purplequeue.h	2daf6b9a32a6b0d004f7c75b523508cb10f14b52
+++ vulture/purplequeue.h	fdb22c8699d897885c9a8f245d0ae277a2aa60ef
@@ -50,6 +50,9 @@ enum PURPLE_CALL_ID
 
 	/* (VULTURE_SAVED_STATUS*) Status to set. */
 	PC_SETSAVEDSTATUS,
+
+	/* (VULTURE_CONVERSATION*) Conversation to destroy. */
+	PC_DESTROYCONVERSATION,
 };
 
 
============================================================
--- vulture/resource.h	f22c088302e92b5f805a9d52393f300ad6c52761
+++ vulture/resource.h	d106cf2f44a2af555a8278fa173fecfe7ec485c3
@@ -7,10 +7,14 @@
 #define IDD_BLIST                               105
 #define IDD_ACCOUNTS                            107
 #define IDR_ACCEL_MAIN                          109
+#define IDM_CONV                                111
+#define IDD_CONVCONT                            113
+#define IDC_TAB_CONVERSATIONS                   1001
 #define IDC_BUDDY_ICON                          1002
 #define IDC_LIST_ACCOUNTS                       1003
 #define IDC_CBEX_STATUS                         1004
 #define IDM_BLIST_BUDDIES_CLOSE                 40000
+#define IDM_CONV_CONV_CLOSE                     40000
 #define IDS_ERROR_BLIST                         40000
 #define IDM_BLIST_ACCOUNTS_MANAGE               40001
 #define IDS_ERROR_PURPLEINIT                    40001
@@ -18,6 +22,7 @@
 #define IDC_EDIT_STATUSMSG                      40003
 #define IDS_ACCMGR_PROTOCOL                     40003
 #define IDC_TREE_BLIST                          40004
+#define IDS_ERROR_CONVCONTCLASS                 40004
 #define IDC_BTN_ACCOUNT_ADD                     40005
 #define IDC_BTN_ACCOUNT_PROPERTIES              40006
 #define IDC_BTN_ACCOUNT_DELETE                  40007
============================================================
--- vulture/vulture-res.rc	099f8b8646ca4235743f0fe537a0e466c0768d60
+++ vulture/vulture-res.rc	65230b716419b95bb111f8b085aa1fad14e80969
@@ -26,6 +26,17 @@ IDM_BLIST MENU
 
 
 
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+IDM_CONV MENU
+{
+    POPUP "&Conversation"
+    {
+        MENUITEM "&Close", IDM_CONV_CONV_CLOSE
+    }
+}
+
+
+
 //
 // Dialog resources
 //
@@ -59,6 +70,17 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_U
 
 
 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+IDD_CONVCONT DIALOG 0, 0, 281, 169
+STYLE DS_3DLOOK | DS_CENTER | DS_SHELLFONT | WS_VISIBLE | WS_CHILDWINDOW
+EXSTYLE WS_EX_TRANSPARENT
+FONT 8, "Ms Shell Dlg"
+{
+    CONTROL         "", IDC_TAB_CONVERSATIONS, WC_TABCONTROL, TCS_FOCUSNEVER, 5, 5, 270, 160, WS_EX_TRANSPARENT
+}
+
+
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
 IDD_STATUS DIALOG 0, 0, 161, 41
 STYLE DS_3DLOOK | DS_CENTER | DS_CONTROL | DS_SHELLFONT | WS_VISIBLE | WS_CHILDWINDOW
 FONT 8, "Ms Shell Dlg"
@@ -81,6 +103,7 @@ STRINGTABLE
     IDS_ERROR_PURPLEINIT          "Couldn't initialise libpurple."
     IDS_ACCMGR_ACCOUNT            "Account"
     IDS_ACCMGR_PROTOCOL           "Protocol"
+    IDS_ERROR_CONVCONTCLASS       "Couldn't register conversation container class."
 }
 
 
============================================================
--- vulture/vulture.c	75bd6f1e9dcef87487b4cb827597312fcae34a7d
+++ vulture/vulture.c	b0a2971e40e97bbe423f58855f873937948413a0
@@ -31,6 +31,7 @@
 #include "purplemain.h"
 #include "purplequeue.h"
 #include "cmdline.h"
+#include "vultureconv.h"
 
 
 HINSTANCE g_hInstance;
@@ -67,6 +68,12 @@ int WINAPI WinMain(HINSTANCE hinst, HINS
 
 	VultureParseCommandLine();
 
+	if(VultureRegisterConvContainerWindowClass() != 0)
+	{
+		MessageBoxFromStringTable(NULL, IDS_ERROR_CONVCONTCLASS, MB_ICONERROR);
+		return VEC_ERROR_CONVCONTCLASS;
+	}
+
 	if(VultureCreateMainWindow(iCmdShow) != 0)
 	{
 		MessageBoxFromStringTable(NULL, IDS_ERROR_BLIST, MB_ICONERROR);
@@ -92,10 +99,9 @@ int WINAPI WinMain(HINSTANCE hinst, HINS
 		}
 	}
 
-	/* UI has shut down; do the same to libpurple, waiting until it's
+	/* UI has shut down; wait for libpurple, waiting until it's
 	 * complete.
 	 */
-	VultureEnqueueAsyncPurpleCall(PC_QUIT, NULL);
 	WaitForSingleObject(hthreadPurple, INFINITE);
 	CloseHandle(hthreadPurple);
 
============================================================
--- vulture/vultureblist.c	767d4092c8e24dea114ee319765908f07381ddf2
+++ vulture/vultureblist.c	09f38cce5acccfd86f57f6d311360421bb1e290a
@@ -33,6 +33,7 @@
 #include "acctmanager.h"
 #include "purpleacct.h"
 #include "purplemain.h"
+#include "vultureconv.h"
 
 
 static LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
@@ -46,6 +47,7 @@ HWND g_hwndMain = NULL;
 
 
 HWND g_hwndMain = NULL;
+GList *g_lpglistConvContainers = NULL;
 
 static GList *g_lpglistStatuses = NULL;
 
@@ -262,14 +264,56 @@ static LRESULT CALLBACK MainWndProc(HWND
 			}
 
 			break;
+
+		case VUIMSG_NEWCONVERSATION:
+			if(!g_lpglistConvContainers)
+				g_lpglistConvContainers = g_list_prepend(g_lpglistConvContainers, VultureCreateConvContainer());
+
+			/* Fall through. */
+			
+		case VUIMSG_DESTROYEDCONVERSATION:
+			/* Forward the message to the first container. */
+			SendMessage((HWND)g_lpglistConvContainers->data, uiMsg, wParam, lParam);
+
+			break;
+
+		case VUIMSG_QUIT:
+			DestroyWindow(hwnd);
+			break;
 		}
 
 		return 0;
 
+
+	case WM_CLOSE:
+		{
+			GList *lpglistRover;
+
+			for(lpglistRover = g_lpglistConvContainers; lpglistRover; lpglistRover = lpglistRover->next)
+				SendMessage((HWND)lpglistRover->data, WM_CLOSE, 0, 0);
+
+			VultureEnqueueAsyncPurpleCall(PC_QUIT, NULL);
+
+			/* Ignore the user for the rest of our life. */
+			EnableWindow(hwnd, FALSE);
+		}
+
+		/* Don't destroy the window. The core will signal this thread
+		 * to do so later.
+		 */
+		return 0;
+
+
 	case WM_DESTROY:
+		
 		DestroyWindow(s_hwndBListDlg);
 		DestroyWindow(s_hwndStatusDlg);
+
+		if(g_lpglistConvContainers)
+			g_list_free(g_lpglistConvContainers);
+
 		PostQuitMessage(VEC_SUCCESS);
+
 		return 0;
 	}
 
============================================================
--- vulture/vultureblist.h	be90fd23547bdeaea7f70fbd864627b7c48a2c32
+++ vulture/vultureblist.h	e6ed29d75ce6780b1837f9f4069b0270d7d73990
@@ -41,6 +41,7 @@ extern HWND g_hwndMain;
 
 
 extern HWND g_hwndMain;
+GList *g_lpglistConvContainers;
 
 
 int VultureCreateMainWindow(int iCmdShow);


More information about the Commits mailing list