You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

812 lines
25 KiB

/*
* Copyright (C) 2000 Brian Harris
*
* 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// ie_favorites.cpp : Plugin that supports ie-style boomarks
//
#include "stdafx.h"
#include "resource.h"
#include "wininet.h" // for INTERNET_MAX_URL_LENGTH
#include <vector>
#define KMELEON_PLUGIN_EXPORTS
#include "../kmeleon_plugin.h"
#include "../Utils.h"
#include "../rebar_menu/hot_tracking.h"
#define PLUGIN_NAME "IE Favorites Plugin"
#define TOOLBAND_LABEL "Links"
#define PREFERENCE_REBAR_ENABLED _T("kmeleon.plugins.favorites.rebar")
#define REG_USER_SHELL_FOLDERS _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders")
#define REG_SHELL_FOLDERS _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders")
#define REG_FAVORITES_KEY _T("Favorites")
#define MAX_FAVORITES 4096
#define ERROR_TOO_MANY_FAVORITES "Error! You have too many favorites!\n\n" \
"Right now, only 4096 favorites are supported"
static CStringArray gFavorites; // this one contains the display filename (Really...vorite)
static CStringArray gFavoritesFiles; // this one contains the full filename (SomeFolder\Stuff\Really Long Favorite)
static CArray<UINT, int> gIcons;
static UINT gNumFavorites;
static int gInternetShortcutIcon;
static int gFolderIcon;
static HIMAGELIST gSystemImages;
static CSize gSysImageSize;
static HMENU gFavoritesMenu;
static UINT nConfigCommand;
static UINT nAddCommand;
static UINT nEditCommand;
static UINT nFirstFavoriteCommand;
static BOOL bRebarEnabled;
static HINSTANCE ghInstance;
static TCHAR gFavoritesPath[MAX_PATH];
static int gFavoritesPathLen;
static WNDPROC KMeleonWndProc;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int BuildFavoritesMenu(char * strPath, HMENU mainMenu);
BOOL CALLBACK DlgProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int Load();
void Create(HWND parent);
void Config(HWND parent);
void Quit();
void DoMenu(HMENU menu, char *param);
int DoAccel(char *param);
void DoRebar(HWND rebarWnd);
long DoMessage(const char *to, const char *from, const char *subject, long data1, long data2);
kmeleonPlugin kPlugin = {
KMEL_PLUGIN_VER,
PLUGIN_NAME,
DoMessage
};
/* End K-Meleon Plugin Header */
long DoMessage(const char *to, const char *from, const char *subject, long data1, long data2)
{
if (to[0] == '*' || stricmp(to, kPlugin.dllname) == 0) {
if (stricmp(subject, "Load") == 0) {
Load();
}
else if (stricmp(subject, "Create") == 0) {
Create((HWND)data1);
}
else if (stricmp(subject, "Config") == 0) {
Config((HWND)data1);
}
else if (stricmp(subject, "Quit") == 0) {
Quit();
}
else if (stricmp(subject, "DoRebar") == 0) {
DoRebar((HWND)data1);
}
else if (stricmp(subject, "DoMenu") == 0) {
DoMenu((HMENU)data1, (char *)data2);
}
else if (stricmp(subject, "DoAccel") == 0) {
*(int *)data2 = DoAccel((char *)data1);
}
else return 0;
return 1;
}
return 0;
}
int Load()
{
nConfigCommand = kPlugin.kFuncs->GetCommandIDs(1);
nAddCommand = kPlugin.kFuncs->GetCommandIDs(1);
nEditCommand = kPlugin.kFuncs->GetCommandIDs(1);
nFirstFavoriteCommand = kPlugin.kFuncs->GetCommandIDs(MAX_FAVORITES);
TCHAR sz[MAX_PATH];
HKEY hKey;
DWORD dwSize;
ITEMIDLIST *idl;
long rslt = ERROR_SUCCESS;
// first try the correct way
if (SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &idl) == NOERROR) {
IMalloc *malloc;
SHGetPathFromIDList(idl, sz);
SHGetMalloc(&malloc);
malloc->Free(idl);
malloc->Release();
}
else {
// if the correct way failed, find out from the registry where the favorites are located.
if(RegOpenKey(HKEY_CURRENT_USER, REG_USER_SHELL_FOLDERS, &hKey) == ERROR_SUCCESS) {
dwSize = MAX_PATH;
rslt = RegQueryValueEx(hKey, REG_FAVORITES_KEY, NULL, NULL, (LPBYTE)sz, &dwSize);
RegCloseKey(hKey);
if (rslt != ERROR_SUCCESS) {
if (RegOpenKey(HKEY_CURRENT_USER, REG_SHELL_FOLDERS, &hKey) == ERROR_SUCCESS) {
rslt = RegQueryValueEx(hKey, REG_FAVORITES_KEY, NULL, NULL, (LPBYTE)sz, &dwSize);
RegCloseKey(hKey);
}
else {
TRACE0("Favorites folder not found\n");
rslt = -1;
}
}
}
else {
TRACE0("Favorites folder not found\n");
rslt = -1;
}
}
if (rslt == ERROR_SUCCESS) {
ExpandEnvironmentStrings(sz, gFavoritesPath, MAX_PATH);
strcat(gFavoritesPath, "\\");
gFavoritesPathLen = strlen(gFavoritesPath);
}
else {
gFavoritesPath[0] = 0;
gFavoritesPathLen = 0;
}
// Get the rebar status
int pref = 0;
kPlugin.kFuncs->GetPreference(PREF_BOOL, PREFERENCE_REBAR_ENABLED, &bRebarEnabled, &pref);
return true;
}
void Create(HWND parent)
{
KMeleonWndProc = (WNDPROC) GetWindowLong(parent, GWL_WNDPROC);
SetWindowLong(parent, GWL_WNDPROC, (LONG)WndProc);
}
void Config(HWND hWndParent)
{
gLoc->DialogBoxParam(MAKEINTRESOURCE(IDD_CONFIG), hWndParent, (DLGPROC)DlgProc, NULL);
}
void Quit()
{
DestroyMenu(gFavoritesMenu);
}
void DoMenu(HMENU menu, char *param)
{
// there are no favorites
if (!*gFavoritesPath)
return;
if (*param != 0) {
char *comma = strchr(param, ',');
char *action = param;
char *string = strchr(param, ',');
if (string) {
*string = 0;
string = SkipWhiteSpace(string+1);
}
else
string = action;
int command = 0;
if (stricmp(action, "Config") == 0){
command = nConfigCommand;
}
if (stricmp(action, "Add") == 0){
command = nAddCommand;
}
if (stricmp(action, "Edit") == 0){
command = nEditCommand;
}
if (command) {
AppendMenu(menu, MF_STRING, command, string);
}
}
else {
gInternetShortcutIcon = -1;
gFavoritesMenu = menu;
BuildFavoritesMenu("", gFavoritesMenu);
SHFILEINFO sfi;
gSystemImages = (HIMAGELIST)SHGetFileInfo( gFavoritesPath,
0,
&sfi,
sizeof(SHFILEINFO),
SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
if (gSystemImages != NULL) {
int cx, cy;
ImageList_GetIconSize (gSystemImages, &cx, &cy);
gSysImageSize = CSize (cx, cy);
gFolderIcon = sfi.iIcon;
}
}
}
int DoAccel(char *param)
{
if (stricmp(param, "Config") == 0){
return nConfigCommand;
}
if (stricmp(param, "Add") == 0){
return nAddCommand;
}
if (stricmp(param, "Edit") == 0){
return nEditCommand;
}
return nAddCommand;
}
void DoRebar(HWND rebarWnd){
if (!bRebarEnabled)
return;
DWORD dwStyle = 0x40 | /*the 40 gets rid of an ugly border on top. I have no idea what flag it corresponds to...*/
CCS_NOPARENTALIGN | CCS_NORESIZE | //CCS_ADJUSTABLE |
TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_LIST | TBSTYLE_TOOLTIPS;
// Create the toolbar control to be added.
#if 1
HWND hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, "Links:",
WS_CHILD | dwStyle,
0,0,0,0,
rebarWnd, (HMENU)/*id*/200,
kPlugin.hDllInstance, NULL
);
#else
HWND hwndTB = CreateToolbarEx(rebarWnd, dwStyle,
/*id*/ 200,
/*nBitmaps*/ 0,
/*hBMInst*/ kPlugin.hDllInstance,
/*wBMID*/ 0,
/*lpButtons*/ NULL,
/*iNumButtons*/ 0,
/*dxButton*/ 16,
/*dyButton*/ 16,
/*dxBitmap*/ 16,
/*dyBitmap*/ 16,
/*uStructSize*/ sizeof(TBBUTTON)
);
#endif
if (!hwndTB){
MessageBox(NULL, "Failed to create ie toolbar", NULL, 0);
return;
}
// Register the band name and child hwnd
kPlugin.kFuncs->RegisterBand(hwndTB, "Favorites", true);
SetWindowText(hwndTB, TOOLBAND_LABEL);
//SendMessage(hwndTB, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS);
SendMessage(hwndTB, TB_SETIMAGELIST, 0, (LPARAM)gSystemImages);
SendMessage(hwndTB, TB_SETBUTTONWIDTH, 0, MAKELONG(0, 100));
int stringID;
int index;
MENUITEMINFO mInfo;
mInfo.cbSize = sizeof(MENUITEMINFO);
int i;
int count = GetMenuItemCount(gFavoritesMenu);
HMENU hLinksMenu = NULL;
for (i=0; i<count; i++){
if (GetMenuState(gFavoritesMenu, i, MF_BYPOSITION) & MF_POPUP){
bool isLinksMenu = false;
mInfo.fMask = MIIM_TYPE;
GetMenuItemInfo(gFavoritesMenu, i, MF_BYPOSITION, &mInfo);
if (mInfo.fType == MFT_STRING) {
char temp[128];
mInfo.cch = 127;
mInfo.dwTypeData = temp;
GetMenuItemInfo(gFavoritesMenu, i, MF_BYPOSITION, &mInfo);
isLinksMenu = (mInfo.dwTypeData && stricmp(mInfo.dwTypeData, "Links") == 0);
}
else {
// if it's ownerdrawn, we get at the string another way (damn, this is ugly...)
mInfo.fMask = MIIM_DATA;
GetMenuItemInfo(gFavoritesMenu, i, MF_BYPOSITION, &mInfo);
isLinksMenu = (stricmp((char*)mInfo.dwItemData, "Links") == 0);
}
if (isLinksMenu) {
hLinksMenu = GetSubMenu(gFavoritesMenu, i);
break;
}
}
}
if (hLinksMenu == NULL)
hLinksMenu = gFavoritesMenu;
count = GetMenuItemCount(hLinksMenu);
for (i=0; i<count; i++){
if (GetMenuState(hLinksMenu, i, MF_BYPOSITION) & MF_POPUP){
mInfo.fMask = MIIM_TYPE | MIIM_SUBMENU;
GetMenuItemInfo(hLinksMenu, i, MF_BYPOSITION, &mInfo);
if (mInfo.fType == MFT_STRING) {
char temp[128];
mInfo.cch = 127;
mInfo.dwTypeData = temp;
GetMenuItemInfo(hLinksMenu, i, MF_BYPOSITION, &mInfo);
stringID = SendMessage(hwndTB, TB_ADDSTRING, (WPARAM)NULL, (LPARAM)(LPCTSTR)mInfo.dwTypeData);
}
else {
// if it's ownerdrawn, we get at the string another way (damn, this is ugly...)
mInfo.fMask = MIIM_DATA | MIIM_SUBMENU;
GetMenuItemInfo(hLinksMenu, i, MF_BYPOSITION, &mInfo);
stringID = SendMessage(hwndTB, TB_ADDSTRING, (WPARAM)NULL, (LPARAM)(LPCTSTR)mInfo.dwItemData);
}
TBBUTTON button;
button.iBitmap = gFolderIcon;
button.idCommand = (int)mInfo.hSubMenu+SUBMENU_OFFSET;
button.fsState = TBSTATE_ENABLED;
button.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE | TBSTYLE_DROPDOWN;
//button.bReserved = NULL;
button.iString = stringID;
SendMessage(hwndTB, TB_INSERTBUTTON, (WPARAM)-1, (LPARAM)&button);
}
else{
index = GetMenuItemID(hLinksMenu, i) - nFirstFavoriteCommand;
if (index >= 0 && index < MAX_FAVORITES){
stringID = SendMessage(hwndTB, TB_ADDSTRING, (WPARAM)NULL, (LPARAM)(LPCTSTR)gFavorites[index]);
TBBUTTON button;
button.iBitmap = gIcons[index];
button.idCommand = index + nFirstFavoriteCommand;
button.fsState = TBSTATE_ENABLED;
button.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE;
//button.bReserved = NULL;
button.iString = stringID;
SendMessage(hwndTB, TB_INSERTBUTTON, (WPARAM)-1, (LPARAM)&button);
}
}
}
// Get the width & height of the toolbar.
SIZE size;
SendMessage(hwndTB, TB_GETMAXSIZE, 0, (LPARAM)&size);
REBARBANDINFO rbBand;
rbBand.cbSize = sizeof(REBARBANDINFO); // Required
rbBand.fMask = RBBIM_TEXT |
RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE |
RBBIM_SIZE | RBBIM_IDEALSIZE;
rbBand.fStyle = RBBS_CHILDEDGE | RBBS_FIXEDBMP | RBBS_VARIABLEHEIGHT;
rbBand.lpText = "Links";
rbBand.hwndChild = hwndTB;
rbBand.cxMinChild = 0;
rbBand.cyMinChild = size.cy;
rbBand.cyIntegral = 1;
rbBand.cyMaxChild = rbBand.cyMinChild;
rbBand.cxIdeal = size.cx + 16;
rbBand.cx = rbBand.cxIdeal;
// Add the band that has the toolbar.
SendMessage(rebarWnd, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
}
int BuildFavoritesMenu(char * strPath, HMENU mainMenu)
{
// screen height
int cy = GetSystemMetrics(SM_CYSCREEN);
// menu line height
// int cmenu = GetSystemMetrics(SM_CYMENU);
// if bmp_menu is enabled, the menu items will actually be at least 18 pixels... but this system call won't reflect that
// in any case, SM_CYMENU gets the height of the menu bar, not a menu item
// for now we'll just assume bmp_menu is enabled and they're 18 pixels...
#define cmenu 18
// space to allow above menu for title bar, menu bar (assuming maximized window), and extra frame junk
#define MENUPADDING 50
int maxLength = (int)((cy-MENUPADDING)/cmenu);
const int nStart = gNumFavorites;
int nPos;
int pathLen = strlen(strPath);
char * searchString = new char[gFavoritesPathLen + pathLen + 2];
strcpy(searchString, gFavoritesPath);
strcat(searchString, strPath);
strcat(searchString, "*");
char * urlFile;
char * subPath;
// now scan the directory, first for .URL files and then for subdirectories
// that may also contain .URL files
WIN32_FIND_DATA wfd;
HANDLE h = FindFirstFile(searchString, &wfd);
delete [] searchString;
if(h == INVALID_HANDLE_VALUE) {
return gNumFavorites;
}
int tooMany = false;
int count = GetMenuItemCount(mainMenu);
do {
if (count++ == maxLength) {
HMENU childMenu = CreatePopupMenu();
AppendMenu(mainMenu, MF_STRING|MF_POPUP, (UINT)childMenu, "[more]");
mainMenu = childMenu; // and continue on, populating the new menu
count = 0;
}
if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// ignore the current and parent directory entries
if(lstrcmp(wfd.cFileName, _T(".")) == 0 || lstrcmp(wfd.cFileName, _T("..")) == 0)
continue;
subPath = new char[pathLen + strlen(wfd.cFileName) + 2];
strcpy(subPath, strPath);
strcat(subPath, wfd.cFileName);
strcat(subPath, "/");
HMENU subMenu = CreatePopupMenu();
// call this function recursively.
if(gNumFavorites < MAX_FAVORITES && BuildFavoritesMenu(subPath, subMenu)) {
// only insert a submenu if there are in fact .URL files in the subdirectory
char *pszTemp = fixString(wfd.cFileName, 40);
AppendMenu(mainMenu, MF_BYCOMMAND | MF_POPUP | MF_STRING, (UINT)subMenu, pszTemp);
delete pszTemp;
} else{
DestroyMenu(subMenu);
}
delete [] subPath;
} else if ((wfd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))==0) {
// if it's not a hidden or system file
char *dot = strrchr(wfd.cFileName, '.');
if(dot && stricmp(dot, ".url") == 0) {
// scan through the array and perform an insertion sort
// to make sure the menu ends up in alphabetic order
// for(nPos = nStart; nPos < gNumFavorites; nPos++) {
// if(stricmp(wfd.cFileName, gFavorites[nPos]) < 0)
// break;
// }
nPos = gNumFavorites; // no alphabetization for now - isn't the order in which they were inserted better anyway?
int filenameLen = (dot - wfd.cFileName) + 4;
urlFile = new char[pathLen + filenameLen + 1];
strcpy(urlFile, strPath);
strcat(urlFile, wfd.cFileName);
gFavoritesFiles.InsertAt(nPos, urlFile);
// format for display in the menu
// chop off the .url
*dot = 0;
// condense the string and escape ampersands
char *pszTemp = fixString(wfd.cFileName, 40);
gFavorites.InsertAt(nPos, pszTemp);
AppendMenu(mainMenu, MF_STRING | MF_ENABLED, nFirstFavoriteCommand + nPos, pszTemp);
delete pszTemp;
/*
HACK HACK HACK
We append the filename to gFavoritesPath, get the icon, then chop the file off again
this is a really lame way of doing this...
*/
strcpy(gFavoritesPath + gFavoritesPathLen, urlFile);
// Retrieve icon
SHFILEINFO sfi;
if (SHGetFileInfo (gFavoritesPath, 0, &sfi, sizeof(SHFILEINFO), SHGFI_SMALLICON | SHGFI_SYSICONINDEX) && sfi.iIcon >= 0) {
gIcons.InsertAt(nPos, sfi.iIcon);
if (gInternetShortcutIcon == -1) {
gInternetShortcutIcon = sfi.iIcon;
}
}else{
gIcons.InsertAt(nPos, 0);
}
gFavoritesPath[gFavoritesPathLen] = 0;
delete [] urlFile;
gNumFavorites++;
if (gNumFavorites >= MAX_FAVORITES) {
tooMany = true;
break;
}
}
}
} while(FindNextFile(h, &wfd));
FindClose(h);
if (tooMany) MessageBox(NULL, ERROR_TOO_MANY_FAVORITES, PLUGIN_NAME, 0);
return gNumFavorites - nStart;
}
char *GetURL(int index){
// this is static so that we can return it
static char url[INTERNET_MAX_URL_LENGTH];
char path[MAX_PATH];
strcpy(path, gFavoritesPath);
strcpy(path+gFavoritesPathLen, gFavoritesFiles.GetAt(index));
// a .URL file is formatted just like an .INI file, so we can
// use GetPrivateProfileString() to get the information we want
GetPrivateProfileString(_T("InternetShortcut"), _T("URL"), _T(""), url, INTERNET_MAX_URL_LENGTH, path);
return url;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
// store these in static vars so that the BeginHotTrack call can access them
static NMTOOLBAR tbhdr;
static NMHDR hdr;
if (message == WM_COMMAND){
WORD command = LOWORD(wParam);
if (command == nConfigCommand){
Config(hWnd);
return true;
}
if (command == nAddCommand){
kmeleonDocInfo *dInfo = kPlugin.kFuncs->GetDocInfo(hWnd);
// remove any characters the filesystem won't like
char *c;
while ((c = strpbrk(dInfo->title, "\\/:*?\"<>|")) != NULL) *c = ' ';
CString filename = dInfo->title;
filename += _T(".url");
gFavoritesFiles.Add(filename);
filename = gFavoritesPath + filename;
::WritePrivateProfileString(_T("InternetShortcut"), _T("URL"), dInfo->url, filename);
int nPos = gFavorites.GetSize();
char *pszTemp = fixString(dInfo->title, 40);
AppendMenu(gFavoritesMenu, MF_STRING, nFirstFavoriteCommand+nPos, pszTemp);
gFavorites.Add(pszTemp);
gIcons.Add(0);
delete pszTemp;
DrawMenuBar(hWnd);
return true;
}
if (command == nEditCommand){
ShellExecute(hWnd, "explore", gFavoritesPath, NULL, gFavoritesPath, SW_SHOWNORMAL);
return true;
}
if (command >= nFirstFavoriteCommand && command < (nFirstFavoriteCommand + MAX_FAVORITES)){
kPlugin.kFuncs->NavigateTo(GetURL(command-nFirstFavoriteCommand), OPEN_NORMAL, NULL);
return true;
}
}
else if (message == WM_MENUSELECT) {
WORD command = LOWORD(wParam);
if (command >= nFirstFavoriteCommand && command < (nFirstFavoriteCommand + MAX_FAVORITES)){
kPlugin.kFuncs->SetStatusBarText(GetURL(command-nFirstFavoriteCommand));
return true;
}
}
else if (message == WM_NOTIFY) {
hdr = *((LPNMHDR)lParam);
if (hdr.code == TBN_DROPDOWN) {
tbhdr = *((LPNMTOOLBAR)lParam);
if (IsMenu((HMENU)(tbhdr.iItem-SUBMENU_OFFSET))){
char toolbarName[11];
GetWindowText(tbhdr.hdr.hwndFrom, toolbarName, 10);
if (strcmp(toolbarName, TOOLBAND_LABEL) != 0) {
// oops, this isn't our toolbar
return CallWindowProc(KMeleonWndProc, hWnd, message, wParam, lParam);
}
// post a message to defer exceution of BeginHotTrack
PostMessage(hWnd, WM_DEFERHOTTRACK, NULL, NULL);
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
}
else if (message == WM_DEFERHOTTRACK) {
BeginHotTrack(&tbhdr, kPlugin.hDllInstance, hWnd);
return true;
}
return CallWindowProc(KMeleonWndProc, hWnd, message, wParam, lParam);
}
// Preferences Dialog function
BOOL CALLBACK DlgProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_INITDIALOG:
SendDlgItemMessage(hWnd, IDC_REBARENABLED, BM_SETCHECK, bRebarEnabled, 0);
break;
case WM_COMMAND:
switch(HIWORD(wParam)) {
case BN_CLICKED:
switch (LOWORD(wParam)) {
case IDOK:
bRebarEnabled = SendDlgItemMessage(hWnd, IDC_REBARENABLED, BM_GETCHECK, 0, 0);
kPlugin.kFuncs->SetPreference(PREF_BOOL, _T("kmeleon.plugins.favorites.rebar"), &bRebarEnabled, FALSE);
case IDCANCEL:
SendMessage(hWnd, WM_CLOSE, 0, 0);
}
}
break;
case WM_CLOSE:
EndDialog(hWnd, NULL);
break;
default:
return FALSE;
}
return TRUE;
}
// so it doesn't munge the function name
extern "C" {
KMELEON_PLUGIN kmeleonPlugin *GetKmeleonPlugin() {
return &kPlugin;
}
KMELEON_PLUGIN int DrawBitmap(DRAWITEMSTRUCT *dis) {
int top = (dis->rcItem.bottom - dis->rcItem.top - 16) / 2;
top += dis->rcItem.top;
if (GetMenuState((HMENU)dis->hwndItem, dis->itemID, MF_BYCOMMAND) & MF_POPUP){
if (dis->itemState & ODS_SELECTED){
ImageList_Draw(gSystemImages, gFolderIcon, dis->hDC, dis->rcItem.left, top, ILD_TRANSPARENT | ILD_FOCUS );
}else{
ImageList_Draw(gSystemImages, gFolderIcon, dis->hDC, dis->rcItem.left, top, ILD_TRANSPARENT);
}
return 18;
}
if (dis->itemID >= nFirstFavoriteCommand && dis->itemID < (nFirstFavoriteCommand + MAX_FAVORITES)){
if (dis->itemState & ODS_SELECTED){
ImageList_Draw(gSystemImages, gIcons[dis->itemID - nFirstFavoriteCommand], dis->hDC, dis->rcItem.left, top, ILD_TRANSPARENT | ILD_FOCUS);
}else{
ImageList_Draw(gSystemImages, gIcons[dis->itemID - nFirstFavoriteCommand], dis->hDC, dis->rcItem.left, top, ILD_TRANSPARENT);
}
return 18;
}
return 0;
}
}
/*
From: "Nathan Fredrickson" <8nrf@qlink.queensu.ca>
To: <kmeleon-dev@lists.sourceforge.net>
Subject: [Kmeleon-dev] favorites plugin
Date: Fri, 2 Nov 2001 11:17:40 -0500
Hello,
I like how favorites can be shared between IE and Kmeleon, but I miss the
ability to custom order my favorites in IE. While I would ideally like to
re-order favorites in Kmeleon, a good first step would be just using the IE
ordering when displaying the favorites.
I have done some investigating of how IE stores the menu order of favorites.
The favorites directory and each subdirectory has a corresponding key in the
registry:
HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MenuOrder\\Favorites
HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MenuOrder\\Favorites\\subdir
These keys contain a binary value named "Order". If the key does not exist
for a specified directory, alphabetical order should be used. I have not
found the format of the binary data specified anywhere, so this is what I
have discovered so far:
Order = {
4 0x08 0x00 0x00 0x00
4 0x02 0x00 0x00 0x00
4 (total size of data) - (first 8 bytes) - (last byte)
4 0x01 0x00 0x00 0x00
4 N (number of records)
record 1
record 2
...
record N
1 terminating byte 0x00
}
record = {
4 size of record in bytes
4 position of item in menu
range: [0, recordcount-1] or negative if no order is defined
14 unknown ???
X null-terminated string of full filename: "Yahoo!.url"
X null-terminated string of 8.3 filename: "YAHOO!.URL__"
6 unknown ???
}
The above is enough info to extract the positions and the filenames (I have
written bits of code to do that while experimenting). If I have time, I may
try to add this to the favorites plugin. Not sure what is the best approach
to correlate this data with the URL files read from the directory...
*/
/*
Brian's Notes:
Implementation:
Build a list of menu items in order from the registry keys (ordered favorites)
Build a list of menu items in alphabetical order from the directories (actual favorites)
Loop through ordered favorites.
If the ordered favorite is in actual favorites
Remove it from actual favorites
Add it to merged favorites
If the ordered favorite is not found in actual favorites
Remove it from ordered favorites
Append all remaining actual favorites to merged favorites
We should store the favorites lists as a linked tree list thing (like the bookmarks)
*/