It's been an entire summer since I first looked into building a win32 version of Sean Egan's webkit plugin. I promised to tell Megarian first when I got it working. Here's a proof of concept screenshot of how it renders the default style.
Webkit rendering the default style
It fails to render the images for some reason, so it looks very plain. Here's how the GoneDark style looks:
Webkit rendering the GoneDark style
To use this, download the "webkit.zip" file release and install the contents to your Carrier installation directory, i.e. move the dll files and the "carrier" folder into "C:\Program Files\Carrier" and move the "plugins\webkit.dll" file into "C:\Program Files\Carrier\plugins". An immediately obvious bug when Carrier starts will be red x's in place of every icon. This has to do with Pidgin not expecting libgdk_pixbuf-2.0-0.dll to be present, so a stupid kludge would be to move that dll into system32. If the "Adium Message Styles" plugin still does not appear in the list, you might need the library dwmapi.dll to be in system32. Also, because I'm an idiot the plugin will only render the style found in "carrier\webkit\defaultstyle" and nothing else. So when you decide to use a style, make sure it resides in this folder and keep the plugin set to "Cloudborne (default)".

Getting the images above to render properly could be as simple as a few CSS changes, or it could involve spending months studying the webkit code and making it use functions better supported by windows and recompiling webkit along with several dependencies. Hell, maybe the Windows install I used was just broken and your images will show up right away. Ordinarily I'd try to tackle this problem some more, but I've already spent a whole summer on what many would consider a "stupid fixation" and I wouldn't know where to start. Please tell me if anyone finds a probable cause.

One thing you could try is downloading the libwebkit-1.0. file release, replacing your webkit.dll with the much smaller webkit.dll from that archive and moving libwebkit-1.0-1.dll into your installation dir. This version of the plugin (built against a dynamic webkit) would not work for me because libwebkit-1.0-1.dll was expecting different functions to be in my system libraries (user32, shell32, kernel32, etc) but with all the different versions of Windows out there, it will surely load for some people. Another idea might be building Pidgin against the latest GTK+ packages from the all-in-one bundle. This will break Windows9x compatibility but might give better results for this plugin.

What kind of citizen would I be distributing all this GPL'd software in binary form without describing the modifications I made? The WebKit.dll from http://nightly.webkit.org will not help here so to compile the plugin, you'll have to use a library from the libwebkit-1.0 file release or build your own. An official win32 build of WebKitGTK+ doesn't exist as of August 2008. The following is a howto that will take you through compiling libwebkit-1.0.a, libwebkit-1.0-1.dll, libwebkit-1.0.dll.a and webkit.dll with MinGW. If you want to attempt it, make sure you have at least one free weekend to devote. It's a pain in the ass and more trouble than it's worth. Three methods come to mind:
  1. MSYS: This is what I used. All the executables and libraries in your build environment will have to be windows versions - simple. However, the shell is a crude hack that requires entering the "full path" for some programs, e.g. $ /c/MinGW/bin/program instead of $ program even if "/c/MinGW/bin" is in your PATH. It also destroys some combinations of quotes.
  2. Cygwin: This shell just works; it's probably what I would have used if I had to do it all over again. The Cygwin setup lets you conveniently install hundreds of packages. Use this to install the required executables but not the libraries. The libraries must be native windows versions, not Cygwin versions. Also, commands like gcc and g++ will need to be called using the "-mno-cygwin" falg. Since the makefiles call these commands automatically, you'll want to add alias gcc='gcc -mno-cygwin' and alias g++='g++ -mno-cygwin' to your bashrc.
  3. MinGW cross-compiler that runs on GNU/Linux: Use this in your favourite shell. The executables will be Linux versions which you'll probably have already but the librares will still have to be windows versions. The packages in your distro will probably name gcc something like i486-mingw32-gcc or i586-mingw32msvc-cc and similarly for g++ so you'll probably want to alias while you're cross-compiling. You'll also have to track down copies of some Windows headers like windows.h in order to build Pidgin plugins.


  4. Setting up your build environment

    I started by downloading MinGW-5.1.4.exe, MSYS-1.0.10.exe and msysDTK-1.0.1.exe from the MinGW file list and installing them in that order. They appear only to work on 32-bit systems. After installing MSYS, I also needed to upgrade to autoconf2.5-2.61-1.tar.bz2 and install crypt-1.1-1-MSYS-1.0.11-1.tar.bz2 and regex-0.12-MSYS-1.0.11-1.tar.bz2 from the MinGW list as well as install gperf-3.0.1.exe and upgrade to m4-1.4.9.exe from the GNUWin32 list. I installed everything to the C:\MinGW\ root.

    If you're using Cygwin, the equivalent packages would probably be autoconf, automake, bash, binutils, bison, bzip2, crypt, coreutils, cygutils, cygwin, flex, gawk, gcc-mingw, gcc-mingw-g++, gperf, grep, gzip, libtool, m4, make, mingw-runtime, patch, perl, pkg-config, sed, tar, unzip and wget.

    Perl

    Cygwin includes Perl 5.10 so it might not need to be changed. However, the Perl 5.6 that comes with MSYS is too out of date. If you're using MSYS, install ActivePerl or Strawberry Perl and make sure the perl executable can be found inside your PATH. Now get rid of the perl.exe that comes with MSYS and run $ aclocal --help, $ autoconf --help and $ autoheader --help to make sure they work. If none of them work, you might have to change the /bin/perl -w path at the top of each script. If autoheader is the only one that doesn't work you might need to modify the paths in the script so that it can find Autom4te.

    Library dependencies

    GTK:
    To make your life a little easier, GTK+ provides an all-in-one bundle which should be installed to the C:\MinGW\ or C:\cygwin root mainly worrying about bin, etc, include, lib and share.

    Jpeg:
    Install jpeg from GNUWin32 and let it overwrite what you already got from GTK+.

    ICU:
    Installing ICU 4.0 will be easy. There were a few places where WebKit had trouble finding these headers so to be safe, you might want to dump the contents of C:\MinGW\include\unicode or C:\cygwin\include\unicode into C:\MinGW\include or C:\cygwin\include respectively.

    Curl:
    The best one to get is libcurl. If curl.h contains any type called socklen_t change all occurences to unsigned int.

    XML and XSLT:
    Grab libxml2 and libxslt. This time, the files in the lib directories don't appear to work. Instead, move libxml2.dll and libxslt.dll from the bin directories, into C:\MinGW\lib or C:\cygwin\lib. Also, the WebKit configure script wanted a C:\MinGW\lib\pkgconfig\libxslt.pc file so here's what I used:
    prefix=/c/MinGW exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: libxslt Version: 1.1.23 Description: XSLT library version 2. Requires: libxml-2.0 Libs: -L${libdir} -lxslt -lxml2 -lz -lm -lm Cflags: -I${includedir}


    SQLite:
    Suggestion from Camarade_Tux: if you issue the configure switches --disable-offline-web-applications --disable-dom-storage --disable-database --disable-icon-database SQLite3 will no longer be a dependency. SQLite3 will be another dll link time dependency in C:\MinGW\lib or C:\cygwin\lib. You will also need sqlite3.h from the amalgamation to go in your C:\MinGW\include or C:\cygwin\include. I had to write a .pc file for this one too. Here is my C:\MinGW\lib\pkgconfig\sqlite3.pc:
    prefix=/c/MinGW exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: SQLite Description: SQL database engine Version: 3.6.1 Libs: -L${libdir} -lsqlite3 Libs.private: -lpthreadGCE2 Cflags: -I${includedir}


    Pthread:
    Go to folder containing the posix threads for win32 and put everything from the include folder into your own C:\MinGW\include or C:\cygwin\include. As for the libs, I wasn't really sure which ones to get. On very vague advice of a few google searches I ended up putting libpthreadGCE2.a in C:\MinGW\lib and putting pthreadGCE2.dll in C:\MinGW\bin.

    Iconv:
    The GTK+ bundle already provides iconv as a link time dependency but you'll need the iconv.dll runtime dependency to use the plugin. There are thousands of ways to get it, I picked up this copy.

    The WebKit source

    Download a copy of the WebKit source from http://nightly.webkit.org and extract it wherever you want with $ tar -xjf WebKit-r#####.tar.bz2. I am thankful to the folks in #webkit for knowing what to change. I got started with a patch by alp and had to change a few more files as I went with help from others, mainly bdash. Download the patch, put it in your source tree and apply it with WebKit-r##### $ patch -p0 < win32-changes.patch. This fixes quite a few problem areas but it may not fix all of them. Every revision has its own quirks, e.g. when I started with r35177, AccessibilityImageMapLink.cpp wasn't part of the build; that was fixed in r35179. As a final precaution, let your toolchain know where to store temporary files with $ export TMPDIR=/c/Temp or wherever you think they should go and if you're using MSYS, you'll want to $ export PKG_CONFIG_PATH=/c/MinGW/lib as well.

    Starting the build

    In MSYS, pkg-config is one of those annoying programs that requires a full path, so start the build with WebKit-r##### $ PKG_CONFIG=/c/MinGW/bin/pkg-config.exe ./autogen.sh --prefix=/c/MinGW --with-font-backend=pango --with-target=win32. If you're using Cygwin, you can probably just type WebKit-r##### $ make when the script finishes, if you're using MSYS there are a few more things you have to do.

    For some reason, my GNUMakefile was missing newline backslashes for the first thousand lines or so. I tediously added them one by one but it's definitely possible to write a script for this purpose. Also if you had to specify absolute perl paths in aclocal, autoconf and autoheader, you'll probably have to do this for a few more perl scripts, namely C:\MinGW\bin\glib-mkenums, JavaScriptCore\pcre\dftables, WebCore\dom\make_names.pl, WebCore\css\make-css-file-arrays.pl and WebCore\bindings\scripts\generate-bindings.pl. If your shell is showing any signs of the "full path" bug, you'll want to hand edit the GNUMakefile to be safe. I had to change it to show PERL=/c/Perl/bin/perl, GPERF=/c/MinGW/bin/gperf and GLIB_GENMARSHAL=/c/MinGW/bin/glib-genmarshal. While you're at it, search for /lib and -Ic to make sure your library and include paths are respectively correct. The last bug to fix involves gperf invocations. Search for GPERF and when you find it change the flag that looks like -k '*' or -k "*" to -k*. This should have the same effect while bypassing another bug in MSYS. Now you can finally type WebKit-r##### $ make.

    Linking the library

    If you have a fast computer and an error-free build environment wait about an hour, then start bragging about how your build was 24 times faster than mine. My computer was extremely slow, I had errors left and right and I had to start over once when I was near the end to fix a particularly nasty one.

    Anyway, libtool should have no problem linking 41 object files to make libJavaScriptCore.a and then linking an additional 1187 object files to libJavaScriptCode.a to make libWebCore.a but bringing those last 17 webkit related object files into play causes some interesting behaviour. If your case is anything like mine, libtool will start saying that your libraries don't match the expected format, something to do with "a file magic". This is because libtool is trying to run "file" on all of your libraries and if you don't have file, the result it's getting, "command not found" is obviously not what it's expecting. This turned out to be a good thing, because it made libtool resort to building libwebkit-1.0 as a static archive. This gets you the libwebkit-1.0.a you're after. If you're running Cygwin or mingw32 on GNU/Linux your libtool file will probably be completely different. If you can't get it to build libwebkit-1.0.a, create the archive yourself using:
    WebKit-r##### $ mkdir tmp && cd temp temp $ cp ../.libs/libJavaScriptCore.a libJavaScriptCore.a && cp ../.libs/libWebCore.a libWebCore.a temp $ ar -x libJavaScriptCore.a && rm libJavaScriptCore.a && ar -x libWebCore.a && rm libWebCore.a temp $ cp ../DerivedSources/.libs/libwebkit_1_0_la-webkit-marshal.o libwebkit_1_0_la-webkit-marshal.o temp $ cp ../DerivedSources/.libs/libwebkit_1_0_la-webkitenumtypes.o libwebkit_1_0_la-webkitenumtypes.o temp $ cp ../WebKit/gtk/WebCoreSupport/.libs/libwebkit_1_0_la-ChromeClientGtk.o libwebkit_1_0_la-ChromeClientGtk.o temp $ cp ../WebKit/gtk/WebCoreSupport/.libs/libwebkit_1_0_la-ContextMenuClientGtk.o libwebkit_1_0_la-ContextMenuClientGtk.o temp $ cp ../WebKit/gtk/WebCoreSupport/.libs/libwebkit_1_0_la-DragClientGtk.o libwebkit_1_0_la-DragClientGtk.o temp $ cp ../WebKit/gtk/WebCoreSupport/.libs/libwebkit_1_0_la-EditorClientGtk.o libwebkit_1_0_la-EditorClientGtk.o temp $ cp ../WebKit/gtk/WebCoreSupport/.libs/libwebkit_1_0_la-FrameLoaderClientGtk.o libwebkit_1_0_la-FrameLoaderClientGtk.o temp $ cp ../WebKit/gtk/WebCoreSupport/.libs/libwebkit_1_0_la-InspectorClientGtk.o libwebkit_1_0_la-InspectorClientGtk.o temp $ cp ../WebKit/gtk/WebCoreSupport/.libs/libwebkit_1_0_la-PasteboardHelperGtk.o libwebkit_1_0_la-PasteboardHelperGtk.o temp $ cp ../WebKit/gtk/webkit/.libs/libwebkit_1_0_la-webkitnetworkrequest.o libwebkit_1_0_la-webkitnetworkrequest.o temp $ cp ../WebKit/gtk/webkit/.libs/libwebkit_1_0_la-webkitprivate.o libwebkit_1_0_la-webkitprivate.o temp $ cp ../WebKit/gtk/webkit/.libs/libwebkit_1_0_la-webkitversion.o libwebkit_1_0_la-webkitversion.o temp $ cp ../WebKit/gtk/webkit/.libs/libwebkit_1_0_la-webkitwebbackforwardlist.o libwebkit_1_0_la-webkitwebbackforwardlist.o temp $ cp ../WebKit/gtk/webkit/.libs/libwebkit_1_0_la-webkitwebframe.o libwebkit_1_0_la-webkitwebframe.o temp $ cp ../WebKit/gtk/webkit/.libs/libwebkit_1_0_la-webkitwebhistoryitem.o libwebkit_1_0_la-webkitwebhistoryitem.o temp $ cp ../WebKit/gtk/webkit/.libs/libwebkit_1_0_la-webkitwebsettings.o libwebkit_1_0_la-webkitwebsettings.o temp $ cp ../WebKit/gtk/webkit/.libs/libwebkit_1_0_la-webkitwebview.o libwebkit_1_0_la-webkitwebview.o temp $ cd .. && ar -r libwebkit-1.0.a ./temp/* WebKit-r##### $ ranlib libwebkit-1.0.a

    Once I had libwebkit-1.0.a, I still received several errors when building the Programs like jsc.exe and I still don't know why, but those programs aren't important for compiling WebKitGTK+ applications. I went back to try and build a shared library and an import library for it. It's easy to install "file" from the Cygwin setup, or GNUWin32 but it is one of those annoying programs that requires the "full path" so I had to hand edit libtool to give it that path. When this was done, retrying the build got libtool to recognize all of my libraries. It then made "reloadable object files" in .libs, named libwebkit-1.0.la-1.o, libwebkit-1.0.la-2.o, libwebkit-1.0.la-3.o all the way up to libwebkit-1.0.la-11.o. It then tried to create libwebkit-1.0-1.dll and the libwebkit-1.0.dll.a import lib from libwebkit-1.0.la-11.o using g++ -shared and it got the command completely wrong.

    Even after I fixed the errors in the command libtool invoked, ld kept running out of memory because the actual object code libwebkit-1.0.la-11.o was faulty. I found the best way to go about this is to convert the static archive into a shared library with this command:
    $ g++ -shared -Wl,--whole-archive ./libwebkit-1.0.a -L/c/MinGW/lib -lgthread-2.0 -lgtk-win32-2.0 -lgdk-win32-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangowin32-1.0 -lpangocairo-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -lintl -lcairo -lcurl -lgdi32 -lwinmm -lwldap32 -lws2_32 -licuuc -licuin -licudt -lsqlite3 -lxslt -lz -lm -lxml2 -lpthreadGCE2 -ljpeg -lpng12 -lstdc++ -Wl,--allow-multiple-definition -Wl,--enable-auto-import -Wl,--enable-auto-image-base -Wl,--exclude-symbols,icuin40_NULL_THUNK_DATA -Wl,--exclude-symbols,icuuc40_NULL_THUNK_DATA -o ./libwebkit-1.0-1.dll -Wl,--out-implib,libwebkit-1.0.dll.a

    Note that those tunking symbols you need to exclude start with a delete sign (ASCII 127, Unicode 007F) so if you can't type that in your terminal emulator, you'll need to type the above command in a text editor, save it as a script and then execute that script. If you're using Cygwin (whose libmingw32.a does not contain main.o) this should work. If you're using MSYS, you will probably get an error that looks like this: libmingw32.a(main.o)(.text+0x8e): undefined reference to `WinMain@16'. This is a very common error and a quick google search will turn up dozens of possible fixes and chances are none of them will work. The way I "fixed" it was by taking main.o out of libmingw32.a:
    lib $ mkdir temp lib $ mv libmingw32.a temp/mingw32.a lib $ cd temp temp $ ar -x libmingw32.a temp $ rm libmingw32.a main.o temp $ cd .. lib $ ar -r libmingw32.a temp/* lib $ rm -r temp lib $ ranlib libmingw32.a

    Once the shared webkit library is built, you should link the plugin to libwebkit-1.0.dll.a which will make libwebkit-1.0-1.dll a runtime dependency of the plugin. I still haven't tested the plugin which is built against the webkit dll as it expected too much out of my system libraries. The plugin built against the static archive is probably more likely to work on several versions of Windows but perhaps the dynamic one will work better.

    Compiling the plugin

    If you've made it this far, compiling the plugin will be simple. This is where the library dependencies come into play so make sure you have the following files in your lib folder which we'll call HOME_SWEET_HOME:
    libgthread-2.0.dll.a libgtk-win32-2.0.dll.a libgdk-win32-2.0.dll.a libatk-1.0.dll.a libgdk_pixbuf-2.0.dll.a libpangowin32-1.0.dll.a libpangocairo-1.0.dll.a libpango-1.0.dll.a libgobject-2.0.dll.a libgmodule-2.0.dll.a libglib-2.0.dll.a libintl.dll.a libcairo.dll.a libcurl.a libgdi32.a libwinmm.a libwldap32.a libws2_32.a icuin.lib icuuc.lib sqlite3.dll libxslt.dll libm.a libz.a libxml2.dll libpthreadGCE2.a libjpeg.dll.a libpng12.dll.a libstdc++.a

    To compile webkit.c into webkit.o, the easiest way is to start by setting up the build environment for Pidgin (or Carrier) as described by the BuildingWinPidgin instructions. For the additional headers, make the folders win32-dev\webkit-1.0\include\webkit and win32-dev\webkit-1.0\include\JavaScriptCore. Populate the webkit folder with the header files from WebKit-r#####\WebKit\gtk and populate the JavaScriptCore folder with the headers from WebKit-r#####\JavaScriptCore\API. If you plan on using the dynamic libwebkit-1.0.dll.a, keep webkitdefines.h the same. If you are using libwebkit-1.0.a, go into webkitdefines.h and change __declspec(dllimport) and __declspec(dllexport) to extern. Now you should take whatever webkit library you plan on using and move it to win32-dev\webkit-1.0\lib. There are also three changes you should make to webkit.c:
    1. Add #define G_GNUC_NULL_TERMINATED to the very top of the file.
    2. Add [code]#include [/code] to the /* Purple headers */ section. You might also want to go into win32dep.h and change DATADIR to something else like WEBKITDATADIR (and propogate that change through webkit.c). Some part of my toolchain defined something called DATADIR to an enum which caused conflicts.
    3. Fix the bug that forces the plugin to only use the defaultstyle on Windows, that I am too stupid to find.

    Now compiling the plugin will be a matter of issuing these two commands:
    $ gcc -O2 -Wall -pipe -mno-cygwin -mms-bitfeilds -g -I. -I../../../../win32-dev/webkit-1.0/include -I../../../../win32-dev/gtk_2_0/include -I../../../../win32-dev/gtk_2_0/include/gtk-2.0 -I../../../../win32-dev/gtk_2_0/include/glib-2.0 -I../../../../win32-dev/gtk_2_0/include/pango-1.0 -I../../../../win32-dev/gtk_2_0/include/atk-1.0 -I../../../../win32-dev/gtk_2_0/include/cairo -I../../../../win32-dev/gtk_2_0/lib/glib-2.0/include -I../../../../win32-dev/gtk_2_0/lib/gtk-2.0/include -I../../../libpurple -I../../../libpurple/win32 -I../../../carrier -I../../../carrier/win32 -I../../.. -o webkit.o -c webkit.c $ gcc -mno-cygwin -shared webkit.o -L../../../../win32-dev/webkit-1.0/lib -L../../../libpurple -L../../../carrier -LHOME_SWEET_HOME -lwebkit-1.0 -lgthread-2.0 -lgtk-win32-2.0 -lgdk-win32-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangowin32-1.0 -lpangocairo-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -lintl -lcairo -lcurl -lgdi32 -lwinmm -lwldap32 -lws2_32 -licuin -licuuc -lsqlite3 -lxslt -lz -lm -lxml2 -lpthreadGCE2 -ljpeg -lpng12 -lstdc++ -lpurple -lcarrier -Wl,--enable-auto-image-base -Wl,--enable-auto-import -Wl,--enable-stdcall-fixup -o webkit.dll

    Once you build the dll it's just a matter of installing the plugin as described in the "teaser" part of this story. You just put it in the plugins folder, add the carrier\webkit\defaultstyle and carrier\webkit\Template.html and put the following runtime dependencies which you should already have, loose in your Pidgin install dir:
    iconv.dll icudt40.dll icuin40.dll icuuc40.dll intl.dll jpeg62.dll libatk-1.0-0.dll libcairo-2.dll libcurl.dll libgdk-win32-2.0-0.dll libgdk_pixbuf-2.0-0.dll libglib-2.0-0.dll libgmodule-2.0-0.dll libgobject-2.0-0.dll libgthread-2.0-0.dll libgtk-win32-2.0-0.dll libpango-1.0-0.dll libpangocairo-1.0-0.dll libpangowin32-1.0-0.dll libpng12.dll libxslt.dll mingwm10.dll pthreadGCE2.dll sqlite3.dll zlib1.dll


    Acknowledgements go out to two good friends who let me borrow their computers and helpful people in #mingw, #webkit, #cygwin, #gnu and #pidgin.