summaryrefslogtreecommitdiff
path: root/plugins/TabSRMM
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-05-23 07:44:30 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-05-23 07:44:30 +0000
commitf3d44bc057201407373012b7f682881bda7b3d98 (patch)
treeddf031a82529c84e13222131cf184ecf176d3954 /plugins/TabSRMM
parentc2d827972a16f1710406d15e58304aecc4e1c9b5 (diff)
some includes restored, mir_full.sln updated, some renaming of folders and projects
git-svn-id: http://svn.miranda-ng.org/main/trunk@140 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/TabSRMM')
-rw-r--r--plugins/TabSRMM/.cproject1892
-rw-r--r--plugins/TabSRMM/.project82
-rw-r--r--plugins/TabSRMM/BuildScripts/VS_2010_Toolset9.bat18
-rw-r--r--plugins/TabSRMM/BuildScripts/Visual1
-rw-r--r--plugins/TabSRMM/DEPRECATED/tabSRMM.sln58
-rw-r--r--plugins/TabSRMM/DEPRECATED/tabsrmm.vcproj1076
-rw-r--r--plugins/TabSRMM/DEPRECATED/tabsrmm_9.sln38
-rw-r--r--plugins/TabSRMM/Makefile129
-rw-r--r--plugins/TabSRMM/chat/Icons/1.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/2.icobin0 -> 918 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/3.icobin0 -> 918 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/4.icobin0 -> 918 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/5.icobin0 -> 918 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/6.icobin0 -> 918 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/1.icobin0 -> 1742 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/2.icobin0 -> 1742 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/3.icobin0 -> 1742 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/4.icobin0 -> 1742 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/5.icobin0 -> 1742 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/6.icobin0 -> 1742 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/Bkgcolor.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/action.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/addmode.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/blank.icobin0 -> 318 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/filter.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/filter2.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/highlight.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/history.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/info.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/join.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/kick.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/message.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/messageout.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/nick.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/nicklist_hide.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/nicklist_show.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/notice.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/overlay.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/part.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/quit.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/removestatus.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/tag1.icobin0 -> 1590 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/tag2.icobin0 -> 4726 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/topic.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/topicbut.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/NOVA/window.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/action.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/addmode.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/bkgcolor.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/blank.icobin0 -> 318 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/filter.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/filter2.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/highlight.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/history.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/info.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/join.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/kick.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/message.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/messageout.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/nick.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/nicklist_hide.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/nicklist_show.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/notice.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/overlay.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/part.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/quit.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/removestatus.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/tag1.icobin0 -> 1590 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/tag2.icobin0 -> 4726 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/topic.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/topicbut.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/Icons/window.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/chat/chat.h369
-rw-r--r--plugins/TabSRMM/chat/chat.rc411
-rw-r--r--plugins/TabSRMM/chat/chat_resource.h161
-rw-r--r--plugins/TabSRMM/chat/chatprototypes.h174
-rw-r--r--plugins/TabSRMM/chat/clist.cpp326
-rw-r--r--plugins/TabSRMM/chat/colorchooser.cpp281
-rw-r--r--plugins/TabSRMM/chat/log.cpp1352
-rw-r--r--plugins/TabSRMM/chat/main.cpp142
-rw-r--r--plugins/TabSRMM/chat/manager.cpp1541
-rw-r--r--plugins/TabSRMM/chat/message.cpp341
-rw-r--r--plugins/TabSRMM/chat/muchighlight.cpp427
-rw-r--r--plugins/TabSRMM/chat/muchighlight.h94
-rw-r--r--plugins/TabSRMM/chat/options.cpp1496
-rw-r--r--plugins/TabSRMM/chat/services.cpp909
-rw-r--r--plugins/TabSRMM/chat/tools.cpp1351
-rw-r--r--plugins/TabSRMM/chat/window.cpp3840
-rw-r--r--plugins/TabSRMM/docs/INSTALL43
-rw-r--r--plugins/TabSRMM/docs/MetaContacts.TXT35
-rw-r--r--plugins/TabSRMM/docs/POPUPS.TXT84
-rw-r--r--plugins/TabSRMM/docs/changelog.OLD2596
-rw-r--r--plugins/TabSRMM/docs/changelog.txt777
-rw-r--r--plugins/TabSRMM/docs/contributors.txt32
-rw-r--r--plugins/TabSRMM/docs/readme.txt124
-rw-r--r--plugins/TabSRMM/icons/ICONSXP/.cvsignore2
-rw-r--r--plugins/TabSRMM/icons/ICONSXP/ICONSXP.dsp74
-rw-r--r--plugins/TabSRMM/icons/ICONSXP/ICONSXP.mak192
-rw-r--r--plugins/TabSRMM/icons/ICONSXP/ICONSXP.rc176
-rw-r--r--plugins/TabSRMM/icons/ICONSXP/ICONSXP.vcproj442
-rw-r--r--plugins/TabSRMM/icons/ICONSXP/iconsxp_8.sln23
-rw-r--r--plugins/TabSRMM/icons/ICONSXP/iconsxp_8.vcproj278
-rw-r--r--plugins/TabSRMM/icons/ICONSXP/iconsxp_8.vpj251
-rw-r--r--plugins/TabSRMM/icons/ICONSXP/iconsxp_9.vcproj402
-rw-r--r--plugins/TabSRMM/icons/ICONSXP/resource.h127
-rw-r--r--plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dep77
-rw-r--r--plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dsp74
-rw-r--r--plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dsw29
-rw-r--r--plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.mak111
-rw-r--r--plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.rc175
-rw-r--r--plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.vcproj197
-rw-r--r--plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA_10.vcxproj108
-rw-r--r--plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA_10.vcxproj.filters23
-rw-r--r--plugins/TabSRMM/include/ImageDataObject.h136
-rw-r--r--plugins/TabSRMM/include/contactcache.h167
-rw-r--r--plugins/TabSRMM/include/controls.h136
-rw-r--r--plugins/TabSRMM/include/functions.h199
-rw-r--r--plugins/TabSRMM/include/generic_msghandlers.h67
-rw-r--r--plugins/TabSRMM/include/globals.h246
-rw-r--r--plugins/TabSRMM/include/infopanel.h220
-rw-r--r--plugins/TabSRMM/include/mim.h319
-rw-r--r--plugins/TabSRMM/include/msgdlgutils.h103
-rw-r--r--plugins/TabSRMM/include/msgs.h1062
-rw-r--r--plugins/TabSRMM/include/nen.h169
-rw-r--r--plugins/TabSRMM/include/resource.h797
-rw-r--r--plugins/TabSRMM/include/sendlater.h155
-rw-r--r--plugins/TabSRMM/include/sendqueue.h123
-rw-r--r--plugins/TabSRMM/include/sidebar.h239
-rw-r--r--plugins/TabSRMM/include/taskbar.h197
-rw-r--r--plugins/TabSRMM/include/templates.h50
-rw-r--r--plugins/TabSRMM/include/themes.h409
-rw-r--r--plugins/TabSRMM/include/translator.h513
-rw-r--r--plugins/TabSRMM/include/typingnotify.h76
-rw-r--r--plugins/TabSRMM/include/utils.h268
-rw-r--r--plugins/TabSRMM/include/version.h15
-rw-r--r--plugins/TabSRMM/msgwindow.rc128
-rw-r--r--plugins/TabSRMM/pack.cmd24
-rw-r--r--plugins/TabSRMM/res/Logo.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/Font2.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/Incom.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/Outg.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/Status change.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/avatar.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/block.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/bold.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/check.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/clock.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/color.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/delete.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/emoticon.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/favlist.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/file.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/font.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/history.icobin0 -> 6830 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/icon_down_arrow.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/info.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/italic.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/message.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/mtn.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/multisend.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/nomtn.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/options.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/pencil.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/plus.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/quote.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/recentlist.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/sbaroptions.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/secureOff.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/secureon.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/slist.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/sounds_off.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/sounds_on.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/strike.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/underline.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/NOVA/userprefs.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/SKIN/close.icobin0 -> 1150 bytes
-rw-r--r--plugins/TabSRMM/res/SKIN/default.tabsrmm341
-rw-r--r--plugins/TabSRMM/res/SKIN/default.tsk342
-rw-r--r--plugins/TabSRMM/res/SKIN/glyph.pngbin0 -> 970 bytes
-rw-r--r--plugins/TabSRMM/res/SKIN/logo.pngbin0 -> 4868 bytes
-rw-r--r--plugins/TabSRMM/res/SKIN/maximize.icobin0 -> 1150 bytes
-rw-r--r--plugins/TabSRMM/res/SKIN/minimize.icobin0 -> 1150 bytes
-rw-r--r--plugins/TabSRMM/res/SKIN/tabskin_aero.pngbin0 -> 368 bytes
-rw-r--r--plugins/TabSRMM/res/SKIN/tabskin_aero_button.pngbin0 -> 353 bytes
-rw-r--r--plugins/TabSRMM/res/SKIN/tabskin_aero_glow.pngbin0 -> 347 bytes
-rw-r--r--plugins/TabSRMM/res/SKIN/unknown.pngbin0 -> 512 bytes
-rw-r--r--plugins/TabSRMM/res/leftarrow.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/messAnim/M1.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/messAnim/M2.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/messAnim/M3.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/messAnim/M4.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/overlay_disabled.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/overlay_enabled.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/Font2.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/Incom.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/Outg.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/Pencil.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/Status change.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/avatar.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/block.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/bold.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/check.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/color.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/delete.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/emoticon.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/favlist.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/file.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/font.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/history.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/info.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/italic.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/message.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/mtn.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/multisend.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/nomtn.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/options.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/plus.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/quote.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/recentlist.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/sbaroptions.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/secureOff.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/secureon.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/slist.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/sounds_off.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/sounds_on.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/strikethrough.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/underline.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/proxal/userprefs.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/res/pulldown.icobin0 -> 1150 bytes
-rw-r--r--plugins/TabSRMM/res/pullup.icobin0 -> 1150 bytes
-rw-r--r--plugins/TabSRMM/res/res_TN/popup.icobin0 -> 894 bytes
-rw-r--r--plugins/TabSRMM/res/res_TN/popup_no.icobin0 -> 894 bytes
-rw-r--r--plugins/TabSRMM/res/rightarrow.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/res/unknown.bmpbin0 -> 12342 bytes
-rw-r--r--plugins/TabSRMM/resource.rc1142
-rw-r--r--plugins/TabSRMM/sdkbuild.bat13
-rw-r--r--plugins/TabSRMM/skin/Back1.pngbin0 -> 3515 bytes
-rw-r--r--plugins/TabSRMM/skin/Back1Inactive.pngbin0 -> 1167 bytes
-rw-r--r--plugins/TabSRMM/skin/button.pngbin0 -> 3049 bytes
-rw-r--r--plugins/TabSRMM/skin/button_hover.pngbin0 -> 3315 bytes
-rw-r--r--plugins/TabSRMM/skin/buttonpressed.pngbin0 -> 3076 bytes
-rw-r--r--plugins/TabSRMM/skin/close.icobin0 -> 1150 bytes
-rw-r--r--plugins/TabSRMM/skin/frames.pngbin0 -> 2954 bytes
-rw-r--r--plugins/TabSRMM/skin/maximize.icobin0 -> 1150 bytes
-rw-r--r--plugins/TabSRMM/skin/minimize.icobin0 -> 2038 bytes
-rw-r--r--plugins/TabSRMM/skin/panel.pngbin0 -> 2947 bytes
-rw-r--r--plugins/TabSRMM/skin/tab.pngbin0 -> 3632 bytes
-rw-r--r--plugins/TabSRMM/skin/tabhover.pngbin0 -> 899 bytes
-rw-r--r--plugins/TabSRMM/skin/tabsrmm.tsk530
-rw-r--r--plugins/TabSRMM/skin/textborder.pngbin0 -> 3124 bytes
-rw-r--r--plugins/TabSRMM/src/ImageDataObject.cpp215
-rw-r--r--plugins/TabSRMM/src/TSButton.cpp738
-rw-r--r--plugins/TabSRMM/src/buttonsbar.cpp1622
-rw-r--r--plugins/TabSRMM/src/commonheaders.h291
-rw-r--r--plugins/TabSRMM/src/contactcache.cpp655
-rw-r--r--plugins/TabSRMM/src/container.cpp2734
-rw-r--r--plugins/TabSRMM/src/containeroptions.cpp586
-rw-r--r--plugins/TabSRMM/src/controls.cpp1157
-rw-r--r--plugins/TabSRMM/src/eventpopups.cpp997
-rw-r--r--plugins/TabSRMM/src/generic_msghandlers.cpp2419
-rw-r--r--plugins/TabSRMM/src/globals.cpp967
-rw-r--r--plugins/TabSRMM/src/hotkeyhandler.cpp688
-rw-r--r--plugins/TabSRMM/src/infopanel.cpp1696
-rw-r--r--plugins/TabSRMM/src/mim.cpp935
-rw-r--r--plugins/TabSRMM/src/msgdialog.cpp3895
-rw-r--r--plugins/TabSRMM/src/msgdlgutils.cpp2555
-rw-r--r--plugins/TabSRMM/src/msglog.cpp1621
-rw-r--r--plugins/TabSRMM/src/msgoptions.cpp1787
-rw-r--r--plugins/TabSRMM/src/msgs.cpp1180
-rw-r--r--plugins/TabSRMM/src/selectcontainer.cpp226
-rw-r--r--plugins/TabSRMM/src/sendlater.cpp989
-rw-r--r--plugins/TabSRMM/src/sendqueue.cpp989
-rw-r--r--plugins/TabSRMM/src/sidebar.cpp1232
-rw-r--r--plugins/TabSRMM/src/srmm.cpp316
-rw-r--r--plugins/TabSRMM/src/tabctrl.cpp1592
-rw-r--r--plugins/TabSRMM/src/taskbar.cpp956
-rw-r--r--plugins/TabSRMM/src/templates.cpp391
-rw-r--r--plugins/TabSRMM/src/themeio.cpp474
-rw-r--r--plugins/TabSRMM/src/themes.cpp2871
-rw-r--r--plugins/TabSRMM/src/translator.cpp665
-rw-r--r--plugins/TabSRMM/src/trayicon.cpp374
-rw-r--r--plugins/TabSRMM/src/typingnotify.cpp573
-rw-r--r--plugins/TabSRMM/src/userprefs.cpp593
-rw-r--r--plugins/TabSRMM/src/utils.cpp1513
-rw-r--r--plugins/TabSRMM/tabmodplus/icons/imgclose.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/tabmodplus/icons/imgopen.icobin0 -> 2550 bytes
-rw-r--r--plugins/TabSRMM/tabmodplus/modplus.cpp276
-rw-r--r--plugins/TabSRMM/tabmodplus/msgoptions_plus.cpp207
-rw-r--r--plugins/TabSRMM/tabsrmm_10.vcxproj627
-rw-r--r--plugins/TabSRMM/tabsrmm_10.vcxproj.filters632
-rw-r--r--plugins/TabSRMM/tabsrmm_private.rc18
291 files changed, 73399 insertions, 0 deletions
diff --git a/plugins/TabSRMM/.cproject b/plugins/TabSRMM/.cproject
new file mode 100644
index 0000000000..49f52d176f
--- /dev/null
+++ b/plugins/TabSRMM/.cproject
@@ -0,0 +1,1892 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?>
+
+<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+ <storageModule moduleId="org.eclipse.cdt.core.settings">
+ <cconfiguration id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962">
+ <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962" moduleId="org.eclipse.cdt.core.settings" name="Release_Unicode">
+ <externalSettings>
+ <externalSetting>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="includePath" name="/TabSRMM"/>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/TabSRMM/Release"/>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/TabSRMM/Release_Unicode"/>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/TabSRMM"/>
+ <entry flags="RESOLVED" kind="libraryFile" name="TabSRMM"/>
+ </externalSetting>
+ <externalSetting languages="cdt.managedbuild.tool.gnu.cpp.compiler.input.100990330"/>
+ </externalSettings>
+ <extensions>
+ <extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/>
+ <extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ </extensions>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <configuration artifactExtension="dll" artifactName="TabSRMM" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.sharedLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib" cleanCommand="rm -rf" description="" errorParsers="org.eclipse.cdt.core.VCErrorParser" id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962" name="Release_Unicode" parent="cdt.managedbuild.config.gnu.mingw.so.release">
+ <folderInfo id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962." name="/" resourcePath="">
+ <toolChain errorParsers="" id="cdt.managedbuild.toolchain.gnu.mingw.so.release.2146797782" name="MinGW GCC" superClass="cdt.managedbuild.toolchain.gnu.mingw.so.release" unusedChildren="cdt.managedbuild.tool.gnu.c.linker.mingw.so.release;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.release">
+ <targetPlatform id="cdt.managedbuild.target.gnu.platform.mingw.so.release.1339003256" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.mingw.so.release"/>
+ <builder arguments="tabsrmm_9.vcproj &quot;Release Unicode&quot; /platform:Win32" buildPath="${workspace_loc:/TabSRMM}" cleanBuildTarget="/clean" command="vcbuild.exe" errorParsers="" id="cdt.managedbuild.target.gnu.builder.base.1412933718" incrementalBuildTarget="" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+ <tool errorParsers="" id="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release.190433702" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release">
+ <option id="gnu.cpp.compiler.mingw.so.release.option.optimization.level.1928516420" name="Optimization Level" superClass="gnu.cpp.compiler.mingw.so.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
+ <option id="gnu.cpp.compiler.mingw.so.release.option.debugging.level.389624385" name="Debug Level" superClass="gnu.cpp.compiler.mingw.so.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+ <option id="gnu.cpp.compiler.option.include.paths.1727447973" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+ <listOptionValue builtIn="false" value="../../../include/"/>
+ <listOptionValue builtIn="false" value="../../../include/mingw"/>
+ </option>
+ <option id="gnu.cpp.compiler.option.warnings.allwarn.822323982" name="All warnings (-Wall)" superClass="gnu.cpp.compiler.option.warnings.allwarn" value="false" valueType="boolean"/>
+ <option id="gnu.cpp.compiler.option.preprocessor.def.907970376" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
+ <listOptionValue builtIn="false" value="__GNUWIN32__=1"/>
+ <listOptionValue builtIn="false" value="UNICODE=1"/>
+ <listOptionValue builtIn="false" value="_UNICODE=1"/>
+ <listOptionValue builtIn="false" value="_MSC_VER=1"/>
+ <listOptionValue builtIn="false" value="_SHLOBJ_H_=1"/>
+ </option>
+ <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.100990330" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+ </tool>
+ <tool command="as" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" errorParsers="" id="cdt.managedbuild.tool.gnu.assembler.mingw.so.release.160225412" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.mingw.so.release">
+ <option id="gnu.both.asm.option.include.paths.1914079530" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths" valueType="includePath">
+ <listOptionValue builtIn="false" value="c:/tabsrmm/trunk/miranda/include/mingw"/>
+ </option>
+ <inputType id="cdt.managedbuild.tool.gnu.assembler.input.2013567033" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+ </tool>
+ <tool errorParsers="" id="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release.1572924727" name="MinGW C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release">
+ <option defaultValue="true" id="gnu.cpp.link.mingw.so.release.option.shared.1469422926" name="Shared (-shared)" superClass="gnu.cpp.link.mingw.so.release.option.shared" valueType="boolean"/>
+ <option id="gnu.cpp.link.option.paths.1351658784" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths"/>
+ <option id="gnu.cpp.link.option.libs.741054938" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs">
+ <listOptionValue builtIn="false" value="kernel32"/>
+ <listOptionValue builtIn="false" value="user32"/>
+ <listOptionValue builtIn="false" value="gdi32"/>
+ <listOptionValue builtIn="false" value="comctl32"/>
+ <listOptionValue builtIn="false" value="comdlg32"/>
+ <listOptionValue builtIn="false" value="ole32"/>
+ <listOptionValue builtIn="false" value="shell32"/>
+ <listOptionValue builtIn="false" value="shlwapi"/>
+ <listOptionValue builtIn="false" value="uuid"/>
+ </option>
+ <option id="gnu.cpp.link.option.strip.935825052" name="Omit all symbol information (-s)" superClass="gnu.cpp.link.option.strip" value="true" valueType="boolean"/>
+ <option id="gnu.cpp.link.option.userobjs.42711706" name="Other objects" superClass="gnu.cpp.link.option.userobjs" valueType="userObjs">
+ <listOptionValue builtIn="false" value="build/tabsrmm_privateW.coff"/>
+ </option>
+ <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.98225411" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+ <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+ <additionalInput kind="additionalinput" paths="$(LIBS)"/>
+ </inputType>
+ <outputType id="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release.output.1066666505" outputPrefix="" superClass="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release.output"/>
+ </tool>
+ <tool id="cdt.managedbuild.tool.gnu.archiver.mingw.base.2073530555" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.mingw.base"/>
+ </toolChain>
+ </folderInfo>
+ <sourceEntries>
+ <entry excluding="chat/log.c|chat/clist.c|chat/services.c|chat/manager.c|chat/colorchooser.c|chat/chat.h|Include|chat/options.c|chat/chatprototypes.h|chat/tools.c|chat/main.c|chat/chat_resource.h|chat/window.c|chat/message.c|chat/chat.rc" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+ </sourceEntries>
+ </configuration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+ <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+ <storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+ <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets">
+ <buildTargets>
+ <target name="Release_Unicode" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
+ <buildCommand>make</buildCommand>
+ <buildTarget>Release_Unicode</buildTarget>
+ <stopOnError>true</stopOnError>
+ <useDefaultCommand>true</useDefaultCommand>
+ <runAllBuilders>true</runAllBuilders>
+ </target>
+ <target name="Release Unicode|x64" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
+ <buildCommand>sdkbuild.bat</buildCommand>
+ <buildArguments/>
+ <buildTarget>Release Unicode|x64</buildTarget>
+ <stopOnError>true</stopOnError>
+ <useDefaultCommand>false</useDefaultCommand>
+ <runAllBuilders>true</runAllBuilders>
+ </target>
+ </buildTargets>
+ </storageModule>
+ </cconfiguration>
+ <cconfiguration id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273">
+ <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273" moduleId="org.eclipse.cdt.core.settings" name="Release Unicode|x64">
+ <externalSettings>
+ <externalSetting>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="includePath" name="/TabSRMM"/>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/TabSRMM/Release"/>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/TabSRMM/Release_Unicode"/>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/TabSRMM"/>
+ <entry flags="RESOLVED" kind="libraryFile" name="TabSRMM"/>
+ </externalSetting>
+ <externalSetting languages="cdt.managedbuild.tool.gnu.cpp.compiler.input.100990330"/>
+ </externalSettings>
+ <extensions>
+ <extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/>
+ <extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ </extensions>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <configuration artifactExtension="dll" artifactName="TabSRMM" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.sharedLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib" cleanCommand="rm -rf" description="" errorParsers="org.eclipse.cdt.core.VCErrorParser" id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273" name="Release Unicode|x64" parent="cdt.managedbuild.config.gnu.mingw.so.release">
+ <folderInfo id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273." name="/" resourcePath="">
+ <toolChain errorParsers="" id="cdt.managedbuild.toolchain.gnu.mingw.so.release.30218171" name="MinGW GCC" superClass="cdt.managedbuild.toolchain.gnu.mingw.so.release" unusedChildren="cdt.managedbuild.tool.gnu.c.linker.mingw.so.release;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.release">
+ <targetPlatform id="cdt.managedbuild.target.gnu.platform.mingw.so.release.1379790891" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.mingw.so.release"/>
+ <builder arguments="tabsrmm_9.vcproj &quot;Release Unicode&quot; /platform:x64" buildPath="${workspace_loc:/TabSRMM}" cleanBuildTarget="/clean" command="vcbuild.exe" enabledIncrementalBuild="true" errorParsers="" id="cdt.managedbuild.target.gnu.builder.base.165647079" incrementalBuildTarget="" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+ <tool errorParsers="" id="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release.655019311" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release">
+ <option id="gnu.cpp.compiler.mingw.so.release.option.optimization.level.2075890504" name="Optimization Level" superClass="gnu.cpp.compiler.mingw.so.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
+ <option id="gnu.cpp.compiler.mingw.so.release.option.debugging.level.2018947952" name="Debug Level" superClass="gnu.cpp.compiler.mingw.so.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+ <option id="gnu.cpp.compiler.option.include.paths.1718619247" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+ <listOptionValue builtIn="false" value="../../../include"/>
+ <listOptionValue builtIn="false" value="../../../include/mingw"/>
+ </option>
+ <option id="gnu.cpp.compiler.option.warnings.allwarn.1682059092" name="All warnings (-Wall)" superClass="gnu.cpp.compiler.option.warnings.allwarn" value="false" valueType="boolean"/>
+ <option id="gnu.cpp.compiler.option.preprocessor.def.789922860" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
+ <listOptionValue builtIn="false" value="__GNUWIN32__=1"/>
+ <listOptionValue builtIn="false" value="UNICODE=1"/>
+ <listOptionValue builtIn="false" value="_UNICODE=1"/>
+ <listOptionValue builtIn="false" value="_MSC_VER=1"/>
+ <listOptionValue builtIn="false" value="_SHLOBJ_H_=1"/>
+ </option>
+ <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1998615564" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+ </tool>
+ <tool command="as" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" errorParsers="" id="cdt.managedbuild.tool.gnu.assembler.mingw.so.release.462232327" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.mingw.so.release">
+ <option id="gnu.both.asm.option.include.paths.2044658897" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths" valueType="includePath">
+ <listOptionValue builtIn="false" value="c:/tabsrmm/trunk/miranda/include/mingw"/>
+ </option>
+ <inputType id="cdt.managedbuild.tool.gnu.assembler.input.609523499" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+ </tool>
+ <tool errorParsers="" id="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release.613146519" name="MinGW C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release">
+ <option defaultValue="true" id="gnu.cpp.link.mingw.so.release.option.shared.1272062237" name="Shared (-shared)" superClass="gnu.cpp.link.mingw.so.release.option.shared" valueType="boolean"/>
+ <option id="gnu.cpp.link.option.paths.1286809137" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths"/>
+ <option id="gnu.cpp.link.option.libs.182797290" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs">
+ <listOptionValue builtIn="false" value="kernel32"/>
+ <listOptionValue builtIn="false" value="user32"/>
+ <listOptionValue builtIn="false" value="gdi32"/>
+ <listOptionValue builtIn="false" value="comctl32"/>
+ <listOptionValue builtIn="false" value="comdlg32"/>
+ <listOptionValue builtIn="false" value="ole32"/>
+ <listOptionValue builtIn="false" value="shell32"/>
+ <listOptionValue builtIn="false" value="shlwapi"/>
+ <listOptionValue builtIn="false" value="uuid"/>
+ </option>
+ <option id="gnu.cpp.link.option.strip.578035025" name="Omit all symbol information (-s)" superClass="gnu.cpp.link.option.strip" value="true" valueType="boolean"/>
+ <option id="gnu.cpp.link.option.userobjs.678929158" name="Other objects" superClass="gnu.cpp.link.option.userobjs" valueType="userObjs">
+ <listOptionValue builtIn="false" value="build/tabsrmm_privateW.coff"/>
+ </option>
+ <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1831227134" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+ <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+ <additionalInput kind="additionalinput" paths="$(LIBS)"/>
+ </inputType>
+ <outputType id="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release.output.1108328783" outputPrefix="" superClass="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release.output"/>
+ </tool>
+ <tool id="cdt.managedbuild.tool.gnu.archiver.mingw.base.2010374596" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.mingw.base"/>
+ </toolChain>
+ </folderInfo>
+ <sourceEntries>
+ <entry excluding="chat/log.c|chat/clist.c|chat/services.c|chat/manager.c|chat/colorchooser.c|chat/chat.h|Include|chat/options.c|chat/chatprototypes.h|chat/tools.c|chat/main.c|chat/chat_resource.h|chat/window.c|chat/message.c|chat/chat.rc" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+ </sourceEntries>
+ </configuration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+ <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+ <storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+ <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets">
+ <buildTargets>
+ <target name="Release_Unicode" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
+ <buildCommand>make</buildCommand>
+ <buildTarget>Release_Unicode</buildTarget>
+ <stopOnError>true</stopOnError>
+ <useDefaultCommand>true</useDefaultCommand>
+ <runAllBuilders>true</runAllBuilders>
+ </target>
+ <target name="Release Unicode|x64" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
+ <buildCommand>sdkbuild.bat</buildCommand>
+ <buildArguments/>
+ <buildTarget>Release Unicode|x64</buildTarget>
+ <stopOnError>true</stopOnError>
+ <useDefaultCommand>false</useDefaultCommand>
+ <runAllBuilders>true</runAllBuilders>
+ </target>
+ </buildTargets>
+ </storageModule>
+ </cconfiguration>
+ <cconfiguration id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273.677392902">
+ <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273.677392902" moduleId="org.eclipse.cdt.core.settings" name="Debug Unicode|x64">
+ <externalSettings>
+ <externalSetting>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="includePath" name="/TabSRMM"/>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/TabSRMM/Release"/>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/TabSRMM/Release_Unicode"/>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/TabSRMM"/>
+ <entry flags="RESOLVED" kind="libraryFile" name="TabSRMM"/>
+ </externalSetting>
+ <externalSetting languages="cdt.managedbuild.tool.gnu.cpp.compiler.input.100990330"/>
+ </externalSettings>
+ <extensions>
+ <extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/>
+ <extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ </extensions>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <configuration artifactExtension="dll" artifactName="TabSRMM" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.sharedLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib" cleanCommand="rm -rf" description="" errorParsers="org.eclipse.cdt.core.VCErrorParser" id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273.677392902" name="Debug Unicode|x64" parent="cdt.managedbuild.config.gnu.mingw.so.release">
+ <folderInfo id="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273.677392902." name="/" resourcePath="">
+ <toolChain errorParsers="" id="cdt.managedbuild.toolchain.gnu.mingw.so.release.2019363488" name="MinGW GCC" superClass="cdt.managedbuild.toolchain.gnu.mingw.so.release" unusedChildren="cdt.managedbuild.tool.gnu.c.linker.mingw.so.release;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.release">
+ <targetPlatform id="cdt.managedbuild.target.gnu.platform.mingw.so.release.2088585956" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.mingw.so.release"/>
+ <builder arguments="tabsrmm_9.vcproj &quot;Debug Unicode&quot; /platform:x64" buildPath="${workspace_loc:/TabSRMM}" cleanBuildTarget="/clean" command="vcbuild.exe" enabledIncrementalBuild="true" errorParsers="" id="cdt.managedbuild.target.gnu.builder.base.1984959863" incrementalBuildTarget="" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+ <tool errorParsers="" id="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release.1587198361" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release">
+ <option id="gnu.cpp.compiler.mingw.so.release.option.optimization.level.524596121" name="Optimization Level" superClass="gnu.cpp.compiler.mingw.so.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
+ <option id="gnu.cpp.compiler.mingw.so.release.option.debugging.level.1956067300" name="Debug Level" superClass="gnu.cpp.compiler.mingw.so.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+ <option id="gnu.cpp.compiler.option.include.paths.266932678" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+ <listOptionValue builtIn="false" value="../../../include"/>
+ <listOptionValue builtIn="false" value="../../../include/mingw"/>
+ <listOptionValue builtIn="false" value="&quot;D:\sdk\Include&quot;"/>
+ </option>
+ <option id="gnu.cpp.compiler.option.warnings.allwarn.1056594207" name="All warnings (-Wall)" superClass="gnu.cpp.compiler.option.warnings.allwarn" value="false" valueType="boolean"/>
+ <option id="gnu.cpp.compiler.option.preprocessor.def.1091165392" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
+ <listOptionValue builtIn="false" value="__GNUWIN32__=1"/>
+ <listOptionValue builtIn="false" value="UNICODE=1"/>
+ <listOptionValue builtIn="false" value="_UNICODE=1"/>
+ <listOptionValue builtIn="false" value="_MSC_VER=1"/>
+ <listOptionValue builtIn="false" value="_SHLOBJ_H_=1"/>
+ </option>
+ <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.871230492" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+ </tool>
+ <tool command="as" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" errorParsers="" id="cdt.managedbuild.tool.gnu.assembler.mingw.so.release.1287059339" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.mingw.so.release">
+ <option id="gnu.both.asm.option.include.paths.1539981826" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths" valueType="includePath">
+ <listOptionValue builtIn="false" value="c:/tabsrmm/trunk/miranda/include/mingw"/>
+ </option>
+ <inputType id="cdt.managedbuild.tool.gnu.assembler.input.71824240" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+ </tool>
+ <tool errorParsers="" id="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release.157654788" name="MinGW C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release">
+ <option defaultValue="true" id="gnu.cpp.link.mingw.so.release.option.shared.441975628" name="Shared (-shared)" superClass="gnu.cpp.link.mingw.so.release.option.shared" valueType="boolean"/>
+ <option id="gnu.cpp.link.option.paths.961182051" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths"/>
+ <option id="gnu.cpp.link.option.libs.860557767" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs">
+ <listOptionValue builtIn="false" value="kernel32"/>
+ <listOptionValue builtIn="false" value="user32"/>
+ <listOptionValue builtIn="false" value="gdi32"/>
+ <listOptionValue builtIn="false" value="comctl32"/>
+ <listOptionValue builtIn="false" value="comdlg32"/>
+ <listOptionValue builtIn="false" value="ole32"/>
+ <listOptionValue builtIn="false" value="shell32"/>
+ <listOptionValue builtIn="false" value="shlwapi"/>
+ <listOptionValue builtIn="false" value="uuid"/>
+ </option>
+ <option id="gnu.cpp.link.option.strip.791215908" name="Omit all symbol information (-s)" superClass="gnu.cpp.link.option.strip" value="true" valueType="boolean"/>
+ <option id="gnu.cpp.link.option.userobjs.593688707" name="Other objects" superClass="gnu.cpp.link.option.userobjs" valueType="userObjs">
+ <listOptionValue builtIn="false" value="build/tabsrmm_privateW.coff"/>
+ </option>
+ <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.2033680982" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+ <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+ <additionalInput kind="additionalinput" paths="$(LIBS)"/>
+ </inputType>
+ <outputType id="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release.output.1231908658" outputPrefix="" superClass="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release.output"/>
+ </tool>
+ <tool id="cdt.managedbuild.tool.gnu.archiver.mingw.base.483531863" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.mingw.base"/>
+ </toolChain>
+ </folderInfo>
+ <sourceEntries>
+ <entry excluding="chat/log.c|chat/clist.c|chat/services.c|chat/manager.c|chat/colorchooser.c|chat/chat.h|Include|chat/options.c|chat/chatprototypes.h|chat/tools.c|chat/main.c|chat/chat_resource.h|chat/window.c|chat/message.c|chat/chat.rc" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+ </sourceEntries>
+ </configuration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+ <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+ <storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+ <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets">
+ <buildTargets>
+ <target name="Release_Unicode" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
+ <buildCommand>make</buildCommand>
+ <buildTarget>Release_Unicode</buildTarget>
+ <stopOnError>true</stopOnError>
+ <useDefaultCommand>true</useDefaultCommand>
+ <runAllBuilders>true</runAllBuilders>
+ </target>
+ <target name="Release Unicode|x64" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
+ <buildCommand>sdkbuild.bat</buildCommand>
+ <buildArguments/>
+ <buildTarget>Release Unicode|x64</buildTarget>
+ <stopOnError>true</stopOnError>
+ <useDefaultCommand>false</useDefaultCommand>
+ <runAllBuilders>true</runAllBuilders>
+ </target>
+ </buildTargets>
+ </storageModule>
+ </cconfiguration>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <project id="TabSRMM.cdt.managedbuild.target.gnu.mingw.so.1178041117" name="Shared Library" projectType="cdt.managedbuild.target.gnu.mingw.so"/>
+ </storageModule>
+ <storageModule moduleId="refreshScope"/>
+ <storageModule moduleId="scannerConfiguration">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.debug.583177157;cdt.managedbuild.config.gnu.mingw.so.debug.583177157.;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.debug.1083186743;cdt.managedbuild.tool.gnu.c.compiler.input.2000906432">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.release.603393219;cdt.managedbuild.config.gnu.mingw.so.release.603393219.;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.release.1002623625;cdt.managedbuild.tool.gnu.c.compiler.input.49167673">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.release.1628480916;cdt.managedbuild.config.gnu.mingw.so.release.1628480916.;cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release.1049207571;cdt.managedbuild.tool.gnu.cpp.compiler.input.175152046">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.release.111606149;cdt.managedbuild.config.gnu.mingw.so.release.111606149.;cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release.916307467;cdt.managedbuild.tool.gnu.cpp.compiler.input.865588859">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.release.111606149;cdt.managedbuild.config.gnu.mingw.so.release.111606149.;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.release.1347126386;cdt.managedbuild.tool.gnu.c.compiler.input.1541055042">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.release.1628480916;cdt.managedbuild.config.gnu.mingw.so.release.1628480916.;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.release.1746838512;cdt.managedbuild.tool.gnu.c.compiler.input.2139649235">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.debug.537588189;cdt.managedbuild.config.gnu.mingw.so.debug.537588189.;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.debug.1718695978;cdt.managedbuild.tool.gnu.c.compiler.input.1378197595">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273.677392902;cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273.677392902.;cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release.1587198361;cdt.managedbuild.tool.gnu.cpp.compiler.input.871230492">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962;cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.release.913712733;cdt.managedbuild.tool.gnu.c.compiler.input.759676664">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.debug.1080660173;cdt.managedbuild.config.gnu.mingw.so.debug.1080660173.;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.debug.43875570;cdt.managedbuild.tool.gnu.c.compiler.input.1484640134">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.debug.537588189">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.debug.583177157;cdt.managedbuild.config.gnu.mingw.so.debug.583177157.2109372240;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.debug.932494701;cdt.managedbuild.tool.gnu.c.compiler.input.329145553">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962;cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.;cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release.190433702;cdt.managedbuild.tool.gnu.cpp.compiler.input.100990330">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.debug.583177157;cdt.managedbuild.config.gnu.mingw.so.debug.583177157.2109372240;cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.debug.1212064346;cdt.managedbuild.tool.gnu.cpp.compiler.input.652819075">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.debug.1080660173;cdt.managedbuild.config.gnu.mingw.so.debug.1080660173.;cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.debug.1957063610;cdt.managedbuild.tool.gnu.cpp.compiler.input.1287619684">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.debug.583177157;cdt.managedbuild.config.gnu.mingw.so.debug.583177157.;cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.debug.102908662;cdt.managedbuild.tool.gnu.cpp.compiler.input.994667369">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273;cdt.managedbuild.config.gnu.mingw.so.release.1628480916.583737962.153418273.;cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release.655019311;cdt.managedbuild.tool.gnu.cpp.compiler.input.1998615564">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.debug.537588189;cdt.managedbuild.config.gnu.mingw.so.debug.537588189.;cdt.managedbuild.tool.gnu.c.compiler.mingw.base.584221430;cdt.managedbuild.tool.gnu.c.compiler.input.968376063">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ </scannerConfigBuildInfo>
+ </storageModule>
+</cproject>
diff --git a/plugins/TabSRMM/.project b/plugins/TabSRMM/.project
new file mode 100644
index 0000000000..9bbc96288f
--- /dev/null
+++ b/plugins/TabSRMM/.project
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>TabSRMM_Trunk</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+ <triggers>clean,full,incremental,</triggers>
+ <arguments>
+ <dictionary>
+ <key>?name?</key>
+ <value></value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.append_environment</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.autoBuildTarget</key>
+ <value>all</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.buildArguments</key>
+ <value>tabsrmm_9.vcproj &quot;Release Unicode&quot; /platform:Win32</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.buildCommand</key>
+ <value>vcbuild.exe</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.buildLocation</key>
+ <value>${workspace_loc:/TabSRMM}</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
+ <value>/clean</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.contents</key>
+ <value>org.eclipse.cdt.make.core.activeConfigSettings</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+ <value>false</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableFullBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.fullBuildTarget</key>
+ <value></value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.stopOnError</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+ <value>false</value>
+ </dictionary>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+ <nature>org.eclipse.cdt.core.cnature</nature>
+ <nature>org.eclipse.cdt.core.ccnature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/TabSRMM/BuildScripts/VS_2010_Toolset9.bat b/plugins/TabSRMM/BuildScripts/VS_2010_Toolset9.bat
new file mode 100644
index 0000000000..cad0559f2f
--- /dev/null
+++ b/plugins/TabSRMM/BuildScripts/VS_2010_Toolset9.bat
@@ -0,0 +1,18 @@
+@echo off
+
+REM ignore this if you do not have Visual Studio 2010 installed.
+
+echo * ------------------------------------------------- *
+echo This builds x86/x64 targets using the Visual C++ 9
+echo toolset. The builds will use the msvcr90 runtime,
+echo same as builds created with Visual Studio 2008 SP1.
+echo
+echo This must be used from a Visual Studio 2010 command
+echo line prompt to be found in:
+echo
+echo Start->Visual Studio 2010->Visual Studio Tools
+echo * ------------------------------------------------- *
+
+cd ..
+msbuild tabsrmm_10.sln /t:rebuild /p:"Configuration=Release Unicode";platform=Win32;PlatformToolset=v90
+msbuild tabsrmm_10.sln /t:rebuild /p:"Configuration=Release Unicode";platform=x64;PlatformToolset=v90
diff --git a/plugins/TabSRMM/BuildScripts/Visual b/plugins/TabSRMM/BuildScripts/Visual
new file mode 100644
index 0000000000..41bc5aeb8d
--- /dev/null
+++ b/plugins/TabSRMM/BuildScripts/Visual
@@ -0,0 +1 @@
+Start- Studio 2010- Studio Tools
diff --git a/plugins/TabSRMM/DEPRECATED/tabSRMM.sln b/plugins/TabSRMM/DEPRECATED/tabSRMM.sln
new file mode 100644
index 0000000000..3404e993ff
--- /dev/null
+++ b/plugins/TabSRMM/DEPRECATED/tabSRMM.sln
@@ -0,0 +1,58 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tabSRMM", "tabsrmm.vcproj", "{8954217B-1306-4250-854D-6BF6BE5E57C9}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ICONS", "icons\default\default.vcproj", "{8CA07E0A-0632-4F95-B411-CDFAF048821B}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ICONSXP", "icons\ICONSXP\ICONSXP.vcproj", "{987C5A57-A46B-4779-BB85-077E21F7BF7F}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Debug Unicode = Debug Unicode
+ Release = Release
+ Release Unicode = Release Unicode
+ Release Unicode 98 = Release Unicode 98
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {8954217B-1306-4250-854D-6BF6BE5E57C9}.Debug.ActiveCfg = Debug|Win32
+ {8954217B-1306-4250-854D-6BF6BE5E57C9}.Debug.Build.0 = Debug|Win32
+ {8954217B-1306-4250-854D-6BF6BE5E57C9}.Debug Unicode.ActiveCfg = Debug Unicode|Win32
+ {8954217B-1306-4250-854D-6BF6BE5E57C9}.Debug Unicode.Build.0 = Debug Unicode|Win32
+ {8954217B-1306-4250-854D-6BF6BE5E57C9}.Release.ActiveCfg = Release|Win32
+ {8954217B-1306-4250-854D-6BF6BE5E57C9}.Release.Build.0 = Release|Win32
+ {8954217B-1306-4250-854D-6BF6BE5E57C9}.Release Unicode.ActiveCfg = Release Unicode|Win32
+ {8954217B-1306-4250-854D-6BF6BE5E57C9}.Release Unicode.Build.0 = Release Unicode|Win32
+ {8954217B-1306-4250-854D-6BF6BE5E57C9}.Release Unicode 98.ActiveCfg = Release Unicode 98|Win32
+ {8954217B-1306-4250-854D-6BF6BE5E57C9}.Release Unicode 98.Build.0 = Release Unicode 98|Win32
+ {8CA07E0A-0632-4F95-B411-CDFAF048821B}.Debug.ActiveCfg = Debug|Win32
+ {8CA07E0A-0632-4F95-B411-CDFAF048821B}.Debug.Build.0 = Debug|Win32
+ {8CA07E0A-0632-4F95-B411-CDFAF048821B}.Debug Unicode.ActiveCfg = Debug|Win32
+ {8CA07E0A-0632-4F95-B411-CDFAF048821B}.Debug Unicode.Build.0 = Debug|Win32
+ {8CA07E0A-0632-4F95-B411-CDFAF048821B}.Release.ActiveCfg = Release|Win32
+ {8CA07E0A-0632-4F95-B411-CDFAF048821B}.Release.Build.0 = Release|Win32
+ {8CA07E0A-0632-4F95-B411-CDFAF048821B}.Release Unicode.ActiveCfg = Release|Win32
+ {8CA07E0A-0632-4F95-B411-CDFAF048821B}.Release Unicode.Build.0 = Release|Win32
+ {8CA07E0A-0632-4F95-B411-CDFAF048821B}.Release Unicode 98.ActiveCfg = Release Unicode 98|Win32
+ {8CA07E0A-0632-4F95-B411-CDFAF048821B}.Release Unicode 98.Build.0 = Release Unicode 98|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Debug.ActiveCfg = Debug|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Debug.Build.0 = Debug|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Debug Unicode.ActiveCfg = Debug|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Debug Unicode.Build.0 = Debug|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Release.ActiveCfg = Release|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Release.Build.0 = Release|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Release Unicode.ActiveCfg = Release|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Release Unicode.Build.0 = Release|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Release Unicode 98.ActiveCfg = Release Unicode 98|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Release Unicode 98.Build.0 = Release Unicode 98|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/plugins/TabSRMM/DEPRECATED/tabsrmm.vcproj b/plugins/TabSRMM/DEPRECATED/tabsrmm.vcproj
new file mode 100644
index 0000000000..fe38e13978
--- /dev/null
+++ b/plugins/TabSRMM/DEPRECATED/tabsrmm.vcproj
@@ -0,0 +1,1076 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="tabSRMM"
+ ProjectGUID="{99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}"
+ RootNamespace="srmm"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)/Plugins"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="comctl32.lib shlwapi.lib"
+ LinkIncremental="2"
+ SuppressStartupBanner="TRUE"
+ DelayLoadDLLs=""
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\Debug/srmm.pdb"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/srmm.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="2057"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release Unicode|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)/Plugins"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="1"
+ WholeProgramOptimization="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ GlobalOptimizations="TRUE"
+ FavorSizeOrSpeed="2"
+ OmitFramePointers="FALSE"
+ OptimizeForProcessor="0"
+ AdditionalIncludeDirectories="..\..\include"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerOutput="4"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="TRUE"
+ AdditionalDependencies="vc7to6.lib eh7.lib comctl32.lib shlwapi.lib"
+ AdditionalLibraryDirectories="../../lib"
+ IgnoreAllDefaultLibraries="TRUE"
+ DelayLoadDLLs=""
+ GenerateDebugInformation="TRUE"
+ GenerateMapFile="TRUE"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ BaseAddress="0x6a540000"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release_Unicode/srmm.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG;UNICODE"
+ Culture="2057"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)/Plugins"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2"
+ WholeProgramOptimization="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="TRUE"
+ AdditionalDependencies="vc7to6.lib eh7.lib comctl32.lib shlwapi.lib oldnames.lib"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ AdditionalLibraryDirectories="../../lib"
+ IgnoreAllDefaultLibraries="TRUE"
+ DelayLoadDLLs=""
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ BaseAddress="0x6a540000"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/srmm.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="2057"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug Unicode|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)/Plugins"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ UseOfATL="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="1">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="TRUE"
+ AdditionalDependencies="comctl32.lib shlwapi.lib"
+ LinkIncremental="2"
+ SuppressStartupBanner="TRUE"
+ DelayLoadDLLs=""
+ GenerateDebugInformation="TRUE"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug_Unicode/srmm.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="2057"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath=".\buttonsbar.c">
+ </File>
+ <File
+ RelativePath=".\container.c">
+ </File>
+ <File
+ RelativePath=".\containeroptions.c">
+ </File>
+ <File
+ RelativePath="eventpopups.c">
+ </File>
+ <File
+ RelativePath=".\formatting.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ExceptionHandling="TRUE"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ ExceptionHandling="TRUE"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\generic_msghandlers.c">
+ </File>
+ <File
+ RelativePath=".\hotkeyhandler.c">
+ </File>
+ <File
+ RelativePath="ImageDataObject.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\tabmodplus\modplus.c">
+ </File>
+ <File
+ RelativePath="msgdialog.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\msgdlgutils.c">
+ </File>
+ <File
+ RelativePath="msglog.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="msgoptions.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\tabmodplus\msgoptions_plus.c">
+ </File>
+ <File
+ RelativePath="msgs.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\selectcontainer.c">
+ </File>
+ <File
+ RelativePath="sendqueue.c">
+ </File>
+ <File
+ RelativePath="srmm.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="1"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\tabctrl.c">
+ </File>
+ <File
+ RelativePath="templates.c">
+ </File>
+ <File
+ RelativePath=".\themes.c">
+ </File>
+ <File
+ RelativePath="trayicon.c">
+ </File>
+ <File
+ RelativePath="TSButton.c">
+ </File>
+ <File
+ RelativePath=".\typingnotify.c">
+ </File>
+ <File
+ RelativePath="userprefs.c">
+ </File>
+ <Filter
+ Name="Chat"
+ Filter="">
+ <File
+ RelativePath=".\chat\chat.h">
+ </File>
+ <File
+ RelativePath=".\chat\chat.rc">
+ </File>
+ <File
+ RelativePath=".\chat\chat_resource.h">
+ </File>
+ <File
+ RelativePath=".\chat\chatprototypes.h">
+ </File>
+ <File
+ RelativePath=".\chat\clist.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\chat\colorchooser.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\chat\log.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\chat\main.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\chat\manager.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\chat\message.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\chat\options.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\chat\services.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\chat\tools.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\chat\window.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../commonheaders.h"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="commonheaders.h">
+ </File>
+ <File
+ RelativePath="functions.h">
+ </File>
+ <File
+ RelativePath=".\generic_msghandlers.h">
+ </File>
+ <File
+ RelativePath="ImageDataObject.h">
+ </File>
+ <File
+ RelativePath="msgdlgutils.h">
+ </File>
+ <File
+ RelativePath="msgs.h">
+ </File>
+ <File
+ RelativePath="nen.h">
+ </File>
+ <File
+ RelativePath="resource.h">
+ </File>
+ <File
+ RelativePath=".\resrc1.h">
+ </File>
+ <File
+ RelativePath="sendqueue.h">
+ </File>
+ <File
+ RelativePath="templates.h">
+ </File>
+ <File
+ RelativePath=".\URLCtrl.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ <File
+ RelativePath=".\res\angeli-icons\Add.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\AddXP.ico">
+ </File>
+ <File
+ RelativePath=".\res\arrow-down.ico">
+ </File>
+ <File
+ RelativePath=".\res\blocked.ico">
+ </File>
+ <File
+ RelativePath=".\res\check.ico">
+ </File>
+ <File
+ RelativePath=".\res\checked.ico">
+ </File>
+ <File
+ RelativePath=".\res\Clock8.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\Close.ico">
+ </File>
+ <File
+ RelativePath=".\res\delete.ico">
+ </File>
+ <File
+ RelativePath="res\Details32.ico">
+ </File>
+ <File
+ RelativePath="res\Details8.ico">
+ </File>
+ <File
+ RelativePath=".\res\error.ico">
+ </File>
+ <File
+ RelativePath=".\res\expand.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\HistoryXP.ico">
+ </File>
+ <File
+ RelativePath=".\res\in.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\Incom.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\Info.ico">
+ </File>
+ <File
+ RelativePath=".\res\leftarrow.ico">
+ </File>
+ <File
+ RelativePath=".\msgwindow.rc">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\Multi.ico">
+ </File>
+ <File
+ RelativePath="res\Multisend32.ico">
+ </File>
+ <File
+ RelativePath="res\Multisend8.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\MultiXP.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\Opt.ico">
+ </File>
+ <File
+ RelativePath=".\res\options.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\OptXP.ico">
+ </File>
+ <File
+ RelativePath=".\res\out.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\Outg.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\Pencil.ico">
+ </File>
+ <File
+ RelativePath=".\res\Photo32.ico">
+ </File>
+ <File
+ RelativePath=".\res\Photo8.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\Pic.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\PicXP.ico">
+ </File>
+ <File
+ RelativePath=".\res\pulldown.ico">
+ </File>
+ <File
+ RelativePath=".\res\pulldown1.ico">
+ </File>
+ <File
+ RelativePath=".\res\pullup.ico">
+ </File>
+ <File
+ RelativePath=".\res\quote.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\Quote02.ico">
+ </File>
+ <File
+ RelativePath=".\resource.rc">
+ </File>
+ <File
+ RelativePath=".\res\rightarrow.ico">
+ </File>
+ <File
+ RelativePath=".\res\save.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\Save.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\SaveXP.ico">
+ </File>
+ <File
+ RelativePath=".\res\angeli-icons\Send.ico">
+ </File>
+ <File
+ RelativePath=".\res\smbutton.ico">
+ </File>
+ <File
+ RelativePath=".\res\smiley_xp.ico">
+ </File>
+ <File
+ RelativePath=".\res\status.ico">
+ </File>
+ <File
+ RelativePath="res\Typing32.ico">
+ </File>
+ <File
+ RelativePath="res\Typing8.ico">
+ </File>
+ <File
+ RelativePath=".\res\unchecked.ico">
+ </File>
+ <File
+ RelativePath=".\res\visible.ico">
+ </File>
+ <File
+ RelativePath=".\res\xstatus.bmp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Misc Files"
+ Filter="">
+ <File
+ RelativePath=".\docs\changelog.txt">
+ </File>
+ <File
+ RelativePath=".\hotkeyhandler.c">
+ </File>
+ <File
+ RelativePath="docs\INSTALL">
+ </File>
+ <File
+ RelativePath="langpacks\langpack_tabsrmm_german.txt">
+ </File>
+ <File
+ RelativePath=".\Makefile.ansi">
+ </File>
+ <File
+ RelativePath=".\docs\Popups.txt">
+ </File>
+ <File
+ RelativePath=".\docs\Readme.icons">
+ </File>
+ <File
+ RelativePath=".\docs\readme.txt">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ <Global
+ Name="RESOURCE_FILE"
+ Value="resource.rc"/>
+ </Globals>
+</VisualStudioProject>
diff --git a/plugins/TabSRMM/DEPRECATED/tabsrmm_9.sln b/plugins/TabSRMM/DEPRECATED/tabsrmm_9.sln
new file mode 100644
index 0000000000..fe00cca356
--- /dev/null
+++ b/plugins/TabSRMM/DEPRECATED/tabsrmm_9.sln
@@ -0,0 +1,38 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tabsrmm", "tabsrmm_9.vcproj", "{99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug Unicode|Win32 = Debug Unicode|Win32
+ Debug Unicode|x64 = Debug Unicode|x64
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release Unicode|Win32 = Release Unicode|Win32
+ Release Unicode|x64 = Release Unicode|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Debug Unicode|Win32.ActiveCfg = Debug Unicode|Win32
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Debug Unicode|Win32.Build.0 = Debug Unicode|Win32
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Debug Unicode|x64.ActiveCfg = Debug Unicode|x64
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Debug Unicode|x64.Build.0 = Debug Unicode|x64
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Debug|Win32.Build.0 = Debug|Win32
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Debug|x64.ActiveCfg = Debug|Win32
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Debug|x64.Build.0 = Debug|Win32
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Release Unicode|Win32.ActiveCfg = Release Unicode|Win32
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Release Unicode|Win32.Build.0 = Release Unicode|Win32
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Release Unicode|x64.ActiveCfg = Release Unicode|x64
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Release Unicode|x64.Build.0 = Release Unicode|x64
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Release|Win32.ActiveCfg = Release|Win32
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Release|Win32.Build.0 = Release|Win32
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Release|x64.ActiveCfg = Release|Win32
+ {99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}.Release|x64.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/plugins/TabSRMM/Makefile b/plugins/TabSRMM/Makefile
new file mode 100644
index 0000000000..5ab409d0a5
--- /dev/null
+++ b/plugins/TabSRMM/Makefile
@@ -0,0 +1,129 @@
+#
+# There exist several targets which are by default empty and which can be
+# used for execution of your targets. These targets are usually executed
+# before and after some main targets. They are:
+#
+# .build-pre: called before 'build' target
+# .build-post: called after 'build' target
+# .clean-pre: called before 'clean' target
+# .clean-post: called after 'clean' target
+# .clobber-pre: called before 'clobber' target
+# .clobber-post: called after 'clobber' target
+# .all-pre: called before 'all' target
+# .all-post: called after 'all' target
+# .help-pre: called before 'help' target
+# .help-post: called after 'help' target
+#
+# Targets beginning with '.' are not intended to be called on their own.
+#
+# Main targets can be executed directly, and they are:
+#
+# build build a specific configuration
+# clean remove built files from a configuration
+# clobber remove all built files
+# all build all configurations
+# help print help mesage
+#
+# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
+# .help-impl are implemented in nbproject/makefile-impl.mk.
+#
+# Available make variables:
+#
+# CND_BASEDIR base directory for relative paths
+# CND_DISTDIR default top distribution directory (build artifacts)
+# CND_BUILDDIR default top build directory (object files, ...)
+# CONF name of current configuration
+# CND_PLATFORM_${CONF} platform name (current configuration)
+# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration)
+# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration)
+# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration)
+# CND_PACKAGE_DIR_${CONF} directory of package (current configuration)
+# CND_PACKAGE_NAME_${CONF} name of package (current configuration)
+# CND_PACKAGE_PATH_${CONF} path to package (current configuration)
+#
+# NOCDDL
+
+
+# Environment
+MKDIR=mkdir
+CP=cp
+CCADMIN=CCadmin
+RANLIB=ranlib
+
+
+# build
+build: .build-post
+
+.build-pre:
+# Add your pre 'build' code here...
+
+.build-post: .build-impl
+# Add your post 'build' code here...
+
+
+# clean
+clean: .clean-post
+
+.clean-pre:
+# Add your pre 'clean' code here...
+
+.clean-post: .clean-impl
+# Add your post 'clean' code here...
+
+
+# clobber
+clobber: .clobber-post
+
+.clobber-pre:
+# Add your pre 'clobber' code here...
+
+.clobber-post: .clobber-impl
+# Add your post 'clobber' code here...
+
+
+# all
+all: .all-post
+
+.all-pre:
+# Add your pre 'all' code here...
+
+.all-post: .all-impl
+# Add your post 'all' code here...
+
+
+# build tests
+build-tests: .build-tests-post
+
+.build-tests-pre:
+# Add your pre 'build-tests' code here...
+
+.build-tests-post: .build-tests-impl
+# Add your post 'build-tests' code here...
+
+
+# run tests
+test: .test-post
+
+.test-pre:
+# Add your pre 'test' code here...
+
+.test-post: .test-impl
+# Add your post 'test' code here...
+
+
+# help
+help: .help-post
+
+.help-pre:
+# Add your pre 'help' code here...
+
+.help-post: .help-impl
+# Add your post 'help' code here...
+
+
+
+# include project implementation makefile
+include nbproject/Makefile-impl.mk
+
+# include project make variables
+include nbproject/Makefile-variables.mk
diff --git a/plugins/TabSRMM/chat/Icons/1.ico b/plugins/TabSRMM/chat/Icons/1.ico
new file mode 100644
index 0000000000..2c7324149c
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/1.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/2.ico b/plugins/TabSRMM/chat/Icons/2.ico
new file mode 100644
index 0000000000..f212c16855
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/2.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/3.ico b/plugins/TabSRMM/chat/Icons/3.ico
new file mode 100644
index 0000000000..680cfd63e1
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/3.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/4.ico b/plugins/TabSRMM/chat/Icons/4.ico
new file mode 100644
index 0000000000..d39ae9ea76
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/4.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/5.ico b/plugins/TabSRMM/chat/Icons/5.ico
new file mode 100644
index 0000000000..a7186bed69
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/5.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/6.ico b/plugins/TabSRMM/chat/Icons/6.ico
new file mode 100644
index 0000000000..550c72285e
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/6.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/1.ico b/plugins/TabSRMM/chat/Icons/NOVA/1.ico
new file mode 100644
index 0000000000..51dcdc4648
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/1.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/2.ico b/plugins/TabSRMM/chat/Icons/NOVA/2.ico
new file mode 100644
index 0000000000..819ecc1d7a
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/2.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/3.ico b/plugins/TabSRMM/chat/Icons/NOVA/3.ico
new file mode 100644
index 0000000000..0928e257fe
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/3.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/4.ico b/plugins/TabSRMM/chat/Icons/NOVA/4.ico
new file mode 100644
index 0000000000..5dcea114fa
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/4.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/5.ico b/plugins/TabSRMM/chat/Icons/NOVA/5.ico
new file mode 100644
index 0000000000..6aa5806c53
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/5.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/6.ico b/plugins/TabSRMM/chat/Icons/NOVA/6.ico
new file mode 100644
index 0000000000..c35cc39ebc
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/6.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/Bkgcolor.ico b/plugins/TabSRMM/chat/Icons/NOVA/Bkgcolor.ico
new file mode 100644
index 0000000000..e3322ef34b
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/Bkgcolor.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/action.ico b/plugins/TabSRMM/chat/Icons/NOVA/action.ico
new file mode 100644
index 0000000000..44816c42d7
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/action.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/addmode.ico b/plugins/TabSRMM/chat/Icons/NOVA/addmode.ico
new file mode 100644
index 0000000000..a6a7e6f38c
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/addmode.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/blank.ico b/plugins/TabSRMM/chat/Icons/NOVA/blank.ico
new file mode 100644
index 0000000000..7845f62fed
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/blank.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/filter.ico b/plugins/TabSRMM/chat/Icons/NOVA/filter.ico
new file mode 100644
index 0000000000..7c99edb58c
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/filter.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/filter2.ico b/plugins/TabSRMM/chat/Icons/NOVA/filter2.ico
new file mode 100644
index 0000000000..701890522b
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/filter2.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/highlight.ico b/plugins/TabSRMM/chat/Icons/NOVA/highlight.ico
new file mode 100644
index 0000000000..552c912eaa
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/highlight.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/history.ico b/plugins/TabSRMM/chat/Icons/NOVA/history.ico
new file mode 100644
index 0000000000..537c9b52c5
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/history.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/info.ico b/plugins/TabSRMM/chat/Icons/NOVA/info.ico
new file mode 100644
index 0000000000..1acdb7190b
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/info.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/join.ico b/plugins/TabSRMM/chat/Icons/NOVA/join.ico
new file mode 100644
index 0000000000..151cd93211
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/join.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/kick.ico b/plugins/TabSRMM/chat/Icons/NOVA/kick.ico
new file mode 100644
index 0000000000..c93e92dd77
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/kick.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/message.ico b/plugins/TabSRMM/chat/Icons/NOVA/message.ico
new file mode 100644
index 0000000000..19957e4ac8
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/message.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/messageout.ico b/plugins/TabSRMM/chat/Icons/NOVA/messageout.ico
new file mode 100644
index 0000000000..637196b745
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/messageout.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/nick.ico b/plugins/TabSRMM/chat/Icons/NOVA/nick.ico
new file mode 100644
index 0000000000..3f199ffd50
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/nick.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/nicklist_hide.ico b/plugins/TabSRMM/chat/Icons/NOVA/nicklist_hide.ico
new file mode 100644
index 0000000000..f2f611d6a4
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/nicklist_hide.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/nicklist_show.ico b/plugins/TabSRMM/chat/Icons/NOVA/nicklist_show.ico
new file mode 100644
index 0000000000..cba204fe5e
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/nicklist_show.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/notice.ico b/plugins/TabSRMM/chat/Icons/NOVA/notice.ico
new file mode 100644
index 0000000000..1ba34d7244
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/notice.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/overlay.ico b/plugins/TabSRMM/chat/Icons/NOVA/overlay.ico
new file mode 100644
index 0000000000..28742d898d
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/overlay.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/part.ico b/plugins/TabSRMM/chat/Icons/NOVA/part.ico
new file mode 100644
index 0000000000..39c24868aa
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/part.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/quit.ico b/plugins/TabSRMM/chat/Icons/NOVA/quit.ico
new file mode 100644
index 0000000000..d7fbdaf4b7
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/quit.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/removestatus.ico b/plugins/TabSRMM/chat/Icons/NOVA/removestatus.ico
new file mode 100644
index 0000000000..ea3cef3fef
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/removestatus.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/tag1.ico b/plugins/TabSRMM/chat/Icons/NOVA/tag1.ico
new file mode 100644
index 0000000000..1dc687becd
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/tag1.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/tag2.ico b/plugins/TabSRMM/chat/Icons/NOVA/tag2.ico
new file mode 100644
index 0000000000..4fac50a4c8
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/tag2.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/topic.ico b/plugins/TabSRMM/chat/Icons/NOVA/topic.ico
new file mode 100644
index 0000000000..e4bb7da7e0
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/topic.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/topicbut.ico b/plugins/TabSRMM/chat/Icons/NOVA/topicbut.ico
new file mode 100644
index 0000000000..ddb72fb8ca
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/topicbut.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/NOVA/window.ico b/plugins/TabSRMM/chat/Icons/NOVA/window.ico
new file mode 100644
index 0000000000..5c21ea3052
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/NOVA/window.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/action.ico b/plugins/TabSRMM/chat/Icons/action.ico
new file mode 100644
index 0000000000..1bccf99db6
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/action.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/addmode.ico b/plugins/TabSRMM/chat/Icons/addmode.ico
new file mode 100644
index 0000000000..844b7c5d46
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/addmode.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/bkgcolor.ico b/plugins/TabSRMM/chat/Icons/bkgcolor.ico
new file mode 100644
index 0000000000..11c54ab502
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/bkgcolor.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/blank.ico b/plugins/TabSRMM/chat/Icons/blank.ico
new file mode 100644
index 0000000000..7845f62fed
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/blank.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/filter.ico b/plugins/TabSRMM/chat/Icons/filter.ico
new file mode 100644
index 0000000000..02aa5455f6
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/filter.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/filter2.ico b/plugins/TabSRMM/chat/Icons/filter2.ico
new file mode 100644
index 0000000000..3473eb9979
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/filter2.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/highlight.ico b/plugins/TabSRMM/chat/Icons/highlight.ico
new file mode 100644
index 0000000000..abdf6a0c2c
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/highlight.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/history.ico b/plugins/TabSRMM/chat/Icons/history.ico
new file mode 100644
index 0000000000..b2477bc7d3
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/history.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/info.ico b/plugins/TabSRMM/chat/Icons/info.ico
new file mode 100644
index 0000000000..db229094dc
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/info.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/join.ico b/plugins/TabSRMM/chat/Icons/join.ico
new file mode 100644
index 0000000000..3e062a1a95
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/join.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/kick.ico b/plugins/TabSRMM/chat/Icons/kick.ico
new file mode 100644
index 0000000000..e7de687686
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/kick.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/message.ico b/plugins/TabSRMM/chat/Icons/message.ico
new file mode 100644
index 0000000000..cb543ce737
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/message.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/messageout.ico b/plugins/TabSRMM/chat/Icons/messageout.ico
new file mode 100644
index 0000000000..4376f1e756
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/messageout.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/nick.ico b/plugins/TabSRMM/chat/Icons/nick.ico
new file mode 100644
index 0000000000..97b681f0c7
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/nick.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/nicklist_hide.ico b/plugins/TabSRMM/chat/Icons/nicklist_hide.ico
new file mode 100644
index 0000000000..7abd838725
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/nicklist_hide.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/nicklist_show.ico b/plugins/TabSRMM/chat/Icons/nicklist_show.ico
new file mode 100644
index 0000000000..9390b173b3
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/nicklist_show.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/notice.ico b/plugins/TabSRMM/chat/Icons/notice.ico
new file mode 100644
index 0000000000..31ebb310f6
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/notice.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/overlay.ico b/plugins/TabSRMM/chat/Icons/overlay.ico
new file mode 100644
index 0000000000..a3f7cf6c36
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/overlay.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/part.ico b/plugins/TabSRMM/chat/Icons/part.ico
new file mode 100644
index 0000000000..1444253dee
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/part.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/quit.ico b/plugins/TabSRMM/chat/Icons/quit.ico
new file mode 100644
index 0000000000..2d54d764cf
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/quit.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/removestatus.ico b/plugins/TabSRMM/chat/Icons/removestatus.ico
new file mode 100644
index 0000000000..7f4711e8a9
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/removestatus.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/tag1.ico b/plugins/TabSRMM/chat/Icons/tag1.ico
new file mode 100644
index 0000000000..1dc687becd
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/tag1.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/tag2.ico b/plugins/TabSRMM/chat/Icons/tag2.ico
new file mode 100644
index 0000000000..4fac50a4c8
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/tag2.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/topic.ico b/plugins/TabSRMM/chat/Icons/topic.ico
new file mode 100644
index 0000000000..5c7fff78a1
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/topic.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/topicbut.ico b/plugins/TabSRMM/chat/Icons/topicbut.ico
new file mode 100644
index 0000000000..48bec51143
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/topicbut.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/Icons/window.ico b/plugins/TabSRMM/chat/Icons/window.ico
new file mode 100644
index 0000000000..d64d924548
--- /dev/null
+++ b/plugins/TabSRMM/chat/Icons/window.ico
Binary files differ
diff --git a/plugins/TabSRMM/chat/chat.h b/plugins/TabSRMM/chat/chat.h
new file mode 100644
index 0000000000..e06634beef
--- /dev/null
+++ b/plugins/TabSRMM/chat/chat.h
@@ -0,0 +1,369 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * This code is based on and still contains large parts of the the
+ * original chat module for Miranda IM, written and copyrighted
+ * by Joergen Persson in 2005.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: chat.h 12272 2010-08-04 08:24:08Z silvercircle $
+ *
+ */
+
+#ifndef _CHAT_H_
+#define _CHAT_H_
+
+#pragma warning( disable : 4786 ) // limitation in MSVC's debugger.
+#pragma warning( disable : 4996 ) // limitation in MSVC's debugger.
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "m_stdhdr.h"
+
+//defines
+#define OPTIONS_FONTCOUNT 20
+#define GC_UPDATETITLE (WM_USER+100)
+#define GC_CLOSEWINDOW (WM_USER+103)
+#define GC_GETITEMDATA (WM_USER+104)
+#define GC_SETITEMDATA (WM_USER+105)
+#define GC_UPDATESTATUSBAR (WM_USER+106)
+#define GC_SETVISIBILITY (WM_USER+107)
+#define GC_SETWNDPROPS (WM_USER+108)
+#define GC_REDRAWLOG (WM_USER+109)
+#define GC_FIREHOOK (WM_USER+110)
+#define GC_FILTERFIX (WM_USER+111)
+#define GC_CHANGEFILTERFLAG (WM_USER+112)
+#define GC_SHOWFILTERMENU (WM_USER+113)
+//#define GC_NICKLISTCLEAR (WM_USER+117)
+#define GC_REDRAWWINDOW (WM_USER+118)
+#define GC_SHOWCOLORCHOOSER (WM_USER+119)
+#define GC_ADDLOG (WM_USER+120)
+#define GC_ACKMESSAGE (WM_USER+121)
+//#define GC_ADDUSER (WM_USER+122)
+//#define GC_REMOVEUSER (WM_USER+123)
+//#define GC_NICKCHANGE (WM_USER+124)
+#define GC_UPDATENICKLIST (WM_USER+125)
+//#define GC_MODECHANGE (WM_USER+126)
+#define GC_SCROLLTOBOTTOM (WM_USER+129)
+#define GC_SESSIONNAMECHANGE (WM_USER+131)
+#define GC_SETMESSAGEHIGHLIGHT (WM_USER+139)
+#define GC_REDRAWLOG2 (WM_USER+140)
+#define GC_REDRAWLOG3 (WM_USER+141)
+
+#define EM_ACTIVATE (WM_USER+202)
+
+#define GC_EVENT_HIGHLIGHT 0x1000
+#define STATE_TALK 0x0001
+
+#define ICON_ACTION 0
+#define ICON_ADDSTATUS 1
+#define ICON_HIGHLIGHT 2
+#define ICON_INFO 3
+#define ICON_JOIN 4
+#define ICON_KICK 5
+#define ICON_MESSAGE 6
+#define ICON_MESSAGEOUT 7
+#define ICON_NICK 8
+#define ICON_NOTICE 9
+#define ICON_PART 10
+#define ICON_QUIT 11
+#define ICON_REMSTATUS 12
+#define ICON_TOPIC 13
+
+#define ICON_STATUS1 14
+#define ICON_STATUS2 15
+#define ICON_STATUS3 16
+#define ICON_STATUS4 17
+#define ICON_STATUS0 18
+#define ICON_STATUS5 19
+
+// special service for tweaking performance
+#define MS_GC_GETEVENTPTR "GChat/GetNewEventPtr"
+typedef INT_PTR (*GETEVENTFUNC)(WPARAM wParam, LPARAM lParam);
+typedef struct {
+ GETEVENTFUNC pfnAddEvent;
+}GCPTRS;
+
+class CMUCHighlight;
+
+//structs
+
+typedef struct MODULE_INFO_TYPE
+{
+ char* pszModule;
+ TCHAR* ptszModDispName;
+ char* pszHeader;
+ BOOL bBold;
+ BOOL bUnderline;
+ BOOL bItalics;
+ BOOL bColor;
+ BOOL bBkgColor;
+ BOOL bChanMgr;
+ BOOL bAckMsg;
+ int nColorCount;
+ COLORREF* crColors;
+ /*
+ HICON hOnlineIcon;
+ HICON hOfflineIcon;
+ HICON hOnlineTalkIcon;
+ HICON hOfflineTalkIcon;
+ int OnlineIconIndex;
+ int OfflineIconIndex;
+ */
+ int iMaxText;
+ DWORD idleTimeStamp;
+ DWORD lastIdleCheck;
+ TCHAR tszIdleMsg[60];
+ CMUCHighlight* Highlight;
+ struct MODULE_INFO_TYPE *next;
+}
+ MODULEINFO;
+
+typedef struct COMMAND_INFO_TYPE
+{
+ char* lpCommand;
+ struct COMMAND_INFO_TYPE *last, *next;
+}
+ COMMAND_INFO;
+
+typedef struct
+{
+ LOGFONT lf;
+ COLORREF color;
+}
+ FONTINFO;
+
+typedef struct LOG_INFO_TYPE
+{
+ TCHAR* ptszText;
+ TCHAR* ptszNick;
+ TCHAR* ptszUID;
+ TCHAR* ptszStatus;
+ TCHAR* ptszUserInfo;
+ BOOL bIsMe;
+ BOOL bIsHighlighted;
+ time_t time;
+ int iType;
+ DWORD dwFlags;
+ struct LOG_INFO_TYPE *next;
+ struct LOG_INFO_TYPE *prev;
+}
+ LOGINFO;
+
+typedef struct STATUSINFO_TYPE
+{
+ TCHAR* pszGroup;
+ HICON hIcon;
+ WORD Status;
+ struct STATUSINFO_TYPE *next;
+}
+ STATUSINFO;
+
+typedef struct USERINFO_TYPE
+{
+ TCHAR* pszNick;
+ TCHAR* pszUID;
+ WORD Status;
+ int iStatusEx;
+ WORD ContactStatus;
+ struct USERINFO_TYPE *next;
+}
+ USERINFO;
+
+typedef struct SESSIONINFO_TYPE
+{
+ HWND hWnd;
+
+ BOOL bFGSet;
+ BOOL bBGSet;
+ BOOL bFilterEnabled;
+ BOOL bNicklistEnabled;
+ BOOL bInitDone;
+
+ char* pszModule;
+ TCHAR* ptszID;
+ TCHAR* ptszName;
+ TCHAR* ptszStatusbarText;
+ TCHAR* ptszTopic;
+ TCHAR pszLogFileName[MAX_PATH + 50];
+
+ char* pszID; // ugly fix for returning static ANSI strings in GC_INFO
+ char* pszName; // just to fix a bug quickly, should die after porting IRC to Unicode
+
+ int iType;
+ int iFG;
+ int iBG;
+ int iSplitterY;
+ int iSplitterX;
+ int iLogFilterFlags;
+ int iLogPopupFlags;
+ int iLogTrayFlags;
+ int iDiskLogFlags;
+ int nUsersInNicklist;
+ int iEventCount;
+ int iStatusCount;
+
+ WORD wStatus;
+ WORD wState;
+ WORD wCommandsNum;
+ DWORD dwItemData;
+ DWORD dwFlags;
+ HANDLE hContact;
+ HWND hwndFilter;
+ time_t LastTime;
+ TCHAR szSearch[255];
+ int iSearchItem;
+ CMUCHighlight* Highlight;
+ COMMAND_INFO* lpCommands;
+ COMMAND_INFO* lpCurrentCommand;
+ LOGINFO* pLog;
+ LOGINFO* pLogEnd;
+ USERINFO* pUsers;
+ USERINFO* pMe;
+ STATUSINFO* pStatuses;
+ TContainerData *pContainer;
+ TWindowData *dat;
+ int wasTrimmed;
+ SESSIONINFO_TYPE* next;
+} SESSION_INFO;
+
+typedef struct
+{
+ char* buffer;
+ int bufferOffset, bufferLen;
+ HWND hwnd;
+ LOGINFO* lin;
+ BOOL bStripFormat;
+ BOOL bRedraw;
+ SESSION_INFO* si;
+ int crCount;
+ TWindowData* dat;
+}
+ LOGSTREAMDATA;
+
+struct TMUCSettings {
+ HICON hIconOverlay;
+ BOOL ShowTime;
+ BOOL ShowTimeIfChanged;
+ BOOL LoggingEnabled;
+ BOOL FlashWindow;
+ BOOL FlashWindowHightlight;
+ BOOL OpenInDefault;
+ BOOL HighlightEnabled;
+ BOOL LogIndentEnabled;
+ BOOL StripFormat;
+ BOOL BBCodeInPopups;
+ BOOL TrayIconInactiveOnly;
+ BOOL AddColonToAutoComplete;
+ BOOL LogLimitNames;
+ BOOL TimeStampEventColour;
+ DWORD dwIconFlags;
+ int LogTextIndent;
+ long LoggingLimit;
+ int iEventLimit;
+ int iEventLimitThreshold;
+ int iPopupStyle;
+ int iPopupTimeout;
+ int iSplitterX;
+ int iSplitterY;
+ TCHAR* pszTimeStamp;
+ TCHAR* pszTimeStampLog;
+ TCHAR* pszIncomingNick;
+ TCHAR* pszOutgoingNick;
+ TCHAR pszLogDir[MAX_PATH + 20];
+ LONG iNickListFontHeight;
+ HFONT UserListFont, UserListHeadingsFont;
+ HFONT NameFont;
+ COLORREF crUserListColor;
+ COLORREF crUserListBGColor;
+ COLORREF crUserListHeadingsColor;
+ COLORREF crPUTextColour;
+ COLORREF crPUBkgColour;
+ BYTE ClassicIndicators;
+ //MAD
+ BYTE LogClassicIndicators;
+ BYTE AlternativeSorting;
+ BYTE AnnoyingHighlight;
+ BYTE CreateWindowOnHighlight;
+ //MAD_
+ BYTE LogSymbols;
+ BYTE ClickableNicks;
+ BYTE ColorizeNicks;
+ BYTE ColorizeNicksInLog;
+ BYTE ScaleIcons;
+ BYTE UseDividers;
+ BYTE DividersUsePopupConfig;
+ BYTE MathMod;
+ COLORREF nickColors[8];
+ HBRUSH SelectionBGBrush;
+ BOOL DoubleClick4Privat;
+ BOOL ShowContactStatus;
+ BOOL ContactStatusFirst;
+ HANDLE hGroup;
+ CMUCHighlight* Highlight;
+};
+
+struct FLASH_PARAMS {
+ HANDLE hContact;
+ const char* sound;
+ int iEvent;
+ HICON hNotifyIcon;
+ BOOL bActiveTab, bHighlight, bInactive, bMustFlash, bMustAutoswitch;
+ HWND hWnd;
+};
+
+extern TMUCSettings g_Settings;
+
+typedef struct{
+ MODULEINFO* pModule;
+ int xPosition;
+ int yPosition;
+ HWND hWndTarget;
+ BOOL bForeground;
+ SESSION_INFO* si;
+} COLORCHOOSER;
+
+#pragma comment(lib,"comctl32.lib")
+
+//////////////////////////////////////////////////////////////////////////////////
+
+#include "chatprototypes.h"
+#include "chat_resource.h"
+
+#define mir_tstrdup mir_wstrdup
+
+TCHAR* a2t( const char* str );
+char* t2a( const TCHAR* str, DWORD codepage );
+TCHAR* a2tf( const TCHAR* str, int flags, DWORD cp );
+TCHAR* replaceStr( TCHAR** dest, const TCHAR* src );
+char* replaceStrA( char** dest, const char* src );
+
+extern char *szChatIconString;
+
+#define DEFLOGFILENAME _T("%miranda_logpath%\\%proto%\\%userid%.log")
+
+#endif
diff --git a/plugins/TabSRMM/chat/chat.rc b/plugins/TabSRMM/chat/chat.rc
new file mode 100644
index 0000000000..47c2a877fa
--- /dev/null
+++ b/plugins/TabSRMM/chat/chat.rc
@@ -0,0 +1,411 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "chat_resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+#include "richedit.h"
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_CHANNEL DIALOGEX 0, 0, 252, 140
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_SPLITTERX,"Static",SS_ENHMETAFILE,172,23,10,73
+ CONTROL "",IDC_SPLITTERY,"Static",SS_ENHMETAFILE,0,132,251,6
+ CONTROL "",IDC_CHAT_MESSAGE,"RichEdit20W",WS_VSCROLL | WS_TABSTOP | 0x1144,0,128,127,12,WS_EX_STATICEDGE
+ CONTROL "",IDC_CHAT_LOG,"RichEdit20W",WS_VSCROLL | 0x844,8,23,164,72,WS_EX_STATICEDGE
+ LISTBOX IDC_LIST,182,23,69,73,LBS_MULTIPLESEL | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | LBS_NODATA | NOT WS_BORDER | WS_VSCROLL | WS_TABSTOP,WS_EX_STATICEDGE
+ CONTROL "",IDC_PANELSPLITTER,"Static",SS_ENHMETAFILE,0,32,252,1,WS_EX_TRANSPARENT
+END
+
+IDD_ADDHIGHLIGHT DIALOG 0, 0, 212, 97
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_BORDER
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "",IDC_STATIC,0,0,211,97
+ LTEXT "",IDC_ADDHIGHLIGHTTITLE,7,3,201,12,SS_CENTERIMAGE
+ COMBOBOX IDC_ADDHIGHLIGHTNAME,17,24,178,17,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "You can add the user by user name or his id. Wildcards are allowed and recommended.",IDC_ADDHIGHLIGHTEXPLAIN,15,49,179,21
+ DEFPUSHBUTTON "OK",IDOK,152,76,55,14
+ DEFPUSHBUTTON "Cancel",IDCANCEL,91,76,55,14
+ EDITTEXT IDC_ADDHIGHLIGHTEDITLIST,9,18,192,47,ES_AUTOHSCROLL
+END
+
+IDD_FILTER DIALOG 0, 0, 201, 126
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_BORDER
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "",IDC_STATIC,0,0,201,124
+ LTEXT " Show these events",IDC_TEXTO,1,0,91,13,SS_CENTERIMAGE
+ CONTROL "Actions",IDC_1,"Button",BS_AUTO3STATE | WS_TABSTOP,3,13,114,10
+ CONTROL "Messages",IDC_2,"Button",BS_AUTO3STATE | WS_TABSTOP,3,23,114,10
+ CONTROL "Nick changes",IDC_3,"Button",BS_AUTO3STATE | WS_TABSTOP,3,33,114,10
+ CONTROL "Users joining",IDC_4,"Button",BS_AUTO3STATE | WS_TABSTOP,3,43,114,10
+ CONTROL "Users leaving",IDC_5,"Button",BS_AUTO3STATE | WS_TABSTOP,3,53,114,10
+ CONTROL "Topic changes",IDC_6,"Button",BS_AUTO3STATE | WS_TABSTOP,3,63,114,10
+ CONTROL "Status changes",IDC_7,"Button",BS_AUTO3STATE | WS_TABSTOP,3,73,114,10
+ CONTROL "Information",IDC_8,"Button",BS_AUTO3STATE | WS_TABSTOP,3,83,114,10
+ CONTROL "Disconnects",IDC_9,"Button",BS_AUTO3STATE | WS_TABSTOP,3,93,114,10
+ CONTROL "User kicks",IDC_10,"Button",BS_AUTO3STATE | WS_TABSTOP,3,103,114,10
+ CONTROL "Notices",IDC_11,"Button",BS_AUTO3STATE | WS_TABSTOP,3,113,82,10
+ CTEXT "Popup",IDC_TEXTO2,105,0,43,13,SS_CENTERIMAGE
+ CTEXT "Tray",IDC_TEXTO3,159,0,34,13,SS_CENTERIMAGE
+ CONTROL "",IDC_P1,"Button",BS_AUTO3STATE | WS_TABSTOP,123,13,21,10
+ CONTROL "",IDC_P2,"Button",BS_AUTO3STATE | WS_TABSTOP,123,23,21,10
+ CONTROL "",IDC_P3,"Button",BS_AUTO3STATE | WS_TABSTOP,123,33,21,10
+ CONTROL "",IDC_P4,"Button",BS_AUTO3STATE | WS_TABSTOP,123,43,21,10
+ CONTROL "",IDC_P5,"Button",BS_AUTO3STATE | WS_TABSTOP,123,53,21,10
+ CONTROL "",IDC_P6,"Button",BS_AUTO3STATE | WS_TABSTOP,123,63,21,10
+ CONTROL "",IDC_P7,"Button",BS_AUTO3STATE | WS_TABSTOP,123,73,21,10
+ CONTROL "",IDC_P8,"Button",BS_AUTO3STATE | WS_TABSTOP,123,83,21,10
+ CONTROL "",IDC_P9,"Button",BS_AUTO3STATE | WS_TABSTOP,123,93,21,10
+ CONTROL "",IDC_P10,"Button",BS_AUTO3STATE | WS_TABSTOP,123,103,21,10
+ CONTROL "",IDC_P11,"Button",BS_AUTO3STATE | WS_TABSTOP,123,113,21,10
+ CONTROL "",IDC_T1,"Button",BS_AUTO3STATE | WS_TABSTOP,173,13,21,10
+ CONTROL "",IDC_T2,"Button",BS_AUTO3STATE | WS_TABSTOP,173,23,21,10
+ CONTROL "",IDC_T3,"Button",BS_AUTO3STATE | WS_TABSTOP,173,33,21,10
+ CONTROL "",IDC_T4,"Button",BS_AUTO3STATE | WS_TABSTOP,173,43,21,10
+ CONTROL "",IDC_T5,"Button",BS_AUTO3STATE | WS_TABSTOP,173,53,21,10
+ CONTROL "",IDC_T6,"Button",BS_AUTO3STATE | WS_TABSTOP,173,63,21,10
+ CONTROL "",IDC_T7,"Button",BS_AUTO3STATE | WS_TABSTOP,173,73,21,10
+ CONTROL "",IDC_T8,"Button",BS_AUTO3STATE | WS_TABSTOP,173,83,21,10
+ CONTROL "",IDC_T9,"Button",BS_AUTO3STATE | WS_TABSTOP,173,93,21,10
+ CONTROL "",IDC_T10,"Button",BS_AUTO3STATE | WS_TABSTOP,173,103,21,10
+ CONTROL "",IDC_T11,"Button",BS_AUTO3STATE | WS_TABSTOP,173,113,21,10
+END
+
+IDD_OPTIONS1 DIALOGEX 0, 0, 306, 236
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Options",IDC_STATIC,3,0,300,229
+ CONTROL "",IDC_CHECKBOXES,"SysTreeView32",TVS_HASBUTTONS | TVS_DISABLEDRAGDROP | TVS_FULLROWSELECT | WS_BORDER | WS_TABSTOP,6,9,294,177
+ LTEXT "Add new rooms to group:",IDC_STATIC_ADD,10,213,132,8
+ EDITTEXT IDC_GROUP,152,210,50,14,ES_AUTOHSCROLL
+ LTEXT "Chat integration is disabled. You can enable it here, and then you to NEED RESTART Miranda after making this change.\n\nYou MUST disable the standard chat plugin when you enable the group chat support here. Otherwise no group chat at all may work.",IDC_STATIC_MESSAGE,21,52,256,74
+END
+
+IDD_OPTIONS2 DIALOGEX 0, 0, 306, 239
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Log files",IDC_STATIC,1,2,299,95
+ CONTROL "Enable logging to disk",IDC_LOGGING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,14,277,10
+ LTEXT "Log directory",IDC_STATIC110,17,27,211,8
+ EDITTEXT IDC_LOGDIRECTORY,15,38,211,14,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_FONTCHOOSE,230,39,19,14
+ LTEXT "Maximum size for log files (in kB)",IDC_STATIC112,17,62,159,11
+ EDITTEXT IDC_LIMIT,230,59,38,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_CHAT_SPIN4,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,261,57,11,14
+ GROUPBOX "Group chat log formatting",IDC_STATIC,1,101,299,59
+ LTEXT "Your name",IDC_STATIC,10,111,50,8
+ EDITTEXT IDC_OUTSTAMP,10,121,35,14,ES_AUTOHSCROLL
+ LTEXT "Other name",IDC_STATIC,60,111,57,8
+ EDITTEXT IDC_INSTAMP,60,121,35,14,ES_AUTOHSCROLL
+ LTEXT "Timestamp (window)",IDC_STATIC,118,111,78,8
+ EDITTEXT IDC_TIMESTAMP,118,121,81,14,ES_AUTOHSCROLL
+ LTEXT "Timestamp (logfile)",IDC_STATIC,205,111,81,8
+ EDITTEXT IDC_LOGTIMESTAMP,205,121,81,14,ES_AUTOHSCROLL
+ LTEXT "Maximum number of events in the message window",IDC_STATIC,10,142,225,11
+ EDITTEXT IDC_LOGLIMIT,248,139,38,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Spin1",IDC_CHAT_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,281,138,11,14
+ LTEXT "Groupchat userlist row height (pixels)",IDC_STATIC_ULIST,10,212,221,8
+ EDITTEXT IDC_NICKROW2,247,209,29,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_CHAT_SPIN3,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,275,215,11,14
+ PUSHBUTTON "Open log file base folder",IDC_MUC_OPENLOGBASEDIR,16,76,155,14
+END
+
+IDD_OPTIONS3 DIALOGEX 0, 0, 306, 239
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Default settings for known event types",IDC_STATIC,7,5,293,153
+ LTEXT "Show when filter is active",IDC_STATIC,12,14,119,13,SS_CENTERIMAGE
+ CTEXT "Log to file",IDC_TEXTO4,234,13,64,13,SS_CENTERIMAGE
+ CTEXT "Show Popup",IDC_TEXTO2,131,13,49,13,SS_CENTERIMAGE
+ CTEXT "Notify in tray",IDC_TEXTO3,183,13,49,13,SS_CENTERIMAGE
+ CONTROL "Actions",IDC_1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,28,110,10
+ CONTROL "Messages",IDC_2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,38,110,10
+ CONTROL "Nick changes",IDC_3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,48,110,10
+ CONTROL "Users joining",IDC_4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,58,110,10
+ CONTROL "Users leaving",IDC_5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,68,110,10
+ CONTROL "Topic changes",IDC_6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,78,110,10
+ CONTROL "Status changes",IDC_7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,88,110,10
+ CONTROL "Information",IDC_8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,98,110,10
+ CONTROL "Disconnects",IDC_9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,108,110,10
+ CONTROL "User kicks",IDC_10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,118,110,10
+ CONTROL "Notices",IDC_11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,32,128,110,10
+ CONTROL "",IDC_P1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,28,21,10
+ CONTROL "",IDC_P2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,38,21,10
+ CONTROL "",IDC_P3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,48,21,10
+ CONTROL "",IDC_P4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,58,21,10
+ CONTROL "",IDC_P5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,68,21,10
+ CONTROL "",IDC_P6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,78,21,10
+ CONTROL "",IDC_P7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,88,21,10
+ CONTROL "",IDC_P8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,98,21,10
+ CONTROL "",IDC_P9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,108,21,10
+ CONTROL "",IDC_P10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,118,21,10
+ CONTROL "",IDC_P11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,128,21,10
+ CONTROL "",IDC_P12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,152,138,21,10
+ CONTROL "",IDC_T1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,28,21,10
+ CONTROL "",IDC_T2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,38,21,10
+ CONTROL "",IDC_T3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,48,21,10
+ CONTROL "",IDC_T4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,58,21,10
+ CONTROL "",IDC_T5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,68,21,10
+ CONTROL "",IDC_T6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,78,21,10
+ CONTROL "",IDC_T7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,88,21,10
+ CONTROL "",IDC_T8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,98,21,10
+ CONTROL "",IDC_T9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,108,21,10
+ CONTROL "",IDC_T10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,118,21,10
+ CONTROL "",IDC_T11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,128,21,10
+ CONTROL "",IDC_T12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,138,21,10
+ CONTROL "",IDC_L1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,28,21,10
+ CONTROL "",IDC_L2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,38,21,10
+ CONTROL "",IDC_L3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,48,21,10
+ CONTROL "",IDC_L4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,58,21,10
+ CONTROL "",IDC_L5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,68,21,10
+ CONTROL "",IDC_L6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,78,21,10
+ CONTROL "",IDC_L7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,88,21,10
+ CONTROL "",IDC_L8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,98,21,10
+ CONTROL "",IDC_L9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,108,21,10
+ CONTROL "",IDC_L10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,118,21,10
+ CONTROL "",IDC_L11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,128,21,10
+ CONTROL "Suppress tray notifications for focused channel windows",IDC_TRAYONLYFORINACTIVE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,164,279,10
+ CONTROL "Do not show popups when the channel window is not open",IDC_NOPOPUPSFORCLOSEDWINDOWS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,176,282,10
+ LTEXT "Highlight event",IDC_STATIC,44,139,68,12
+ COMBOBOX IDC_LOGICONTYPE,12,212,171,38,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Line markers in the message log",IDC_STATIC,14,201,257,10
+END
+
+IDD_OPTIONS4 DIALOGEX 0, 0, 306, 239
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Highlight user names",IDC_STATIC,3,6,300,104
+ CONTROL "Enable highlighting for user names",IDC_HIGHLIGHTNICKENABLE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,20,278,11
+ CONTROL "Also look in user ids",IDC_HIGHLIGHTNICKUID,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,34,278,11
+ EDITTEXT IDC_HIGHLIGHTNICKPATTERN,11,69,283,35,ES_AUTOHSCROLL
+ LTEXT "Names to highlight, wildcards like * and ? are allowed, separate multiple entries with spaces",IDC_STATIC,10,49,284,19
+ GROUPBOX "Highlight message text",IDC_STATIC,3,113,300,122
+ CONTROL "Enable highlighting for message text",IDC_HIGHLIGHTTEXTENABLE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,125,278,11
+ EDITTEXT IDC_HIGHLIGHTTEXTPATTERN,11,172,283,35,ES_AUTOHSCROLL
+ LTEXT "Words to highlight, wildcards like * and ? are allowed, separate multiple entries with spaces. Leave it empty if you only want to highlight your own nick name.",IDC_STATIC,10,141,284,23
+ CONTROL "Highlight messages containing my own nick name",IDC_HIGHLIGHTME,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,216,278,11
+END
+
+IDD_COLORCHOOSER DIALOGEX 0, 0, 198, 150
+STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_BORDER
+EXSTYLE WS_EX_TOPMOST
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,172,136,26,14,NOT WS_TABSTOP
+ CTEXT "",IDC_COLORTEXT,0,0,197,12,SS_CENTERIMAGE
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_CHANNEL, DIALOG
+ BEGIN
+ RIGHTMARGIN, 251
+ VERTGUIDE, 8
+ VERTGUIDE, 172
+ VERTGUIDE, 182
+ VERTGUIDE, 237
+ HORZGUIDE, 8
+ HORZGUIDE, 23
+ HORZGUIDE, 70
+ HORZGUIDE, 96
+ HORZGUIDE, 102
+ HORZGUIDE, 108
+ HORZGUIDE, 121
+ END
+
+ IDD_FILTER, DIALOG
+ BEGIN
+ VERTGUIDE, 5
+ VERTGUIDE, 78
+ HORZGUIDE, 13
+ HORZGUIDE, 117
+ END
+
+ IDD_OPTIONS1, DIALOG
+ BEGIN
+ RIGHTMARGIN, 300
+ VERTGUIDE, 10
+ VERTGUIDE, 152
+ VERTGUIDE, 181
+ VERTGUIDE, 202
+ VERTGUIDE, 290
+ HORZGUIDE, 12
+ HORZGUIDE, 174
+ HORZGUIDE, 192
+ HORZGUIDE, 213
+ END
+
+ IDD_OPTIONS2, DIALOG
+ BEGIN
+ LEFTMARGIN, 1
+ RIGHTMARGIN, 295
+ VERTGUIDE, 10
+ VERTGUIDE, 60
+ VERTGUIDE, 144
+ VERTGUIDE, 158
+ VERTGUIDE, 183
+ VERTGUIDE, 221
+ VERTGUIDE, 286
+ TOPMARGIN, 1
+ HORZGUIDE, 107
+ HORZGUIDE, 126
+ HORZGUIDE, 146
+ HORZGUIDE, 150
+ HORZGUIDE, 174
+ HORZGUIDE, 212
+ END
+
+ IDD_OPTIONS3, DIALOG
+ BEGIN
+ END
+
+ IDD_OPTIONS4, DIALOG
+ BEGIN
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Swedish (Sweden) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_SVE)
+LANGUAGE LANG_SWEDISH, SUBLANG_SWEDISH
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "chat_resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winres.h""\r\n"
+ "#include ""richedit.h""\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU
+BEGIN
+ POPUP "List"
+ BEGIN
+ MENUITEM "&Message", ID_MESS
+ END
+ POPUP "Log"
+ BEGIN
+ MENUITEM "Clear lo&g", ID_CLEARLOG
+ MENUITEM SEPARATOR
+ MENUITEM "Co&py all", ID_COPYALL
+ MENUITEM SEPARATOR
+ POPUP "Word lookup", GRAYED
+ BEGIN
+ MENUITEM "Google", ID_SEARCH_GOOGLE
+ MENUITEM "Wikipedia", ID_SEARCH_WIKIPEDIA
+ END
+ END
+ POPUP "Link"
+ BEGIN
+ MENUITEM "Open a &new browser window", ID_NEW
+ MENUITEM "&Open in current browser window", ID_CURR
+ MENUITEM "&Copy link", ID_COPY
+ END
+ MENUITEM "", 65535
+ POPUP "Message"
+ BEGIN
+ MENUITEM "Undo ", ID_MESSAGE_UNDO, GRAYED
+ MENUITEM "Redo", ID_MESSAGE_REDO, GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "Copy", ID_MESSAGE_COPY, GRAYED
+ MENUITEM "Cut", ID_MESSAGE_CUT, GRAYED
+ MENUITEM "Paste", ID_MESSAGE_PASTE
+ MENUITEM "Select All", ID_MESSAGE_SELECTALL
+ MENUITEM SEPARATOR
+ MENUITEM "Clear", ID_MESSAGE_CLEAR
+ END
+ POPUP "Tabs"
+ BEGIN
+ MENUITEM "&Close tab", ID_CLOSE
+ MENUITEM "C&lose other tabs", ID_CLOSEOTHER
+ MENUITEM SEPARATOR
+ MENUITEM "&Open at this position", ID_LOCKPOSITION
+ END
+END
+
+#endif // Swedish (Sweden) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/plugins/TabSRMM/chat/chat_resource.h b/plugins/TabSRMM/chat/chat_resource.h
new file mode 100644
index 0000000000..07a9bb8ba4
--- /dev/null
+++ b/plugins/TabSRMM/chat/chat_resource.h
@@ -0,0 +1,161 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by chat.rc
+//
+#define IDR_MENU 151
+#define IDD_CHANNEL 401
+#define IDD_OPTIONS1 402
+#define IDD_OPTIONS2 403
+#define IDD_FILTER 404
+#define IDD_OPTIONSPOPUP 405
+#define IDD_COLORCHOOSER 406
+#define IDD_OPTIONS3 407
+#define IDD_OPTIONS4 408
+#define IDD_ADDHIGHLIGHT 409
+#define IDC_CHAT_LOG 1005
+#define IDC_SPLITTERX 1006
+#define IDC_SMILEY 1007
+#define IDC_SPLITTERY 1008
+#define IDC_CHAT_MESSAGE 1009
+#define IDC_FILTER 1013
+#define IDC_CHANMGR 1014
+#define IDC_SHOWNICKLIST 1015
+#define IDC_BKGCOLOR 1019
+#define IDC_CHECKBOXES 1021
+#define IDC_NICKROW2 1023
+#define IDC_NICKROW 1024
+#define IDC_LOGLIMIT 1024
+#define IDC_CHAT_CLOSE 1025
+#define IDC_CHAT_SPIN1 1028
+#define IDC_CHAT_SPIN2 1029
+#define IDC_CHAT_SPIN3 1030
+#define IDC_CHAT_SPIN4 1031
+#define IDC_PANELNICK 1032
+#define IDC_PANELUIN 1033
+#define IDC_INSTAMP 1041
+#define IDC_OUTSTAMP 1043
+#define IDC_TIMESTAMP 1046
+#define IDC_FONTCHOOSE 1047
+#define IDC_LOGDIRECTORY 1048
+#define IDC_LIMIT 1050
+#define IDC_LOGTIMESTAMP 1051
+#define IDC_GROUP 1057
+#define IDC_CHAT_RADIO1 1061
+#define IDC_RADIO2 1062
+#define IDC_RADIO3 1063
+#define IDC_TEXT 1064
+#define IDC_BKG 1065
+#define IDC_TIMEOUT 1067
+#define IDC_TEXTO 1069
+#define IDC_LOGGING 1069
+#define IDC_COLORTEXT 1070
+#define IDC_TEXTO2 1070
+#define IDC_TEXTO3 1071
+#define IDC_LIST 1072
+#define IDC_TEXTO4 1072
+#define IDC_STATIC_ADD 1077
+#define IDC_STATIC_ULIST 1078
+#define IDC_STATIC_OTHER 1079
+#define IDC_STATIC_MESSAGE 1081
+#define IDC_STATIC110 1082
+#define IDC_STATIC112 1085
+#define IDC_TRAYONLYFORINACTIVE 1086
+#define IDC_NOPOPUPSFORCLOSEDWINDOWS 1087
+#define IDC_LOGICONTYPE 1088
+#define IDC_HIGHLIGHTNICKENABLE 1089
+#define IDC_HIGHLIGHTNICKUID 1090
+#define IDC_HIGHLIGHTNICKPATTERN 1091
+#define IDC_HIGHLIGHTTEXTENABLE 1092
+#define IDC_COMBO1 1092
+#define IDC_ADDHIGHLIGHTNAME 1092
+#define IDC_HIGHLIGHTTEXTPATTERN 1093
+#define IDC_ADDHIGHLIGHTTITLE 1093
+#define IDC_ADDHIGHLIGHTEXPLAIN 1094
+#define IDC_HIGHLIGHTNICKUID2 1094
+#define IDC_HIGHLIGHTME 1094
+#define IDC_ADDHIGHLIGHTEDITLIST 1095
+#define IDC_MUC_OPENLOGBASEDIR 1096
+#define IDC_CHAT_BOLD 1106
+#define IDC_ITALICS 1107
+#define IDC_CHAT_UNDERLINE 1108
+#define IDC_COLOR 1110
+#define IDC_CHAT_HISTORY 1111
+#define IDC_1 1200
+#define IDC_2 1201
+#define IDC_3 1202
+#define IDC_4 1203
+#define IDC_5 1204
+#define IDC_6 1205
+#define IDC_7 1206
+#define IDC_8 1207
+#define IDC_9 1208
+#define IDC_10 1209
+#define IDC_11 1210
+#define IDC_PANELSPLITTER 1216
+#define IDC_CHAT_TOGGLESIDEBAR 1277
+#define IDC_P1 1300
+#define IDC_P2 1301
+#define IDC_P3 1302
+#define IDC_P4 1303
+#define IDC_P5 1304
+#define IDC_P6 1305
+#define IDC_P7 1306
+#define IDC_P8 1307
+#define IDC_P9 1308
+#define IDC_P10 1309
+#define IDC_P11 1310
+#define IDC_P12 1311
+#define IDC_T1 1400
+#define IDC_T2 1401
+#define IDC_T3 1402
+#define IDC_T4 1403
+#define IDC_T5 1404
+#define IDC_T6 1405
+#define IDC_T7 1406
+#define IDC_T8 1407
+#define IDC_T9 1408
+#define IDC_T10 1409
+#define IDC_T11 1410
+#define IDC_T12 1411
+#define IDC_L1 1500
+#define IDC_L2 1501
+#define IDC_L3 1502
+#define IDC_L4 1503
+#define IDC_L5 1504
+#define IDC_L6 1505
+#define IDC_L7 1506
+#define IDC_L8 1507
+#define IDC_L9 1508
+#define IDC_L10 1509
+#define IDC_L11 1510
+#define IDC_WHITERECT 1600
+#define ID_MESS 40001
+#define ID_NEW 40002
+#define ID_CURR 40003
+#define ID_COPY 40004
+#define ID_COPYALL 40006
+#define ID_CLEARLOG 40009
+#define ID_MESSAGE_UNDO 40013
+#define ID_MESSAGE_COPY 40014
+#define ID_MESSAGE_CUT 40015
+#define ID_MESSAGE_CLEAR 40017
+#define ID_MESSAGE_SELECTALL 40018
+#define ID_MESSAGE_REDO 40019
+#define ID_MESSAGE_PASTE 40020
+#define ID_CLOSE 40022
+#define ID_CLOSEOTHER 40023
+#define ID_LOCKPOSITION 40024
+#define ID_SEARCH_GOOGLE 40027
+#define ID_SEARCH_WIKIPEDIA 40028
+#define ID_WIKIPEDIA_ 40029
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 163
+#define _APS_NEXT_COMMAND_VALUE 40030
+#define _APS_NEXT_CONTROL_VALUE 1097
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plugins/TabSRMM/chat/chatprototypes.h b/plugins/TabSRMM/chat/chatprototypes.h
new file mode 100644
index 0000000000..066a25e919
--- /dev/null
+++ b/plugins/TabSRMM/chat/chatprototypes.h
@@ -0,0 +1,174 @@
+/*
+Chat module plugin for Miranda IM
+
+Copyright (C) 2003-2009 Joergen Persson and others
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+$Id: chatprototypes.h 13184 2010-12-07 14:16:58Z silvercircle $
+
+*/
+
+void LoadIcons(void);
+void LoadLogIcons(void);
+void FreeIcons(void);
+void UpgradeCheck(void);
+
+//colorchooser.c
+INT_PTR CALLBACK DlgProcColorToolWindow(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+//log.c
+void Log_StreamInEvent(HWND hwndDlg, LOGINFO* lin, SESSION_INFO* si, BOOL bRedraw, BOOL bPhaseTwo);
+void LoadMsgLogBitmaps(void);
+void FreeMsgLogBitmaps(void);
+TCHAR* GetChatLogsFilename(SESSION_INFO *si, time_t tTime);
+TCHAR* MakeTimeStamp(TCHAR* pszStamp, time_t time);
+char* Log_CreateRtfHeader(MODULEINFO * mi);
+
+//window.c
+INT_PTR CALLBACK RoomWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam);
+int GetTextPixelSize( TCHAR* pszText, HFONT hFont, BOOL bWidth);
+
+//options.c
+enum { FONTSECTION_AUTO, FONTSECTION_CHAT, FONTSECTION_IM, FONTSECTION_IP };
+int OptionsInit(void);
+int OptionsUnInit(void);
+void LoadMsgDlgFont(int section, int i, LOGFONT * lf, COLORREF * colour, char* szMod );
+void LoadGlobalSettings(void);
+void AddIcons(void);
+HICON LoadIconEx(int iIndex, char * pszIcoLibName, int iX, int iY);
+
+//services.c
+void HookEvents(void);
+void UnhookEvents(void);
+int CreateServiceFunctions(void);
+void DestroyServiceFunctions(void);
+void DestroyHookableEvents(void);
+void CreateHookableEvents(void);
+void TabsInit(void);
+int ModulesLoaded(WPARAM wParam,LPARAM lParam);
+int SmileyOptionsChanged(WPARAM wParam,LPARAM lParam);
+int PreShutdown(WPARAM wParam,LPARAM lParam);
+int IconsChanged(WPARAM wParam,LPARAM lParam);
+void ShowRoom(SESSION_INFO* si, WPARAM wp, BOOL bSetForeground);
+INT_PTR Service_AddEvent(WPARAM wParam, LPARAM lParam);
+int Service_ItemData(WPARAM wParam, LPARAM lParam);
+int Service_SetSBText(WPARAM wParam, LPARAM lParam);
+int Service_SetVisibility(WPARAM wParam, LPARAM lParam);
+INT_PTR Service_GetCount(WPARAM wParam,LPARAM lParam);
+
+HWND CreateNewRoom(TContainerData *pContainer, SESSION_INFO *si, BOOL bActivateTab, BOOL bPopupContainer, BOOL bWantPopup);
+
+//manager.c
+void SetActiveSession(const TCHAR* pszID, const char* pszModule);
+void SetActiveSessionEx(SESSION_INFO* si);
+SESSION_INFO* GetActiveSession(void);
+SESSION_INFO* SM_AddSession(const TCHAR* pszID, const char* pszModule);
+int SM_RemoveSession(const TCHAR* pszID, const char* pszModule);
+SESSION_INFO* SM_FindSession(const TCHAR* pszID, const char* pszModule);
+USERINFO* SM_AddUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus);
+SESSION_INFO* SM_FindSessionAutoComplete(const char* pszModule, SESSION_INFO* currSession, SESSION_INFO* prevSession, const TCHAR* pszOriginal, const TCHAR* pszCurrent);
+BOOL SM_ChangeUID(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszNewUID);
+BOOL SM_ChangeNick(const TCHAR* pszID, const char* pszModule, GCEVENT * gce);
+BOOL SM_RemoveUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID);
+BOOL SM_SetOffline(const TCHAR* pszID, const char* pszModule);
+HICON SM_GetStatusIcon(SESSION_INFO* si, USERINFO* ui, char* szIndicator);
+BOOL SM_SetStatus(const TCHAR* pszID, const char* pszModule, int wStatus);
+BOOL SM_SetStatusEx(const TCHAR* pszID, const char* pszModule, const TCHAR* pszText, int flags );
+BOOL SM_SendUserMessage(const TCHAR* pszID, const char* pszModule, const TCHAR* pszText);
+STATUSINFO* SM_AddStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszStatus);
+BOOL SM_AddEventToAllMatchingUID(GCEVENT * gce, BOOL bisHighLight = FALSE);
+BOOL SM_AddEvent(const TCHAR* pszID, const char* pszModule, GCEVENT * gce, BOOL bIsHighlighted);
+LRESULT SM_SendMessage(const TCHAR* pszID, const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam);
+BOOL SM_PostMessage(const TCHAR* pszID, const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam);
+BOOL SM_BroadcastMessage(const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam, BOOL bAsync);
+BOOL SM_RemoveAll (void);
+BOOL SM_GiveStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszStatus);
+BOOL SM_SetContactStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, WORD pszStatus);
+BOOL SM_TakeStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszStatus);
+BOOL SM_MoveUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID);
+void SM_AddCommand(const TCHAR* pszID, const char* pszModule, const char* lpNewCommand);
+char* SM_GetPrevCommand(const TCHAR* pszID, const char* pszModule);
+char* SM_GetNextCommand(const TCHAR* pszID, const char* pszModule);
+int SM_GetCount(const char* pszModule);
+SESSION_INFO* SM_FindSessionByHWND(HWND h);
+SESSION_INFO* SM_FindSessionByHCONTACT(HANDLE h);
+SESSION_INFO* SM_FindSessionByIndex(const char* pszModule, int iItem);
+char* SM_GetUsers(SESSION_INFO* si);
+USERINFO* SM_GetUserFromIndex(const TCHAR* pszID, const char* pszModule, int index);
+BOOL SM_ReconfigureFilters();
+BOOL SM_InvalidateLogDirectories();
+MODULEINFO* MM_AddModule(const char* pszModule);
+MODULEINFO* MM_FindModule(const char* pszModule);
+void MM_FixColors();
+void MM_FontsChanged(void);
+void MM_IconsChanged(void);
+BOOL MM_RemoveAll (void);
+BOOL TabM_AddTab(const TCHAR* pszID, const char* pszModule);
+BOOL TabM_RemoveAll (void);
+STATUSINFO* TM_AddStatus(STATUSINFO** ppStatusList, const TCHAR* pszStatus, int* iCount);
+STATUSINFO* TM_FindStatus(STATUSINFO* pStatusList, const TCHAR* pszStatus);
+WORD TM_StringToWord(STATUSINFO* pStatusList, const TCHAR* pszStatus);
+TCHAR* TM_WordToString(STATUSINFO* pStatusList, WORD Status);
+BOOL TM_RemoveAll (STATUSINFO** pStatusList);
+BOOL UM_SetStatusEx(USERINFO* pUserList,const TCHAR* pszText, int onlyMe );
+USERINFO* UM_AddUser(STATUSINFO* pStatusList, USERINFO** pUserList, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus);
+USERINFO* UM_SortUser(USERINFO** ppUserList, const TCHAR* pszUID);
+USERINFO* UM_FindUser(USERINFO* pUserList, const TCHAR* pszUID);
+USERINFO* UM_FindUserFromIndex(USERINFO* pUserList, int index);
+USERINFO* UM_GiveStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status);
+USERINFO* UM_SetContactStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status);
+USERINFO* UM_TakeStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status);
+TCHAR* UM_FindUserAutoComplete(USERINFO* pUserList, const TCHAR* pszOriginal, const TCHAR* pszCurrent);
+BOOL UM_RemoveUser(USERINFO** pUserList, const TCHAR* pszUID);
+BOOL UM_RemoveAll (USERINFO** ppUserList);
+LOGINFO* LM_AddEvent(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd);
+BOOL LM_TrimLog(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd, int iCount);
+BOOL LM_RemoveAll (LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd);
+
+//clist.c
+HANDLE CList_AddRoom(const char* pszModule, const TCHAR* pszRoom, const TCHAR* pszDisplayName, int iType);
+BOOL CList_SetOffline(HANDLE hContact, BOOL bHide);
+BOOL CList_SetAllOffline(BOOL bHide, const char *pszModule);
+int CList_RoomDoubleclicked(WPARAM wParam,LPARAM lParam);
+INT_PTR CList_EventDoubleclicked(WPARAM wParam,LPARAM lParam);
+INT_PTR CList_JoinChat(WPARAM wParam, LPARAM lParam);
+INT_PTR CList_LeaveChat(WPARAM wParam, LPARAM lParam);
+int CList_PrebuildContactMenu(WPARAM wParam, LPARAM lParam);
+INT_PTR CList_PrebuildContactMenuSvc(WPARAM wParam, LPARAM lParam);
+void CList_CreateGroup(TCHAR* group);
+BOOL CList_AddEvent(HANDLE hContact, HICON Icon, HANDLE event, int type, const TCHAR* fmt, ... ) ;
+HANDLE CList_FindRoom (const char* pszModule, const TCHAR* pszRoom) ;
+int WCCmp(TCHAR* wild, TCHAR*string);
+
+//tools.c
+TCHAR* RemoveFormatting(const TCHAR* pszText, bool fLower = false, bool fStripCR = false, TCHAR* buf = 0, const size_t len = 0);
+BOOL DoSoundsFlashPopupTrayStuff(SESSION_INFO* si, GCEVENT * gce, BOOL bHighlight, int bManyFix);
+int Chat_GetColorIndex(const char* pszModule, COLORREF cr);
+void CheckColorsInModule(const char* pszModule);
+TCHAR* my_strstri(const TCHAR* s1, const TCHAR* s2) ;
+int GetRichTextLength(HWND hwnd);
+BOOL IsHighlighted(SESSION_INFO* si, const TCHAR* pszText);
+UINT CreateGCMenu(HWND hwndDlg, HMENU *hMenu, int iIndex, POINT pt, SESSION_INFO* si, TCHAR* pszUID, TCHAR* pszWordText);
+void DestroyGCMenu(HMENU *hMenu, int iIndex);
+BOOL DoEventHookAsync(HWND hwnd, const TCHAR* pszID, const char* pszModule, int iType, TCHAR* pszUID, TCHAR* pszText, DWORD dwItem);
+BOOL DoEventHook(const TCHAR* pszID, const char* pszModule, int iType, const TCHAR* pszUID, const TCHAR* pszText, DWORD dwItem);
+BOOL IsEventSupported(int eventType);
+BOOL LogToFile(SESSION_INFO* si, GCEVENT * gce);
+void Chat_SetFilters(SESSION_INFO *si);
+void TSAPI DoFlashAndSoundWorker(FLASH_PARAMS* p);
+// message.c
+char* Chat_Message_GetFromStream(HWND hwndDlg, SESSION_INFO* si);
+TCHAR* Chat_DoRtfToTags( char* pszRtfText, SESSION_INFO* si);
diff --git a/plugins/TabSRMM/chat/clist.cpp b/plugins/TabSRMM/chat/clist.cpp
new file mode 100644
index 0000000000..d321c4d017
--- /dev/null
+++ b/plugins/TabSRMM/chat/clist.cpp
@@ -0,0 +1,326 @@
+/*
+astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ --pad=oper --one-line=keep-blocks --unpad=paren
+
+Chat module plugin for Miranda IM
+
+Copyright (C) 2003 Jörgen Persson
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Group chat module: contact list support functions. Add chat rooms as
+contacts and handle default action for such contacts.
+
+This code was taken in almost unmodified from from the chat.dll
+plugin, originally written by Jörgen Persson
+
+$Id: clist.c 10402 2009-07-24 00:35:21Z silvercircle $
+
+*/
+
+/*
+ * handles interaction of the group chat implementation with the contact list plugin
+ */
+
+#include "../src/commonheaders.h"
+
+char *szChatIconString = "chaticon";
+
+extern HANDLE hJoinMenuItem, hLeaveMenuItem;
+
+static HANDLE Clist_GroupExists(TCHAR *tszGroup)
+{
+ unsigned int i = 0;
+ TCHAR* _t = 0;
+ char str[10];
+ INT_PTR result = 0;
+ DBVARIANT dbv = {0};
+ int match;
+
+ do {
+ _itoa(i, str, 10);
+ result = M->GetTString(0, "CListGroups", str, &dbv);
+ if(!result) {
+ match = (!_tcscmp(tszGroup, &dbv.ptszVal[1]) && (lstrlen(tszGroup) == lstrlen(&dbv.ptszVal[1])));
+ DBFreeVariant(&dbv);
+ if(match)
+ return((HANDLE)(i + 1));
+ }
+ i++;
+ }
+ while(result == 0);
+ return(0);
+}
+
+HANDLE CList_AddRoom(const char* pszModule, const TCHAR* pszRoom, const TCHAR* pszDisplayName, int iType)
+{
+ HANDLE hContact = CList_FindRoom(pszModule, pszRoom);
+ DBVARIANT dbv;
+ TCHAR pszGroup[50];
+
+ *pszGroup = '\0';
+ if (!M->GetTString(NULL, "Chat", "AddToGroup", &dbv)) {
+ if (lstrlen(dbv.ptszVal) > 0)
+ lstrcpyn(pszGroup, dbv.ptszVal, 50);
+ DBFreeVariant(&dbv);
+ } else
+ lstrcpyn(pszGroup, _T("Chat rooms"), 50);
+
+ if (pszGroup[0])
+ CList_CreateGroup(pszGroup);
+
+ if (hContact)
+ return hContact;
+
+ // here we create a new one since no one is to be found
+
+ if ((hContact = (HANDLE) CallService(MS_DB_CONTACT_ADD, 0, 0)) == NULL)
+ return NULL;
+
+ CallService(MS_PROTO_ADDTOCONTACT, (WPARAM) hContact, (LPARAM) pszModule);
+ if (pszGroup && lstrlen(pszGroup) > 0)
+ CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)hContact, (LPARAM)g_Settings.hGroup);
+ else
+ DBDeleteContactSetting(hContact, "CList", "Group");
+
+ M->WriteTString(hContact, pszModule, "Nick", pszDisplayName);
+ M->WriteTString(hContact, pszModule, "ChatRoomID", pszRoom);
+ M->WriteByte(hContact, pszModule, "ChatRoom", (BYTE)iType);
+ DBWriteContactSettingWord(hContact, pszModule, "Status", ID_STATUS_OFFLINE);
+ return hContact;
+}
+
+BOOL CList_SetOffline(HANDLE hContact, BOOL bHide)
+{
+ if (hContact) {
+ char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ int i = M->GetByte(hContact, szProto, "ChatRoom", 0);
+ DBWriteContactSettingWord(hContact, szProto, "ApparentMode", (LPARAM) 0);
+ DBWriteContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL CList_SetAllOffline(BOOL bHide, const char *pszModule)
+{
+ HANDLE hContact;
+ char* szProto;
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (MM_FindModule(szProto)) {
+ if (!pszModule || (pszModule && !strcmp(pszModule, szProto))) {
+ int i = M->GetByte(hContact, szProto, "ChatRoom", 0);
+ if (i != 0) {
+ DBWriteContactSettingWord(hContact, szProto, "ApparentMode", (LPARAM)(WORD) 0);
+ DBWriteContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ }
+ }
+ }
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+ return TRUE;
+}
+
+int CList_RoomDoubleclicked(WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+ char *szProto;
+ BOOL bRedrawFlag = FALSE;
+ bool fCreate = false;
+
+ HANDLE hContact = (HANDLE)wParam;
+ if (!hContact)
+ return 0;
+
+ szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (MM_FindModule(szProto)) {
+ if (M->GetByte(hContact, szProto, "ChatRoom", 0) == 0)
+ return 0;
+
+ if (!M->GetTString(hContact, szProto, "ChatRoomID", &dbv)) {
+ SESSION_INFO* si = SM_FindSession(dbv.ptszVal, szProto);
+ if (si) {
+ // is the "toggle visibility option set, so we need to close the window?
+ if (si->hWnd != NULL
+ && M->GetByte("Chat", "ToggleVisibility", 0) == 1
+ && !CallService(MS_CLIST_GETEVENT, (WPARAM)hContact, 0)
+ && IsWindowVisible(si->hWnd)
+ && !IsIconic(si->pContainer->hwnd)) {
+ PostMessage(si->hWnd, GC_CLOSEWINDOW, 0, 0);
+ DBFreeVariant(&dbv);
+ return 1;
+ }
+ else
+ fCreate = true;
+
+ ShowRoom(si, WINDOW_VISIBLE, TRUE);
+ if(lParam && fCreate) {
+ SendMessage(si->hWnd, DM_ACTIVATEME, 0, 0);
+ if(si->dat)
+ SetForegroundWindow(si->dat->pContainer->hwnd);
+ }
+ }
+ DBFreeVariant(&dbv);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+INT_PTR CList_EventDoubleclicked(WPARAM wParam, LPARAM lParam)
+{
+ return CList_RoomDoubleclicked((WPARAM)((CLISTEVENT*)lParam)->hContact, (LPARAM) 0);
+}
+
+INT_PTR CList_JoinChat(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)wParam;
+ if ( hContact ) {
+ char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if ( szProto ) {
+ if ( DBGetContactSettingWord( hContact, szProto, "Status", 0 ) == ID_STATUS_OFFLINE )
+ CallProtoService( szProto, PS_JOINCHAT, wParam, lParam );
+ else
+ CList_RoomDoubleclicked( wParam, 0 );
+ } }
+
+ return 0;
+}
+
+INT_PTR CList_LeaveChat(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)wParam;
+ if ( hContact ) {
+ char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if ( szProto )
+ CallProtoService( szProto, PS_LEAVECHAT, wParam, lParam );
+ }
+ return 0;
+}
+
+int CList_PrebuildContactMenu(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)wParam;
+ if ( hContact ) {
+ char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+
+ CLISTMENUITEM clmi = {0};
+ clmi.cbSize = sizeof( CLISTMENUITEM );
+ clmi.flags = CMIM_FLAGS | CMIF_DEFAULT | CMIF_HIDDEN;
+
+ if ( szProto ) {
+ // display this menu item only for chats
+ if ( M->GetByte(hContact, szProto, "ChatRoom", 0 )) {
+ // still hide it for offline protos
+ if ( CallProtoService( szProto, PS_GETSTATUS, 0, 0 ) != ID_STATUS_OFFLINE ) {
+ clmi.flags &= ~CMIF_HIDDEN;
+ clmi.flags |= CMIM_NAME;
+
+ if ( DBGetContactSettingWord( hContact, szProto, "Status", 0 ) == ID_STATUS_OFFLINE )
+ clmi.pszName = ( char* )LPGEN("Join chat");
+ else
+ clmi.pszName = ( char* )LPGEN("Open chat window");
+ } } }
+ CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hJoinMenuItem, ( LPARAM )&clmi );
+
+ clmi.flags &= ~(CMIM_NAME | CMIF_DEFAULT);
+ clmi.flags |= CMIF_NOTOFFLINE;
+ CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hLeaveMenuItem, ( LPARAM )&clmi );
+ }
+ return 0;
+}
+
+INT_PTR CList_PrebuildContactMenuSvc(WPARAM wParam, LPARAM lParam)
+{
+ return CList_PrebuildContactMenu(wParam, lParam);
+}
+
+
+void CList_CreateGroup(TCHAR* group)
+{
+ if (!group)
+ return;
+
+ g_Settings.hGroup = Clist_GroupExists(group);
+
+ if(g_Settings.hGroup == 0) {
+ g_Settings.hGroup = (HANDLE)CallService(MS_CLIST_GROUPCREATE, 0, (LPARAM)group);
+
+ if(g_Settings.hGroup) {
+ CallService(MS_CLUI_GROUPADDED, (WPARAM)g_Settings.hGroup, 0);
+ CallService(MS_CLIST_GROUPSETEXPANDED, (WPARAM)g_Settings.hGroup, 1);
+ }
+ }
+}
+
+BOOL CList_AddEvent(HANDLE hContact, HICON Icon, HANDLE event, int type, const TCHAR* fmt, ...)
+{
+ CLISTEVENT cle;
+ va_list marker;
+ TCHAR* szBuf = (TCHAR*)alloca(4096 * sizeof(TCHAR));
+
+ if (!fmt || lstrlen(fmt) < 1 || lstrlen(fmt) > 2000)
+ return FALSE;
+
+ va_start(marker, fmt);
+ _vstprintf(szBuf, fmt, marker);
+ va_end(marker);
+
+ cle.cbSize = sizeof(cle);
+ cle.hContact = (HANDLE)hContact;
+ cle.hDbEvent = (HANDLE)event;
+ cle.flags = type + CLEF_TCHAR;
+ cle.hIcon = Icon;
+ cle.pszService = "GChat/DblClickEvent" ;
+ cle.ptszTooltip = TranslateTS(szBuf);
+ if (type) {
+ if (!CallService(MS_CLIST_GETEVENT, (WPARAM)hContact, (LPARAM)0))
+ CallService(MS_CLIST_ADDEVENT, (WPARAM) hContact, (LPARAM) &cle);
+ } else {
+ if (CallService(MS_CLIST_GETEVENT, (WPARAM)hContact, (LPARAM)0))
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM)hContact, (LPARAM)"chaticon");
+ CallService(MS_CLIST_ADDEVENT, (WPARAM) hContact, (LPARAM) &cle);
+ }
+ return TRUE;
+}
+
+HANDLE CList_FindRoom(const char* pszModule, const TCHAR* pszRoom)
+{
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto && !lstrcmpiA(szProto, pszModule)) {
+ if (M->GetByte(hContact, szProto, "ChatRoom", 0) != 0) {
+ DBVARIANT dbv;
+ if (!M->GetTString(hContact, szProto, "ChatRoomID", &dbv)) {
+ if (!lstrcmpi(dbv.ptszVal, pszRoom)) {
+ DBFreeVariant(&dbv);
+ return hContact;
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ }
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+ return 0;
+}
+
diff --git a/plugins/TabSRMM/chat/colorchooser.cpp b/plugins/TabSRMM/chat/colorchooser.cpp
new file mode 100644
index 0000000000..4879f56d95
--- /dev/null
+++ b/plugins/TabSRMM/chat/colorchooser.cpp
@@ -0,0 +1,281 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * This code is based on and still contains large parts of the the
+ * original chat module for Miranda IM, written and copyrighted
+ * by Joergen Persson in 2005.
+ *
+ * $Id: colorchooser.cpp 10670 2009-09-11 03:28:50Z silvercircle $
+ *
+ * Color chooser for group chats
+ *
+ */
+
+#include "../src/commonheaders.h"
+#include <math.h>
+
+static int CalculateCoordinatesToButton(COLORCHOOSER * pCC, POINT pt)
+{
+ int iSquareRoot = (int)sqrt(static_cast<float>(pCC->pModule->nColorCount));
+ int nCols = iSquareRoot * iSquareRoot < pCC->pModule->nColorCount ? iSquareRoot + 1 : iSquareRoot;
+
+ int col = pt.x / 25;
+ int row = (pt.y - 20) / 20;
+ int pos = nCols * row + col;
+
+ if (pt.y < 20 && pos >= pCC->pModule->nColorCount)
+ pos = -1;
+
+ return pos;
+}
+
+static RECT CalculateButtonToCoordinates(COLORCHOOSER * pCC, int buttonPosition)
+{
+ RECT pt;
+ int iSquareRoot = (int)sqrt(static_cast<float>(pCC->pModule->nColorCount));
+ int nCols = iSquareRoot * iSquareRoot < pCC->pModule->nColorCount ? iSquareRoot + 1 : iSquareRoot;
+
+ int row = buttonPosition / nCols;
+ int col = buttonPosition % nCols;
+
+ pt.left = col * 25 + 1;
+ pt.top = row * 20 + 20;
+ pt.right = pt.left + 25 - 1;
+ pt.bottom = pt.top + 20;
+
+ return pt;
+}
+
+INT_PTR CALLBACK DlgProcColorToolWindow(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static COLORCHOOSER* pCC = NULL;
+ static int iCurrentHotTrack;
+ static BOOL bChoosing;
+ static int iRows;
+ static int iColumns;
+ static HWND hPreviousActiveWindow;
+
+ switch (msg) {
+ case WM_INITDIALOG: {
+ RECT rc;
+ int iSquareRoot;
+ int width ;
+ int height;
+
+ TranslateDialogDefault(hwndDlg);
+ pCC = (COLORCHOOSER*) lParam;
+
+ iCurrentHotTrack = -2;
+ bChoosing = FALSE;
+
+ iSquareRoot = (int)sqrt(static_cast<float>(pCC->pModule->nColorCount));
+
+ iColumns = iSquareRoot * iSquareRoot == pCC->pModule->nColorCount ? iSquareRoot : iSquareRoot + 1;
+ iRows = iSquareRoot;
+
+ rc.top = rc.left = 100;
+ rc.right = 100 + iColumns * 25 + 1;
+ rc.bottom = iRows * 20 + 100 + 20;
+
+ AdjustWindowRectEx(&rc, GetWindowLongPtr(hwndDlg, GWL_STYLE), FALSE, GetWindowLongPtr(hwndDlg, GWL_EXSTYLE));
+
+ width = rc.right - rc.left;
+ height = rc.bottom - rc.top;
+
+ pCC->yPosition -= height;
+
+
+ SetDlgItemText(hwndDlg, IDC_COLORTEXT, pCC->bForeground ? CTranslator::get(CTranslator::GEN_MUC_TEXTCOLOR) :
+ CTranslator::get(CTranslator::GEN_MUC_BGCOLOR));
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_COLORTEXT), NULL, 0, 0, width, 20, 0);
+ SetWindowPos(hwndDlg, NULL, pCC->xPosition, pCC->yPosition, width, height, SWP_SHOWWINDOW);
+ }
+ break;
+
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_COLORTEXT)) {
+ SetTextColor((HDC)wParam, RGB(60, 60, 150));
+ SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
+ return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ if (iCurrentHotTrack >= 0)
+ PostMessage(hwndDlg, WM_LBUTTONUP, 0, 0);
+ break;
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ if (iCurrentHotTrack >= 0 && iCurrentHotTrack < pCC->pModule->nColorCount && pCC->hWndTarget != NULL) {
+ HWND hWindow;
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwMask = 0;
+ cf.dwEffects = 0;
+ hWindow = GetParent(pCC->hWndTarget);
+
+ if (pCC->bForeground) {
+ pCC->si->bFGSet = TRUE;
+ pCC->si->iFG = iCurrentHotTrack;
+ if (IsDlgButtonChecked(hWindow, IDC_COLOR)) {
+ cf.dwMask = CFM_COLOR;
+ cf.crTextColor = pCC->pModule->crColors[iCurrentHotTrack];
+ SendMessage(pCC->hWndTarget, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+ } else {
+ pCC->si->bBGSet = TRUE;
+ pCC->si->iBG = iCurrentHotTrack;
+ if (IsDlgButtonChecked(hWindow, IDC_BKGCOLOR)) {
+ cf.dwMask = CFM_BACKCOLOR;
+ cf.crBackColor = pCC->pModule->crColors[iCurrentHotTrack];
+ SendMessage(pCC->hWndTarget, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+ }
+ }
+ PostMessage(hwndDlg, WM_CLOSE, 0, 0);
+ break;
+
+ case WM_ACTIVATE:
+ if (wParam == WA_INACTIVE)
+ PostMessage(hwndDlg, WM_CLOSE, 0, 0);
+ else if ((wParam == WA_ACTIVE) || (wParam == WA_CLICKACTIVE))
+ hPreviousActiveWindow = (HWND)lParam;
+ break;
+
+ case WM_MOUSEMOVE: {
+ HDC hdc = GetDC(hwndDlg);
+ POINT pt;
+ RECT rect;
+ int but;
+
+ pt.x = LOWORD(lParam);
+ pt.y = HIWORD(lParam);
+
+ if (iCurrentHotTrack == -2)
+ return 0; // prevent focussing when not drawn yet!
+
+ but = CalculateCoordinatesToButton(pCC, pt);
+
+ // weird stuff
+ if (but != iCurrentHotTrack) {
+ if (iCurrentHotTrack >= 0) {
+ rect = CalculateButtonToCoordinates(pCC, iCurrentHotTrack);
+ DrawFocusRect(hdc, &rect);
+ iCurrentHotTrack = -1;
+ }
+ iCurrentHotTrack = but;
+
+ if (iCurrentHotTrack >= 0) {
+ rect = CalculateButtonToCoordinates(pCC, iCurrentHotTrack);
+ DrawFocusRect(hdc, &rect);
+ }
+ }
+ ReleaseDC(hwndDlg, hdc);
+ }
+ break;
+
+ case WM_PAINT: {
+ PAINTSTRUCT ps;
+ HDC hdc;
+ RECT rc;
+ int i = 0;
+ int iThisRow = 1;
+ int iThisColumn = 0;
+
+ GetClientRect(hwndDlg, &rc);
+
+ rc.top += 20;
+
+ hdc = BeginPaint(hwndDlg, &ps);
+
+ // fill background
+ FillRect(hdc, &rc, GetSysColorBrush(COLOR_WINDOW));
+
+ for (i; i < pCC->pModule->nColorCount; i++) {
+ HBRUSH hbr;
+
+ // decide place to draw the color block in the window
+ iThisColumn ++;
+ if (iThisColumn > iColumns) {
+ iThisColumn = 1;
+ iThisRow++;
+ }
+
+ if (pCC->bForeground && pCC->si->bFGSet && pCC->si->iFG == i ||
+ !pCC->bForeground && pCC->si->bBGSet && pCC->si->iBG == i) {
+ rc.top = (iThisRow - 1) * 20 + 1 + 20 ;
+ rc.left = (iThisColumn - 1) * 25 + 1 + 1 ;
+ rc.bottom = iThisRow * 20 - 1 + 20 ;
+ rc.right = iThisColumn * 25 - 1 ;
+
+ DrawEdge(hdc, &rc, EDGE_RAISED, BF_TOP | BF_LEFT | BF_RIGHT | BF_BOTTOM);
+ }
+
+ rc.top = (iThisRow - 1) * 20 + 3 + 20 ;
+ rc.left = (iThisColumn - 1) * 25 + 3 + 1 ;
+ rc.bottom = iThisRow * 20 - 3 + 20 ;
+ rc.right = iThisColumn * 25 - 3 ;
+
+ FillRect(hdc, &rc, CSkin::m_BrushBack);
+
+ hbr = CreateSolidBrush(pCC->pModule->crColors[i]);
+
+ rc.top = (iThisRow - 1) * 20 + 4 + 20;
+ rc.left = (iThisColumn - 1) * 25 + 4 + 1;
+ rc.bottom = iThisRow * 20 - 4 + 20;
+ rc.right = iThisColumn * 25 - 4;
+
+ FillRect(hdc, &rc, hbr);
+ DeleteObject(hbr);
+ }
+
+ EndPaint(hwndDlg, &ps);
+ iCurrentHotTrack = -1;
+ }
+ break;
+
+ case WM_CLOSE:
+ SetFocus(pCC->hWndTarget);
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_DESTROY:
+ mir_free(pCC);
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/plugins/TabSRMM/chat/log.cpp b/plugins/TabSRMM/chat/log.cpp
new file mode 100644
index 0000000000..7c167441d0
--- /dev/null
+++ b/plugins/TabSRMM/chat/log.cpp
@@ -0,0 +1,1352 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * This code is based on and still contains large parts of the the
+ * original chat module for Miranda IM, written and copyrighted
+ * by Joergen Persson in 2005.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: log.cpp 13614 2011-04-22 13:16:21Z borkra $
+ *
+ * Implements the richedit-based message history display for the group
+ * chat window.
+ *
+ */
+
+#include "../src/commonheaders.h"
+#include <math.h>
+#include <mbstring.h>
+#include <shlwapi.h>
+
+/*
+ * The code for streaming the text is to a large extent copied from
+ * the srmm module and then modified to fit the chat module.
+ */
+
+extern FONTINFO aFonts[OPTIONS_FONTCOUNT];
+extern HICON hIcons[30];
+
+static PBYTE pLogIconBmpBits[14];
+static int logIconBmpSize[ SIZEOF(pLogIconBmpBits)];
+
+static int logPixelSY = 0;
+static int logPixelSX = 0;
+static char *szDivider = "\\strike----------------------------------------------------------------------------\\strike0";
+static char CHAT_rtfFontsGlobal[OPTIONS_FONTCOUNT + 2][RTFCACHELINESIZE];
+static char *CHAT_rtffonts = 0;
+
+/*
+ * ieview MUC support - mostly from scriver
+ */
+
+/*
+static char* u2a( const wchar_t* src, int codepage ) {
+ int cbLen = WideCharToMultiByte( codepage, 0, src, -1, NULL, 0, NULL, NULL );
+ char* result = ( char* )mir_alloc( cbLen+1 );
+ if ( result == NULL )
+ return NULL;
+
+ WideCharToMultiByte( codepage, 0, src, -1, result, cbLen, NULL, NULL );
+ result[ cbLen ] = 0;
+ return result;
+}
+
+static char* t2acp( const TCHAR* src, int codepage ) {
+ #if defined( _UNICODE )
+ return u2a( src, codepage );
+ #else
+ return mir_strdup( src );
+ #endif
+}
+
+static TCHAR *a2tcp(const char *text, int cp) {
+ if ( text != NULL ) {
+ #if defined ( _UNICODE )
+ int cbLen = MultiByteToWideChar( cp, 0, text, -1, NULL, 0 );
+ TCHAR* result = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( cbLen+1 ));
+ if ( result == NULL )
+ return NULL;
+ MultiByteToWideChar(cp, 0, text, -1, result, cbLen);
+ return result;
+ #else
+ return mir_strdup(text);
+ #endif
+ }
+ return NULL;
+}
+
+static int Log_AppendIEView(LOGSTREAMDATA* streamData, BOOL simpleMode, TCHAR **buffer, int *cbBufferEnd, int *cbBufferAlloced, const TCHAR *fmt, ...)
+{
+ va_list va;
+ int lineLen, textCharsCount=0;
+ TCHAR* line = (TCHAR*)alloca( 8001 * sizeof(TCHAR));
+ TCHAR* d;
+ MODULEINFO *mi = MM_FindModule(streamData->si->pszModule);
+
+ va_start(va, fmt);
+ lineLen = _vsntprintf( line, 8000, fmt, va);
+ if (lineLen < 0)
+ return 0;
+ line[lineLen] = 0;
+ va_end(va);
+ lineLen = lineLen*9 + 8;
+ if (*cbBufferEnd + lineLen > *cbBufferAlloced) {
+ cbBufferAlloced[0] += (lineLen + 1024 - lineLen % 1024);
+ *buffer = (TCHAR *) mir_realloc(*buffer, *cbBufferAlloced * sizeof(TCHAR));
+ }
+
+ d = *buffer + *cbBufferEnd;
+
+ for (; *line; line++, textCharsCount++) {
+ if (*line == '%' && !simpleMode ) {
+ TCHAR szTemp[200];
+
+ szTemp[0] = '\0';
+ switch ( *++line ) {
+ case '\0':
+ case '%':
+ *d++ = '%';
+ break;
+
+ case 'c':
+ case 'f':
+ if (!g_Settings.StripFormat && !streamData->bStripFormat) {
+ if ( line[1] != '\0' && line[2] != '\0') {
+ TCHAR szTemp3[3], c = *line;
+ int col;
+ szTemp3[0] = line[1];
+ szTemp3[1] = line[2];
+ szTemp3[2] = '\0';
+ col = _ttoi(szTemp3);
+ mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%%c#%02X%02X%02X"), c, GetRValue(mi->crColors[col]), GetGValue(mi->crColors[col]), GetBValue(mi->crColors[col]));
+ }
+ }
+ line += 2;
+ break;
+ case 'C':
+ case 'F':
+ if ( !g_Settings.StripFormat && !streamData->bStripFormat) {
+ mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%%c"), *line );
+ }
+ break;
+ case 'b':
+ case 'u':
+ case 'i':
+ case 'B':
+ case 'U':
+ case 'I':
+ case 'r':
+ if ( !streamData->bStripFormat ) {
+ mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%%c"), *line );
+ }
+ break;
+ }
+
+ if ( szTemp[0] ) {
+ size_t iLen = lstrlen(szTemp);
+ memcpy( d, szTemp, iLen * sizeof(TCHAR));
+ d += iLen;
+ }
+ }
+ else if (*line == '%') {
+ *d++ = '%';
+ *d++ = (char) *line;
+ }
+ else {
+ *d++ = (TCHAR) *line;
+ }
+ }
+ *d = '\0';
+ *cbBufferEnd = (int) (d - *buffer);
+ return textCharsCount;
+}
+
+static void AddEventTextToBufferIEView(TCHAR **buffer, int *bufferEnd, int *bufferAlloced, LOGSTREAMDATA *streamData)
+{
+ if (streamData->lin->ptszText)
+ Log_AppendIEView(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T(": %s"), streamData->lin->ptszText);
+}
+
+static void AddEventToBufferIEView(TCHAR **buffer, int *bufferEnd, int *bufferAlloced, LOGSTREAMDATA *streamData, TCHAR *pszNick)
+{
+
+ if ( streamData && streamData->lin ) {
+ switch ( streamData->lin->iType ) {
+ case GC_EVENT_MESSAGE:
+ if ( streamData->lin->ptszText ) {
+ TCHAR *ptszTemp = NULL;
+ TCHAR *ptszText = streamData->lin->ptszText;
+ #if defined( _UNICODE )
+ if (streamData->dat->codePage != CP_ACP) {
+ char *aText = t2acp(streamData->lin->ptszText, CP_ACP);
+ ptszText = ptszTemp = a2tcp(aText, streamData->dat->codePage);
+ mir_free(aText);
+ }
+ #endif
+ Log_AppendIEView( streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), ptszText );
+ mir_free(ptszTemp);
+ }
+ break;
+ case GC_EVENT_ACTION:
+ if ( pszNick && streamData->lin->ptszText) {
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, _T("%s "), streamData->lin->ptszNick);
+ Log_AppendIEView(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), streamData->lin->ptszText);
+ }
+ break;
+ case GC_EVENT_JOIN:
+ if (pszNick) {
+ if (!streamData->lin->bIsMe)
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s has joined"), pszNick);
+ else
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("You have joined %s"), streamData->si->ptszName);
+ }
+ break;
+ case GC_EVENT_PART:
+ if (pszNick)
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s has left"), pszNick);
+ AddEventTextToBufferIEView(buffer, bufferEnd, bufferAlloced, streamData);
+ break;
+ case GC_EVENT_QUIT:
+ if (pszNick)
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s has disconnected"), pszNick);
+ AddEventTextToBufferIEView(buffer, bufferEnd, bufferAlloced, streamData);
+ break;
+ case GC_EVENT_NICK:
+ if (pszNick && streamData->lin->ptszText) {
+ if (!streamData->lin->bIsMe)
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s is now known as %s"), pszNick, streamData->lin->ptszText);
+ else
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("You are now known as %s"), streamData->lin->ptszText);
+ }
+ break;
+ case GC_EVENT_KICK:
+ if (pszNick && streamData->lin->ptszStatus)
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s kicked %s"), streamData->lin->ptszStatus, streamData->lin->ptszNick);
+ AddEventTextToBufferIEView(buffer, bufferEnd, bufferAlloced, streamData);
+ break;
+ case GC_EVENT_NOTICE:
+ if (pszNick && streamData->lin->ptszText) {
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("Notice from %s"), pszNick );
+ AddEventTextToBufferIEView(buffer, bufferEnd, bufferAlloced, streamData);
+ }
+ break;
+ case GC_EVENT_TOPIC:
+ if (streamData->lin->ptszText)
+ Log_AppendIEView(streamData, FALSE, buffer, bufferEnd, bufferAlloced, TranslateT("The topic is \'%s%s\'"), streamData->lin->ptszText, _T("%r"));
+ if (pszNick)
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced,
+ streamData->lin->ptszUserInfo ? TranslateT(" (set by %s on %s)"): TranslateT(" (set by %s)"),
+ pszNick, streamData->lin->ptszUserInfo);
+ break;
+ case GC_EVENT_INFORMATION:
+ if (streamData->lin->ptszText)
+ Log_AppendIEView(streamData, FALSE, buffer, bufferEnd, bufferAlloced, (streamData->lin->bIsMe) ? _T("--> %s") : _T("%s"), streamData->lin->ptszText);
+ break;
+ case GC_EVENT_ADDSTATUS:
+ if (pszNick && streamData->lin->ptszText && streamData->lin->ptszStatus)
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s enables \'%s\' status for %s"), streamData->lin->ptszText, streamData->lin->ptszStatus, streamData->lin->ptszNick);
+ break;
+ case GC_EVENT_REMOVESTATUS:
+ if (pszNick && streamData->lin->ptszText && streamData->lin->ptszStatus)
+ Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s disables \'%s\' status for %s"), streamData->lin->ptszText , streamData->lin->ptszStatus, streamData->lin->ptszNick);
+ break;
+ }
+ }
+}
+
+static void LogEventIEView(LOGSTREAMDATA *streamData, TCHAR *ptszNick)
+{
+ TCHAR *buffer = NULL;
+ int bufferEnd = 0;
+ int bufferAlloced = 0;
+ IEVIEWEVENTDATA ied;
+ IEVIEWEVENT event;
+ ZeroMemory(&event, sizeof(event));
+ event.cbSize = sizeof(event);
+ event.dwFlags = 0;
+ event.hwnd = streamData->dat->hwndIEView ? streamData->dat->hwndIEView : streamData->dat->hwndHPP;
+ event.hContact = streamData->dat->hContact;
+ event.codepage = streamData->dat->codePage;
+ event.pszProto = streamData->si->pszModule;
+ event.iType = IEE_LOG_MEM_EVENTS;
+ event.eventData = &ied;
+ event.count = 1;
+
+ ZeroMemory(&ied, sizeof(ied));
+ AddEventToBufferIEView(&buffer, &bufferEnd, &bufferAlloced, streamData, ptszNick);
+ ied.ptszNick = ptszNick;
+ ied.ptszText = buffer;
+ ied.time = streamData->lin->time;
+ ied.bIsMe = streamData->lin->bIsMe;
+
+ switch ( streamData->lin->iType ) {
+ case GC_EVENT_MESSAGE:
+ ied.iType = IEED_GC_EVENT_MESSAGE;
+ ied.dwData = IEEDD_GC_SHOW_NICK;
+ break;
+ case GC_EVENT_ACTION:
+ ied.iType = IEED_GC_EVENT_ACTION;
+ break;
+ case GC_EVENT_JOIN:
+ ied.iType = IEED_GC_EVENT_JOIN;
+ break;
+ case GC_EVENT_PART:
+ ied.iType = IEED_GC_EVENT_PART;
+ break;
+ case GC_EVENT_QUIT:
+ ied.iType = IEED_GC_EVENT_QUIT;
+ break;
+ case GC_EVENT_NICK:
+ ied.iType = IEED_GC_EVENT_NICK;
+ break;
+ case GC_EVENT_KICK:
+ ied.iType = IEED_GC_EVENT_KICK;
+ break;
+ case GC_EVENT_NOTICE:
+ ied.iType = IEED_GC_EVENT_NOTICE;
+ break;
+ case GC_EVENT_TOPIC:
+ ied.iType = IEED_GC_EVENT_TOPIC;
+ break;
+ case GC_EVENT_INFORMATION:
+ ied.iType = IEED_GC_EVENT_INFORMATION;
+ break;
+ case GC_EVENT_ADDSTATUS:
+ ied.iType = IEED_GC_EVENT_ADDSTATUS;
+ break;
+ case GC_EVENT_REMOVESTATUS:
+ ied.iType = IEED_GC_EVENT_REMOVESTATUS;
+ break;
+ }
+ ied.dwData |= g_Settings.ShowTime ? IEEDD_GC_SHOW_TIME : 0;
+ ied.dwData |= IEEDD_GC_SHOW_ICON;
+#if defined( _UNICODE )
+ ied.dwFlags = IEEDF_UNICODE_TEXT | IEEDF_UNICODE_NICK | IEEDF_UNICODE_TEXT2;
+#endif
+ ied.next = NULL;
+ CallService(streamData->dat->hwndIEView ? MS_IEVIEW_EVENT : MS_HPP_EG_EVENT, 0, (LPARAM)&event);
+ mir_free(buffer);
+}
+
+*/
+
+static int EventToIndex(LOGINFO * lin)
+{
+ switch (lin->iType) {
+ case GC_EVENT_MESSAGE:
+ if (lin->bIsMe)
+ return 10;
+ else
+ return 9;
+
+ case GC_EVENT_JOIN:
+ return 3;
+ case GC_EVENT_PART:
+ return 4;
+ case GC_EVENT_QUIT:
+ return 5;
+ case GC_EVENT_NICK:
+ return 7;
+ case GC_EVENT_KICK:
+ return 6;
+ case GC_EVENT_NOTICE:
+ return 8;
+ case GC_EVENT_TOPIC:
+ return 11;
+ case GC_EVENT_INFORMATION:
+ return 12;
+ case GC_EVENT_ADDSTATUS:
+ return 13;
+ case GC_EVENT_REMOVESTATUS:
+ return 14;
+ case GC_EVENT_ACTION:
+ return 15;
+ }
+ return 0;
+}
+
+static BYTE EventToSymbol(LOGINFO *lin)
+{
+ switch (lin->iType) {
+ case GC_EVENT_MESSAGE:
+ return (lin->bIsMe) ? 0x37 : 0x38;
+ case GC_EVENT_JOIN:
+ return 0x34;
+ case GC_EVENT_PART:
+ return 0x33;
+ case GC_EVENT_QUIT:
+ return 0x39;
+ case GC_EVENT_NICK:
+ return 0x71;
+ case GC_EVENT_KICK:
+ return 0x72;
+ case GC_EVENT_NOTICE:
+ return 0x28;
+ case GC_EVENT_INFORMATION:
+ return 0x69;
+ case GC_EVENT_ADDSTATUS:
+ return 0x35;
+ case GC_EVENT_REMOVESTATUS:
+ return 0x36;
+ case GC_EVENT_ACTION:
+ return 0x60;
+ }
+ return 0x73;
+}
+
+static int EventToIcon(LOGINFO * lin)
+{
+ switch (lin->iType) {
+ case GC_EVENT_MESSAGE:
+ if (lin->bIsMe)
+ return ICON_MESSAGEOUT;
+ else
+ return ICON_MESSAGE;
+
+ case GC_EVENT_JOIN:
+ return ICON_JOIN;
+ case GC_EVENT_PART:
+ return ICON_PART;
+ case GC_EVENT_QUIT:
+ return ICON_QUIT;
+ case GC_EVENT_NICK:
+ return ICON_NICK;
+ case GC_EVENT_KICK:
+ return ICON_KICK;
+ case GC_EVENT_NOTICE:
+ return ICON_NOTICE;
+ case GC_EVENT_TOPIC:
+ return ICON_TOPIC;
+ case GC_EVENT_INFORMATION:
+ return ICON_INFO;
+ case GC_EVENT_ADDSTATUS:
+ return ICON_ADDSTATUS;
+ case GC_EVENT_REMOVESTATUS:
+ return ICON_REMSTATUS;
+ case GC_EVENT_ACTION:
+ return ICON_ACTION;
+ }
+ return 0;
+}
+
+/* replace pattern `ptrn' with the string `rplc' in string `src' points to */
+static TCHAR * _tcsrplc(TCHAR **src, const TCHAR *ptrn, const TCHAR *rplc)
+{
+ size_t lSrc, lPtrn, lRplc;
+ TCHAR *tszFound, *tszTail;
+
+ lSrc = lstrlen(*src);
+ lPtrn = lstrlen(ptrn);
+ lRplc = lstrlen(rplc);
+ if (lPtrn && lSrc && lSrc >= lPtrn && (tszFound = _tcsstr(*src, ptrn)) != NULL) {
+ if (lRplc > lPtrn)
+ *src = (TCHAR *) realloc((void *) * src,
+ sizeof(TCHAR) * (lSrc + lRplc - lPtrn + 1));
+ if (tszTail = (TCHAR *) malloc(sizeof(TCHAR) *
+ (lSrc - (tszFound - *src) - lPtrn + 1))) {
+ /* save tail */
+ _tcscpy(tszTail, tszFound + lPtrn);
+ /* write replacement string */
+ _tcscpy(tszFound, rplc);
+ /* write tail */
+ _tcscpy(tszFound + lRplc, tszTail);
+ free((void *) tszTail);
+ }
+ }
+ return *src;
+}
+
+/*
+ * replace pattern `ptrn' with the string `rplc' in string `src',
+ * `src' is supposed to be `n' character long (or no checking is done if n < 0).
+ * This function is useful for statically allocated buffers
+ */
+static TCHAR * _tcsnrplc(TCHAR *src, size_t n, const TCHAR *ptrn, const TCHAR *rplc)
+{
+ size_t lSrc, lPtrn, lRplc;
+ TCHAR *tszFound, *tszTail;
+
+ lSrc = lstrlen(src);
+ lPtrn = lstrlen(ptrn);
+ lRplc = lstrlen(rplc);
+ if (lPtrn && lSrc && lSrc >= lPtrn && /* lengths are ok */
+ (tszFound = _tcsstr(src, ptrn)) != NULL && /* pattern was found in string */
+ (n < 0 || lSrc - lPtrn + lRplc < n) && /* there is enough room in the string */
+ (tszTail = (TCHAR *) malloc(sizeof(TCHAR) *
+ (lSrc - (tszFound - src) - lPtrn + 1))) != NULL) {
+ /* save tail */
+ _tcscpy(tszTail, tszFound + lPtrn);
+ /* write replacement string */
+ _tcscpy(tszFound, rplc);
+ /* write tail */
+ _tcscpy(tszFound + lRplc, tszTail);
+ free((void *) tszTail);
+ }
+ return src;
+}
+
+static char *Log_SetStyle(int style, int fontindex)
+{
+ if (style < OPTIONS_FONTCOUNT)
+ return CHAT_rtffonts + (style * RTFCACHELINESIZE);
+
+ return "";
+}
+
+static void Log_Append(char **buffer, int *cbBufferEnd, int *cbBufferAlloced, const char *fmt, ...)
+{
+ va_list va;
+ int charsDone = 0;
+
+ va_start(va, fmt);
+ for (;;) {
+ charsDone = mir_vsnprintf(*buffer + *cbBufferEnd, *cbBufferAlloced - *cbBufferEnd, fmt, va);
+ if (charsDone >= 0)
+ break;
+ *cbBufferAlloced += 4096;
+ *buffer = (char *) mir_realloc(*buffer, *cbBufferAlloced);
+ }
+ va_end(va);
+ *cbBufferEnd += charsDone;
+}
+
+static int Log_AppendRTF(LOGSTREAMDATA* streamData, BOOL simpleMode, char **buffer, int *cbBufferEnd, int *cbBufferAlloced, const TCHAR *fmt, ...)
+{
+ va_list va;
+ int lineLen, textCharsCount = 0;
+ TCHAR* line = (TCHAR*)alloca(8001 * sizeof(TCHAR));
+ char* d;
+
+ va_start(va, fmt);
+ lineLen = _vsntprintf(line, 8000, fmt, va);
+ if (lineLen < 0) lineLen = 8000;
+ line[lineLen] = 0;
+ va_end(va);
+
+ lineLen = lineLen * 20 + 8;
+ if (*cbBufferEnd + lineLen > *cbBufferAlloced) {
+ cbBufferAlloced[0] += (lineLen + 1024 - lineLen % 1024);
+ if ((d = (char *) mir_realloc(*buffer, *cbBufferAlloced)) == 0)
+ return 0;
+ *buffer = d;
+ }
+
+ d = *buffer + *cbBufferEnd;
+
+ for (; *line; line++, textCharsCount++) {
+ if (*line == '\r' && line[1] == '\n') {
+ CopyMemory(d, "\\par ", 5);
+ line++;
+ d += 5;
+ } else if (*line == '\n') {
+ CopyMemory(d, "\\line ", 6);
+ d += 6;
+ } else if (*line == '%' && !simpleMode) {
+ char szTemp[200];
+
+ szTemp[0] = '\0';
+ switch (*++line) {
+ case '\0':
+ case '%':
+ *d++ = '%';
+ break;
+
+ case 'c':
+ case 'f':
+ if (g_Settings.StripFormat || streamData->bStripFormat)
+ line += 2;
+
+ else if (line[1] != '\0' && line[2] != '\0') {
+ TCHAR szTemp3[3], c = *line;
+ int col;
+ szTemp3[0] = line[1];
+ szTemp3[1] = line[2];
+ szTemp3[2] = '\0';
+ line += 2;
+
+ col = _ttoi(szTemp3);
+ col += (OPTIONS_FONTCOUNT + 1);
+ mir_snprintf(szTemp, SIZEOF(szTemp), (c == 'c') ? "\\cf%u " : "\\highlight%u ", col);
+ }
+ break;
+ case 'C':
+ case 'F':
+ if (!g_Settings.StripFormat && !streamData->bStripFormat) {
+ int j = streamData->lin->bIsHighlighted ? 16 : EventToIndex(streamData->lin);
+ if (*line == 'C')
+ mir_snprintf(szTemp, SIZEOF(szTemp), "\\cf%u ", j + 1);
+ else
+ mir_snprintf(szTemp, SIZEOF(szTemp), "\\highlight0 ");
+ }
+ break;
+ case 'b':
+ case 'u':
+ case 'i':
+ if (!streamData->bStripFormat)
+ mir_snprintf(szTemp, SIZEOF(szTemp), (*line == 'u') ? "\\%cl " : "\\%c ", *line);
+ break;
+
+ case 'B':
+ case 'U':
+ case 'I':
+ if (!streamData->bStripFormat) {
+ mir_snprintf(szTemp, SIZEOF(szTemp), (*line == 'U') ? "\\%cl0 " : "\\%c0 ", *line);
+ CharLowerA(szTemp);
+ }
+ break;
+
+ case 'r':
+ if (!streamData->bStripFormat) {
+ int index = EventToIndex(streamData->lin);
+ mir_snprintf(szTemp, SIZEOF(szTemp), "%s ", Log_SetStyle(index, index));
+ }
+ break;
+ }
+
+ if (szTemp[0]) {
+ int iLen = lstrlenA(szTemp);
+ memcpy(d, szTemp, iLen);
+ d += iLen;
+ }
+ } else if (*line == '\t' && !streamData->bStripFormat) {
+ CopyMemory(d, "\\tab ", 5);
+ d += 5;
+ } else if ((*line == '\\' || *line == '{' || *line == '}') && !streamData->bStripFormat) {
+ *d++ = '\\';
+ *d++ = (char) * line;
+ } else if (*line > 0 && *line < 128) {
+ *d++ = (char) * line;
+ }
+ else d += sprintf(d, "\\u%u ?", (WORD) * line);
+ }
+
+ *cbBufferEnd = (int)(d - *buffer);
+ return textCharsCount;
+}
+
+static void AddEventToBuffer(char **buffer, int *bufferEnd, int *bufferAlloced, LOGSTREAMDATA *streamData)
+{
+ TCHAR szTemp[512], szTemp2[512];
+ TCHAR* pszNick = NULL;
+
+ if (streamData == NULL)
+ return;
+
+ if (streamData->lin == NULL)
+ return;
+
+ if (streamData->lin->ptszNick) {
+ if (g_Settings.LogLimitNames && lstrlen(streamData->lin->ptszNick) > 20) {
+ lstrcpyn(szTemp, streamData->lin->ptszNick, 20);
+ lstrcpyn(szTemp + 20, _T("..."), 4);
+ } else lstrcpyn(szTemp, streamData->lin->ptszNick, 511);
+
+ if (g_Settings.ClickableNicks)
+ mir_sntprintf(szTemp2, SIZEOF(szTemp2), _T("~~++#%s#++~~"), szTemp);
+ else
+ _tcscpy(szTemp2, szTemp);
+
+ if (streamData->lin->ptszUserInfo && streamData->lin->iType != GC_EVENT_TOPIC)
+ mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s (%s)"), szTemp2, streamData->lin->ptszUserInfo);
+ else
+ mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s"), szTemp2);
+ pszNick = szTemp;
+ }
+
+ switch (streamData->lin->iType) {
+ case GC_EVENT_MESSAGE:
+ if (streamData->lin->ptszText)
+ Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), streamData->lin->ptszText);
+ break;
+ case GC_EVENT_ACTION:
+ if (streamData->lin->ptszNick && streamData->lin->ptszText) {
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, _T("%s "), streamData->lin->ptszNick);
+ Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), streamData->lin->ptszText);
+ }
+ break;
+ case GC_EVENT_JOIN:
+ if (pszNick) {
+ if (!streamData->lin->bIsMe)
+ /* replace nick of a newcomer with a link */
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, CTranslator::get(CTranslator::MUC_LOG_JOINED), pszNick);
+ else
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, CTranslator::get(CTranslator::MUC_LOG_ME_JOINED), streamData->si->ptszName);
+ }
+ break;
+ case GC_EVENT_PART:
+ if (pszNick)
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, CTranslator::get(CTranslator::MUC_LOG_LEFT), pszNick);
+ if (streamData->lin->ptszText)
+ Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T(": %s"), streamData->lin->ptszText);
+ break;
+ case GC_EVENT_QUIT:
+ if (pszNick)
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, CTranslator::get(CTranslator::MUC_LOG_DISC), pszNick);
+ if (streamData->lin->ptszText)
+ Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T(": %s"), streamData->lin->ptszText);
+ break;
+ case GC_EVENT_NICK:
+ if (pszNick && streamData->lin->ptszText) {
+ if (!streamData->lin->bIsMe)
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, CTranslator::get(CTranslator::MUC_LOG_NICKCHANGE), pszNick, streamData->lin->ptszText);
+ else
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, CTranslator::get(CTranslator::MUC_LOG_ME_NICKCHANGE), streamData->lin->ptszText);
+ }
+ break;
+ case GC_EVENT_KICK:
+ if (pszNick && streamData->lin->ptszStatus)
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced,
+ CTranslator::get(CTranslator::MUC_LOG_KICK), streamData->lin->ptszStatus, pszNick);
+
+ if (streamData->lin->ptszText)
+ Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T(": %s"), streamData->lin->ptszText);
+ break;
+ case GC_EVENT_NOTICE:
+ if (pszNick && streamData->lin->ptszText) {
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, CTranslator::get(CTranslator::MUC_LOG_NOTICE), pszNick);
+ Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), streamData->lin->ptszText);
+ }
+ break;
+ case GC_EVENT_TOPIC:
+ if (streamData->lin->ptszText)
+ Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, CTranslator::get(CTranslator::MUC_LOG_TOPICIS), streamData->lin->ptszText, _T("%r"));
+ if (pszNick)
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced,
+ (streamData->lin->ptszUserInfo) ? CTranslator::get(CTranslator::MUC_LOG_TOPICSETBYON) :
+ CTranslator::get(CTranslator::MUC_LOG_TOPICSETBY),
+ pszNick, streamData->lin->ptszUserInfo);
+ break;
+ case GC_EVENT_INFORMATION:
+ if (streamData->lin->ptszText)
+ Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, (streamData->lin->bIsMe) ? _T("--> %s") : _T("%s"), streamData->lin->ptszText);
+ break;
+ case GC_EVENT_ADDSTATUS:
+ if (pszNick && streamData->lin->ptszText && streamData->lin->ptszStatus)
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced,
+ CTranslator::get(CTranslator::MUC_LOG_STATUSENABLE),
+ streamData->lin->ptszText, streamData->lin->ptszStatus, pszNick);
+ break;
+ case GC_EVENT_REMOVESTATUS:
+ if (pszNick && streamData->lin->ptszText && streamData->lin->ptszStatus) {
+ Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced,
+ CTranslator::get(CTranslator::MUC_LOG_STATUSDISABLE),
+ streamData->lin->ptszText , streamData->lin->ptszStatus, pszNick);
+ }
+ break;
+ }
+}
+
+TCHAR* MakeTimeStamp(TCHAR* pszStamp, time_t time)
+{
+ static TCHAR szTime[30];
+ _tcsftime(szTime, 29, pszStamp, localtime(&time));
+ return szTime;
+}
+
+static char* Log_CreateRTF(LOGSTREAMDATA *streamData)
+{
+ char *buffer, *header;
+ int bufferAlloced, bufferEnd, i, me = 0;
+ LOGINFO * lin = streamData->lin;
+ MODULEINFO *mi = MM_FindModule(streamData->si->pszModule);
+
+ // guesstimate amount of memory for the RTF
+ bufferEnd = 0;
+ bufferAlloced = streamData->bRedraw ? 2048 * (streamData->si->iEventCount + 2) : 2048;
+ buffer = (char *) mir_alloc(bufferAlloced);
+ buffer[0] = '\0';
+
+ // ### RTF HEADER
+
+ if(0 == mi->pszHeader)
+ mi->pszHeader = Log_CreateRtfHeader(mi);
+
+ header = mi->pszHeader;
+ streamData->crCount = mi->nColorCount;
+
+ if (header)
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, header);
+
+
+ // ### RTF BODY (one iteration per event that should be streamed in)
+ while (lin) {
+ // filter
+ if (streamData->si->iType != GCW_CHATROOM || !streamData->si->bFilterEnabled || (streamData->si->iLogFilterFlags&lin->iType) != 0) {
+ if (lin->next != NULL)
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\par ");
+
+ if (streamData->dat->dwFlags & MWF_DIVIDERWANTED || lin->dwFlags & MWF_DIVIDERWANTED) {
+ static char szStyle_div[128] = "\0";
+ if (szStyle_div[0] == 0)
+ mir_snprintf(szStyle_div, 128, "\\f%u\\cf%u\\ul0\\b%d\\i%d\\fs%u", 17, 18, 0, 0, 5);
+
+ lin->dwFlags |= MWF_DIVIDERWANTED;
+ if (lin->prev || !streamData->bRedraw)
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\qc\\sl-1\\highlight%d %s ---------------------------------------------------------------------------------------\\par ", 18, szStyle_div);
+ streamData->dat->dwFlags &= ~MWF_DIVIDERWANTED;
+ }
+ // create new line, and set font and color
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\ql\\sl0%s ", Log_SetStyle(0, 0));
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\v~-+%d+-~\\v0 ", lin);
+
+ // Insert icon
+ if (g_Settings.LogSymbols) // use symbols
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s %c", Log_SetStyle(17, 17), EventToSymbol(lin));
+ else if (g_Settings.dwIconFlags) {
+ int iIndex = lin->bIsHighlighted ? ICON_HIGHLIGHT : EventToIcon(lin);
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\f0\\fs14");
+ while (bufferAlloced - bufferEnd < (logIconBmpSize[0] + 20))
+ bufferAlloced += 4096;
+ buffer = (char *) mir_realloc(buffer, bufferAlloced);
+ CopyMemory(buffer + bufferEnd, pLogIconBmpBits[iIndex], logIconBmpSize[iIndex]);
+ bufferEnd += logIconBmpSize[iIndex];
+ }
+
+ if (g_Settings.TimeStampEventColour) {
+ // colored timestamps
+ static char szStyle[256];
+ int iii;
+ if (lin->ptszNick && lin->iType == GC_EVENT_MESSAGE) {
+ iii = lin->bIsHighlighted ? 16 : (lin->bIsMe ? 2 : 1);
+ mir_snprintf(szStyle, SIZEOF(szStyle), "\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\ul%d\\fs%u", iii + 1, aFonts[0].lf.lfWeight >= FW_BOLD ? 1 : 0,aFonts[0].lf.lfItalic,aFonts[0].lf.lfUnderline, 2 * abs(aFonts[0].lf.lfHeight) * 74 / logPixelSY);
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s ", szStyle);
+ } else {
+ iii = lin->bIsHighlighted ? 16 : EventToIndex(lin);
+ mir_snprintf(szStyle, SIZEOF(szStyle), "\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\ul%d\\fs%u", iii + 1, aFonts[0].lf.lfWeight >= FW_BOLD ? 1 : 0, aFonts[0].lf.lfItalic,aFonts[0].lf.lfUnderline ,2 * abs(aFonts[0].lf.lfHeight) * 74 / logPixelSY);
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s ", szStyle);
+ }
+ } else
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s ", Log_SetStyle(0, 0));
+ // insert a TAB if necessary to put the timestamp in the right position
+ if (g_Settings.dwIconFlags)
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\tab ");
+
+ //insert timestamp
+ if (g_Settings.ShowTime) {
+ TCHAR szTimeStamp[30], szOldTimeStamp[30];
+
+ lstrcpyn(szTimeStamp, MakeTimeStamp(g_Settings.pszTimeStamp, lin->time), 30);
+ lstrcpyn(szOldTimeStamp, MakeTimeStamp(g_Settings.pszTimeStamp, streamData->si->LastTime), 30);
+ if (!g_Settings.ShowTimeIfChanged || streamData->si->LastTime == 0 || lstrcmp(szTimeStamp, szOldTimeStamp)) {
+ streamData->si->LastTime = lin->time;
+ Log_AppendRTF(streamData, TRUE, &buffer, &bufferEnd, &bufferAlloced, _T("%s"), szTimeStamp);
+ }
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\tab ");
+ }
+
+ // Insert the nick
+ if (lin->ptszNick && lin->iType == GC_EVENT_MESSAGE) {
+ TCHAR pszTemp[300], *p1;
+ STATUSINFO *ti;
+ char pszIndicator[3] = "\0\0";
+ int crNickIndex = 0;
+ //mad
+ if (g_Settings.LogClassicIndicators/*g_Settings.ClassicIndicators */||g_Settings.ColorizeNicksInLog) {
+ USERINFO *ui = streamData->si->pUsers;
+ while (ui) {
+ if (!lstrcmp(ui->pszNick, lin->ptszNick)) {
+ ti = TM_FindStatus(streamData->si->pStatuses, TM_WordToString(streamData->si->pStatuses, ui->Status));
+ if (ti && (int)ti->hIcon < streamData->si->iStatusCount) {
+ int id = streamData->si->iStatusCount - (int)ti->hIcon - 1;
+ switch (id) {
+ case 1:
+ pszIndicator[0] = '+';
+ crNickIndex = 2;
+ break;
+ case 2:
+ pszIndicator[0] = '%';
+ crNickIndex = 1;
+ break;
+ case 3:
+ pszIndicator[0] = '@';
+ crNickIndex = 0;
+ break;
+ case 4:
+ pszIndicator[0] = '!';
+ crNickIndex = 3;
+ break;
+ case 5:
+ pszIndicator[0] = '*';
+ crNickIndex = 4;
+ break;
+ default:
+ pszIndicator[0] = 0;
+ }
+ }
+ break;
+ }
+ ui = ui->next;
+ }
+ }
+
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s ", Log_SetStyle(lin->bIsMe ? 2 : 1, lin->bIsMe ? 2 : 1));
+ //MAD
+ if (g_Settings.LogClassicIndicators /*g_Settings.ClassicIndicators*/)
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s", pszIndicator);
+
+ lstrcpyn(pszTemp, lin->bIsMe ? g_Settings.pszOutgoingNick : g_Settings.pszIncomingNick, 299);
+ p1 = _tcsstr(pszTemp, _T("%n"));
+ if (p1)
+ p1[1] = 's';
+
+ if (!lin->bIsMe) {
+ if (g_Settings.ClickableNicks) {
+ _tcsnrplc(pszTemp, 300, _T("%s"), _T("~~++#%s#++~~"));
+ pszTemp[299] = 0;
+ }
+ //Log_Append(&buffer, &bufferEnd, &bufferAlloced, "~~++#");
+ if (g_Settings.ColorizeNicksInLog && pszIndicator[0])
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\cf%u ", OPTIONS_FONTCOUNT + streamData->crCount + crNickIndex + 1);
+ }
+
+ Log_AppendRTF(streamData, TRUE, &buffer, &bufferEnd, &bufferAlloced, pszTemp, lin->ptszNick);
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, " ");
+ }
+
+ // Insert the message
+ {
+ i = lin->bIsHighlighted ? 16 : EventToIndex(lin);
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s ", Log_SetStyle(i, i));
+ streamData->lin = lin;
+ AddEventToBuffer(&buffer, &bufferEnd, &bufferAlloced, streamData);
+ }
+ }
+ lin = lin->prev;
+ }
+
+ // ### RTF END
+ if (streamData->bRedraw)
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\par}");
+ else
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "}");
+ return buffer;
+}
+
+static DWORD CALLBACK Log_StreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb)
+{
+ LOGSTREAMDATA *lstrdat = (LOGSTREAMDATA *) dwCookie;
+
+ if (lstrdat) {
+ // create the RTF
+ if (lstrdat->buffer == NULL) {
+ lstrdat->bufferOffset = 0;
+ lstrdat->buffer = Log_CreateRTF(lstrdat);
+ lstrdat->bufferLen = lstrlenA(lstrdat->buffer);
+ }
+
+ // give the RTF to the RE control
+ *pcb = min(cb, lstrdat->bufferLen - lstrdat->bufferOffset);
+ CopyMemory(pbBuff, lstrdat->buffer + lstrdat->bufferOffset, *pcb);
+ lstrdat->bufferOffset += *pcb;
+
+ // free stuff if the streaming operation is complete
+ if (lstrdat->bufferOffset == lstrdat->bufferLen) {
+ mir_free(lstrdat->buffer);
+ lstrdat->buffer = NULL;
+ }
+ }
+
+ return 0;
+}
+
+void Log_StreamInEvent(HWND hwndDlg, LOGINFO* lin, SESSION_INFO* si, BOOL bRedraw, BOOL bPhaseTwo)
+{
+ EDITSTREAM stream;
+ LOGSTREAMDATA streamData;
+ CHARRANGE oldsel, sel, newsel;
+ POINT point = {0};
+ SCROLLINFO scroll;
+ WPARAM wp;
+ HWND hwndRich;
+ TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ if (hwndDlg == 0 || lin == 0 || si == 0 || dat == 0)
+ return;
+
+ hwndRich = GetDlgItem(hwndDlg, IDC_CHAT_LOG);
+ ZeroMemory(&streamData, sizeof(LOGSTREAMDATA));
+ streamData.hwnd = hwndRich;
+ streamData.si = si;
+ streamData.lin = lin;
+ streamData.bStripFormat = FALSE;
+ streamData.dat = dat;
+
+ // bPhaseTwo = bRedraw && bPhaseTwo;
+
+ if (bRedraw || si->iType != GCW_CHATROOM || !si->bFilterEnabled || (si->iLogFilterFlags&lin->iType) != 0) {
+ BOOL bFlag = FALSE, fDoReplace;
+
+ ZeroMemory(&stream, sizeof(stream));
+ stream.pfnCallback = Log_StreamCallback;
+ stream.dwCookie = (DWORD_PTR) & streamData;
+ scroll.cbSize = sizeof(SCROLLINFO);
+ scroll.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
+ GetScrollInfo(GetDlgItem(hwndDlg, IDC_CHAT_LOG), SB_VERT, &scroll);
+ SendMessage(hwndRich, EM_GETSCROLLPOS, 0, (LPARAM) &point);
+
+ // do not scroll to bottom if there is a selection
+ SendMessage(hwndRich, EM_EXGETSEL, 0, (LPARAM) &oldsel);
+ if (oldsel.cpMax != oldsel.cpMin)
+ SendMessage(hwndRich, WM_SETREDRAW, FALSE, 0);
+
+ //set the insertion point at the bottom
+ sel.cpMin = sel.cpMax = GetRichTextLength(hwndRich);
+ SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) & sel);
+
+ // fix for the indent... must be a M$ bug
+ if (sel.cpMax == 0)
+ bRedraw = TRUE;
+
+ // should the event(s) be appended to the current log
+ wp = bRedraw ? SF_RTF : SFF_SELECTION | SF_RTF;
+
+ //get the number of pixels per logical inch
+ if (bRedraw) {
+ HDC hdc;
+ hdc = GetDC(NULL);
+ logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
+ logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX);
+ ReleaseDC(NULL, hdc);
+ SendMessage(hwndRich, WM_SETREDRAW, FALSE, 0);
+ bFlag = TRUE;
+ // SetCursor(LoadCursor(NULL, IDC_ARROW));
+ }
+
+ // stream in the event(s)
+ streamData.lin = lin;
+ streamData.bRedraw = bRedraw;
+ SendMessage(hwndRich, EM_STREAMIN, wp, (LPARAM) & stream);
+
+
+ //SendMessage(hwndRich, EM_EXGETSEL, (WPARAM)0, (LPARAM)&newsel);
+ /*
+ * for new added events, only replace in message or action events.
+ * no need to replace smileys or math formulas elsewhere
+ */
+
+ fDoReplace = (bRedraw || (lin->ptszText
+ && (lin->iType == GC_EVENT_MESSAGE || lin->iType == GC_EVENT_ACTION)));
+
+
+ /*
+ * use mathmod to replace formulas
+ */
+ if (g_Settings.MathMod && fDoReplace) {
+ TMathRicheditInfo mathReplaceInfo;
+ CHARRANGE mathNewSel;
+ mathNewSel.cpMin = sel.cpMin;
+
+ if (mathNewSel.cpMin < 0)
+ mathNewSel.cpMin = 0;
+
+ mathNewSel.cpMax = -1;
+
+ mathReplaceInfo.hwndRichEditControl = hwndRich;
+
+ if (!bRedraw)
+ mathReplaceInfo.sel = &mathNewSel;
+ else
+ mathReplaceInfo.sel = 0;
+
+ mathReplaceInfo.disableredraw = TRUE;
+ CallService(MATH_RTF_REPLACE_FORMULAE, 0, (LPARAM)&mathReplaceInfo);
+ bFlag = TRUE;
+ }
+
+ /*
+ * replace marked nicknames with hyperlinks to make the nicks
+ * clickable
+ */
+
+ if (g_Settings.ClickableNicks) {
+ CHARFORMAT2 cf2;
+ FINDTEXTEX fi, fi2;
+
+ ZeroMemory(&cf2, sizeof(CHARFORMAT2));
+ fi2.lpstrText = _T("#++~~");
+ fi.chrg.cpMin = bRedraw ? 0 : sel.cpMin;
+ fi.chrg.cpMax = -1;
+ fi.lpstrText = _T("~~++#");
+ cf2.cbSize = sizeof(cf2);
+
+ while (SendMessage(hwndRich, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) > -1) {
+ fi2.chrg.cpMin = fi.chrgText.cpMin;
+ fi2.chrg.cpMax = -1;
+
+ if (SendMessage(hwndRich, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi2) > -1) {
+
+ SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&fi.chrgText);
+ SendMessage(hwndRich, EM_REPLACESEL, TRUE, (LPARAM)_T(""));
+ fi2.chrgText.cpMin -= fi.chrgText.cpMax - fi.chrgText.cpMin;
+ fi2.chrgText.cpMax -= fi.chrgText.cpMax - fi.chrgText.cpMin;
+ SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&fi2.chrgText);
+ SendMessage(hwndRich, EM_REPLACESEL, TRUE, (LPARAM)_T(""));
+ fi2.chrgText.cpMax = fi2.chrgText.cpMin;
+
+ fi2.chrgText.cpMin = fi.chrgText.cpMin;
+ SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&fi2.chrgText);
+ cf2.dwMask = CFM_PROTECTED;
+ cf2.dwEffects = CFE_PROTECTED;
+ SendMessage(hwndRich, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
+ }
+ fi.chrg.cpMin = fi.chrgText.cpMax;
+ }
+ SendMessage(hwndRich, EM_SETSEL, -1, -1);
+ }
+
+
+ /*
+ * run smileyadd
+ */
+ if (PluginConfig.g_SmileyAddAvail && fDoReplace) {
+ SMADD_RICHEDIT3 sm = {0};
+
+ newsel.cpMax = -1;
+ newsel.cpMin = sel.cpMin;
+ if (newsel.cpMin < 0)
+ newsel.cpMin = 0;
+ ZeroMemory(&sm, sizeof(sm));
+ sm.cbSize = sizeof(sm);
+ sm.hwndRichEditControl = hwndRich;
+ sm.Protocolname = si->pszModule;
+ sm.rangeToReplace = bRedraw ? NULL : &newsel;
+ sm.disableRedraw = TRUE;
+ sm.hContact = si->hContact;
+ CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm);
+ }
+
+ /*
+ * trim the message log to the number of most recent events
+ * this uses hidden marks in the rich text to find the events which should be deleted
+ */
+
+
+ if (si->wasTrimmed) {
+ TCHAR szPattern[50];
+ FINDTEXTEX fi;
+
+ mir_sntprintf(szPattern, SIZEOF(szPattern), _T("~-+%d+-~"), si->pLogEnd);
+ fi.lpstrText = szPattern;
+ fi.chrg.cpMin = 0;
+ fi.chrg.cpMax = -1;
+ if (SendMessage(hwndRich, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) != 0) {
+ CHARRANGE sel;
+ sel.cpMin = 0;
+ sel.cpMax = 20;
+ SendMessage(hwndRich, EM_SETSEL, 0, fi.chrgText.cpMax + 1);
+ SendMessage(hwndRich, EM_REPLACESEL, TRUE, (LPARAM)_T(""));
+ }
+ si->wasTrimmed = FALSE;
+ }
+
+ // scroll log to bottom if the log was previously scrolled to bottom, else restore old position
+ if ((bRedraw || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50))
+ SendMessage(GetParent(hwndRich), GC_SCROLLTOBOTTOM, 0, 0);
+ else
+ SendMessage(hwndRich, EM_SETSCROLLPOS, 0, (LPARAM) &point);
+
+ // do we need to restore the selection
+ if (oldsel.cpMax != oldsel.cpMin) {
+ SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) & oldsel);
+ SendMessage(hwndRich, WM_SETREDRAW, TRUE, 0);
+ InvalidateRect(hwndRich, NULL, TRUE);
+ }
+
+ // need to invalidate the window
+ if (bFlag) {
+ sel.cpMin = sel.cpMax = GetRichTextLength(hwndRich);
+ SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) & sel);
+ SendMessage(hwndRich, WM_SETREDRAW, TRUE, 0);
+ InvalidateRect(hwndRich, NULL, TRUE);
+ }
+ }
+}
+
+char * Log_CreateRtfHeader(MODULEINFO * mi)
+{
+ char *buffer;
+ int bufferAlloced, bufferEnd, i = 0;
+
+ // guesstimate amount of memory for the RTF header
+ bufferEnd = 0;
+ bufferAlloced = 4096;
+ buffer = (char *) mir_realloc(mi->pszHeader, bufferAlloced);
+ buffer[0] = '\0';
+
+
+ //get the number of pixels per logical inch
+ if (logPixelSY == 0) {
+ HDC hdc;
+ hdc = GetDC(NULL);
+ logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
+ logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX);
+ ReleaseDC(NULL, hdc);
+ }
+
+ // ### RTF HEADER
+
+ // font table
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "{\\rtf1\\ansi\\deff0{\\fonttbl");
+ for (i = 0; i < OPTIONS_FONTCOUNT ; i++)
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "{\\f%u\\fnil\\fcharset%u" TCHAR_STR_PARAM ";}", i, aFonts[i].lf.lfCharSet, aFonts[i].lf.lfFaceName);
+
+ // colour table
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "}{\\colortbl ;");
+
+ for (i = 0; i < OPTIONS_FONTCOUNT; i++)
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(aFonts[i].color), GetGValue(aFonts[i].color), GetBValue(aFonts[i].color));
+
+ for (i = 0; i < mi->nColorCount; i++)
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(mi->crColors[i]), GetGValue(mi->crColors[i]), GetBValue(mi->crColors[i]));
+
+ for (i = 0; i < 5; i++)
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(g_Settings.nickColors[i]), GetGValue(g_Settings.nickColors[i]), GetBValue(g_Settings.nickColors[i]));
+
+ // new paragraph
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "}\\pard\\sl%d", 1000);
+
+ // set tabs and indents
+ {
+ int iIndent = 0;
+
+ if (g_Settings.LogSymbols) {
+ TCHAR szString[2];
+ LOGFONT lf;
+ HFONT hFont;
+ int iText;
+
+ szString[1] = 0;
+ szString[0] = 0x28;
+ LoadMsgDlgFont(FONTSECTION_CHAT, 17, &lf, NULL, CHAT_FONTMODULE);
+ hFont = CreateFontIndirect(&lf);
+ iText = GetTextPixelSize(szString, hFont, TRUE) + 3;
+ DeleteObject(hFont);
+ iIndent += (iText * 1440) / logPixelSX;
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\tx%u", iIndent);
+ } else if (g_Settings.dwIconFlags) {
+ iIndent += ((g_Settings.ScaleIcons ? 14 : 20) * 1440) / logPixelSX;
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\tx%u", iIndent);
+ }
+ if (g_Settings.ShowTime) {
+ int iSize = (g_Settings.LogTextIndent * 1440) / logPixelSX;
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\tx%u", iIndent + iSize);
+ if (g_Settings.LogIndentEnabled)
+ iIndent += iSize;
+ }
+ Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\fi-%u\\li%u", iIndent, iIndent);
+ }
+ return buffer;
+}
+
+#define RTFPICTHEADERMAXSIZE 78
+void LoadMsgLogBitmaps(void)
+{
+ HICON hIcon;
+ HBITMAP hBmp, hoBmp;
+ HDC hdc, hdcMem;
+ BITMAPINFOHEADER bih = { 0 };
+ int widthBytes, i;
+ RECT rc;
+ HBRUSH hBkgBrush;
+ int rtfHeaderSize;
+ PBYTE pBmpBits;
+ int iIconSize;
+ int sizeX = 0, sizeY = 0;
+
+ if (hIcons[0])
+ Utils::getIconSize(hIcons[0], sizeX, sizeY);
+ else
+ sizeX = 16;
+
+ if (sizeX >= 12)
+ iIconSize = g_Settings.ScaleIcons ? 12 : 16;
+ else
+ iIconSize = sizeX;
+
+ hBkgBrush = CreateSolidBrush(M->GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR_MUC, SRMSGDEFSET_BKGCOLOUR));
+ bih.biSize = sizeof(bih);
+ bih.biBitCount = 24;
+ bih.biCompression = BI_RGB;
+ bih.biHeight = iIconSize;
+ bih.biPlanes = 1;
+ bih.biWidth = iIconSize;
+ widthBytes = ((bih.biWidth * bih.biBitCount + 31) >> 5) * 4;
+ rc.top = rc.left = 0;
+ rc.right = iIconSize;
+ rc.bottom = iIconSize;
+ hdc = GetDC(NULL);
+ hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight);
+ hdcMem = CreateCompatibleDC(hdc);
+ pBmpBits = (PBYTE) mir_alloc(widthBytes * bih.biHeight);
+ for (i = 0; i < SIZEOF(pLogIconBmpBits); i++) {
+ hIcon = hIcons[i];
+ pLogIconBmpBits[i] = (PBYTE) mir_alloc(RTFPICTHEADERMAXSIZE + (bih.biSize + widthBytes * bih.biHeight) * 2);
+ rtfHeaderSize = sprintf((char *)pLogIconBmpBits[i], "{\\pict\\dibitmap0\\wbmbitspixel%u\\wbmplanes1\\wbmwidthbytes%u\\picw%u\\pich%u ", bih.biBitCount, widthBytes, bih.biWidth, bih.biHeight);
+ hoBmp = (HBITMAP) SelectObject(hdcMem, hBmp);
+ FillRect(hdcMem, &rc, hBkgBrush);
+ DrawIconEx(hdcMem, 0, 1, hIcon, iIconSize, iIconSize, 0, NULL, DI_NORMAL);
+
+ SelectObject(hdcMem, hoBmp);
+ GetDIBits(hdc, hBmp, 0, bih.biHeight, pBmpBits, (BITMAPINFO *) & bih, DIB_RGB_COLORS);
+ {
+ int n;
+ for (n = 0; n < sizeof(BITMAPINFOHEADER); n++)
+ sprintf((char *)pLogIconBmpBits[i] + rtfHeaderSize + n * 2, "%02X", ((PBYTE) & bih)[n]);
+ for (n = 0; n < widthBytes * bih.biHeight; n += 4)
+ sprintf((char *)pLogIconBmpBits[i] + rtfHeaderSize + (bih.biSize + n) * 2, "%02X%02X%02X%02X", pBmpBits[n], pBmpBits[n + 1], pBmpBits[n + 2], pBmpBits[n + 3]);
+ }
+ logIconBmpSize[i] = rtfHeaderSize + (bih.biSize + widthBytes * bih.biHeight) * 2 + 1;
+ pLogIconBmpBits[i][logIconBmpSize[i] - 1] = '}';
+ }
+ mir_free(pBmpBits);
+ DeleteDC(hdcMem);
+ DeleteObject(hBmp);
+ ReleaseDC(NULL, hdc);
+ DeleteObject(hBkgBrush);
+
+ /* cache RTF font headers */
+
+ //get the number of pixels per logical inch
+ if (logPixelSY == 0) {
+ HDC hdc;
+ hdc = GetDC(NULL);
+ logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
+ logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX);
+ ReleaseDC(NULL, hdc);
+ }
+
+ for (i = 0; i < OPTIONS_FONTCOUNT; i++)
+ mir_snprintf(CHAT_rtfFontsGlobal[i], RTFCACHELINESIZE, "\\f%u\\cf%u\\ul0\\highlight0\\b%d\\i%d\\ul%d\\fs%u", i, i + 1, aFonts[i].lf.lfWeight >= FW_BOLD ? 1 : 0, aFonts[i].lf.lfItalic,aFonts[i].lf.lfUnderline ,2 * abs(aFonts[i].lf.lfHeight) * 74 / logPixelSY);
+ CHAT_rtffonts = &(CHAT_rtfFontsGlobal[0][0]);
+}
+
+void FreeMsgLogBitmaps(void)
+{
+ int i;
+ for (i = 0; i < SIZEOF(pLogIconBmpBits); i++)
+ mir_free(pLogIconBmpBits[i]);
+}
diff --git a/plugins/TabSRMM/chat/main.cpp b/plugins/TabSRMM/chat/main.cpp
new file mode 100644
index 0000000000..45b0717f29
--- /dev/null
+++ b/plugins/TabSRMM/chat/main.cpp
@@ -0,0 +1,142 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * This code is based on and still contains large parts of the the
+ * original chat module for Miranda IM, written and copyrighted
+ * by Joergen Persson in 2005.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: main.cpp 13132 2010-11-17 03:47:44Z silvercircle $
+ *
+ * chat module exports and functions to load/unload the plugin.
+ *
+ */
+
+#include "../src/commonheaders.h"
+
+HANDLE g_hWindowList;
+HMENU g_hMenu = NULL;
+
+FONTINFO aFonts[OPTIONS_FONTCOUNT];
+HICON hIcons[30];
+HBRUSH hListBkgBrush = NULL;
+
+TMUCSettings g_Settings;
+
+TCHAR *pszActiveWndID = 0;
+char *pszActiveWndModule = 0;
+
+/*
+ * load the group chat module
+ */
+
+int Chat_Load(PLUGINLINK *link)
+{
+ if(M->GetByte("forceDisableMUC", 0)) {
+ PluginConfig.m_chat_enabled = false;
+ return(0);
+ }
+ g_hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENU));
+ if(CreateServiceFunctions()) {
+ HookEvents();
+ CreateHookableEvents();
+ OptionsInit();
+ }
+ return 0;
+}
+
+/*
+ * unload the module. final cleanup
+ */
+
+int Chat_Unload(void)
+{
+ if (!PluginConfig.m_chat_enabled)
+ return 0;
+
+ DBWriteContactSettingWord(NULL, "Chat", "SplitterX", (WORD)g_Settings.iSplitterX);
+ DBWriteContactSettingWord(NULL, "Chat", "splitY", (WORD)g_Settings.iSplitterY);
+
+ CList_SetAllOffline(TRUE, NULL);
+
+ mir_free(pszActiveWndID);
+ mir_free(pszActiveWndModule);
+
+ DestroyMenu(g_hMenu);
+ DestroyServiceFunctions();
+ DestroyHookableEvents();
+ FreeIcons();
+ OptionsUnInit();
+ UnhookEvents();
+ return 0;
+}
+
+void LoadLogIcons(void)
+{
+ ZeroMemory(hIcons, sizeof(HICON) * (ICON_STATUS5 - ICON_ACTION));
+ hIcons[ICON_ACTION] = LoadIconEx(IDI_ACTION, "log_action", 16, 16);
+ hIcons[ICON_ADDSTATUS] = LoadIconEx(IDI_ADDSTATUS, "log_addstatus", 16, 16);
+ hIcons[ICON_HIGHLIGHT] = LoadIconEx(IDI_HIGHLIGHT, "log_highlight", 16, 16);
+ hIcons[ICON_INFO] = LoadIconEx(IDI_INFO, "log_info", 16, 16);
+ hIcons[ICON_JOIN] = LoadIconEx(IDI_JOIN, "log_join", 16, 16);
+ hIcons[ICON_KICK] = LoadIconEx(IDI_KICK, "log_kick", 16, 16);
+ hIcons[ICON_MESSAGE] = LoadIconEx(IDI_MESSAGE, "log_message_in", 16, 16);
+ hIcons[ICON_MESSAGEOUT] = LoadIconEx(IDI_MESSAGEOUT, "log_message_out", 16, 16);
+ hIcons[ICON_NICK] = LoadIconEx(IDI_NICK, "log_nick", 16, 16);
+ hIcons[ICON_NOTICE] = LoadIconEx(IDI_NOTICE, "log_notice", 16, 16);
+ hIcons[ICON_PART] = LoadIconEx(IDI_PART, "log_part", 16, 16);
+ hIcons[ICON_QUIT] = LoadIconEx(IDI_QUIT, "log_quit", 16, 16);
+ hIcons[ICON_REMSTATUS] = LoadIconEx(IDI_REMSTATUS, "log_removestatus", 16, 16);
+ hIcons[ICON_TOPIC] = LoadIconEx(IDI_TOPIC, "log_topic", 16, 16);
+ hIcons[ICON_STATUS1] = LoadIconEx(IDI_STATUS1, "status1", 16, 16);
+ hIcons[ICON_STATUS2] = LoadIconEx(IDI_STATUS2, "status2", 16, 16);
+ hIcons[ICON_STATUS3] = LoadIconEx(IDI_STATUS3, "status3", 16, 16);
+ hIcons[ICON_STATUS4] = LoadIconEx(IDI_STATUS4, "status4", 16, 16);
+ hIcons[ICON_STATUS0] = LoadIconEx(IDI_STATUS0, "status0", 16, 16);
+ hIcons[ICON_STATUS5] = LoadIconEx(IDI_STATUS5, "status5", 16, 16);
+
+ return;
+}
+
+void LoadIcons(void)
+{
+ int i;
+
+ for (i = 0; i < 20; i++)
+ hIcons[i] = NULL;
+
+ LoadLogIcons();
+ g_Settings.hIconOverlay = LoadIconEx(IDI_OVERLAY, "overlay", 16, 16);
+ LoadMsgLogBitmaps();
+ return ;
+}
+
+void FreeIcons(void)
+{
+ FreeMsgLogBitmaps();
+ return;
+}
diff --git a/plugins/TabSRMM/chat/manager.cpp b/plugins/TabSRMM/chat/manager.cpp
new file mode 100644
index 0000000000..8a1e404ea5
--- /dev/null
+++ b/plugins/TabSRMM/chat/manager.cpp
@@ -0,0 +1,1541 @@
+/*
+astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ --pad=oper --one-line=keep-blocks --unpad=paren
+
+Chat module plugin for Miranda IM
+
+Copyright (C) 2003 Jörgen Persson
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+$Id: manager.cpp 14208 2012-03-26 13:56:42Z silvercircle $
+*/
+
+#include "../src/commonheaders.h"
+
+extern TCHAR *pszActiveWndID ;
+extern char *pszActiveWndModule ;
+extern HICON hIcons[30];
+
+#define WINDOWS_COMMANDS_MAX 30
+#define STATUSICONCOUNT 6
+
+SESSION_INFO *m_WndList = 0;
+MODULEINFO *m_ModList = 0;
+
+extern CRITICAL_SECTION cs;
+
+void SetActiveSession(const TCHAR* pszID, const char* pszModule)
+{
+ SESSION_INFO* si = SM_FindSession(pszID, pszModule);
+ if (si)
+ SetActiveSessionEx(si);
+}
+
+void SetActiveSessionEx(SESSION_INFO* si)
+{
+ if (si) {
+ replaceStr(&pszActiveWndID, si->ptszID);
+ replaceStrA(&pszActiveWndModule, si->pszModule);
+ }
+}
+
+SESSION_INFO* GetActiveSession(void)
+{
+ SESSION_INFO* si = SM_FindSession(pszActiveWndID, pszActiveWndModule);
+ if (si)
+ return si;
+
+ return m_WndList;
+}
+
+//---------------------------------------------------
+// Session Manager functions
+//
+// Keeps track of all sessions and its windows
+//---------------------------------------------------
+
+SESSION_INFO* SM_AddSession(const TCHAR* pszID, const char* pszModule)
+{
+ if (!pszID || !pszModule)
+ return NULL;
+
+ if (!SM_FindSession(pszID, pszModule)) {
+ SESSION_INFO*node = (SESSION_INFO*) mir_alloc(sizeof(SESSION_INFO));
+ ZeroMemory(node, sizeof(SESSION_INFO));
+ node->ptszID = mir_tstrdup(pszID);
+ node->pszModule = mir_strdup(pszModule);
+
+ MODULEINFO *mi = MM_FindModule(pszModule);
+
+ if(mi) {
+ mi->idleTimeStamp = time(0);
+ SM_BroadcastMessage(pszModule, GC_UPDATESTATUSBAR, 0, 1, TRUE);
+ }
+
+ if (m_WndList == NULL) { // list is empty
+ m_WndList = node;
+ node->next = NULL;
+ } else {
+ node->next = m_WndList;
+ m_WndList = node;
+ }
+ node->Highlight = g_Settings.Highlight;
+ return node;
+ }
+ return NULL;
+}
+
+int SM_RemoveSession(const TCHAR* pszID, const char* pszModule)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszModule)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if ((!pszID && pTemp->iType != GCW_SERVER || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { // match
+ COMMAND_INFO *pCurComm;
+ DWORD dw = pTemp->dwItemData;
+
+ if (pTemp->hWnd)
+ SendMessage(pTemp->hWnd, GC_EVENT_CONTROL + WM_USER + 500, SESSION_TERMINATE, 0);
+
+ DoEventHook(pTemp->ptszID, pTemp->pszModule, GC_SESSION_TERMINATE, NULL, NULL, (DWORD)pTemp->dwItemData);
+
+ if (pLast == NULL)
+ m_WndList = pTemp->next;
+ else
+ pLast->next = pTemp->next;
+
+ UM_RemoveAll(&pTemp->pUsers);
+ TM_RemoveAll(&pTemp->pStatuses);
+ LM_RemoveAll(&pTemp->pLog, &pTemp->pLogEnd);
+ pTemp->iStatusCount = 0;
+ pTemp->nUsersInNicklist = 0;
+
+ if (pTemp->hContact) {
+ CList_SetOffline(pTemp->hContact, pTemp->iType == GCW_CHATROOM ? TRUE : FALSE);
+ //if (pTemp->iType != GCW_SERVER)
+ //DBWriteContactSettingByte(pTemp->hContact, "CList", "Hidden", 1);
+ }
+ DBWriteContactSettingString(pTemp->hContact, pTemp->pszModule , "Topic", "");
+ DBWriteContactSettingString(pTemp->hContact, pTemp->pszModule, "StatusBar", "");
+ DBDeleteContactSetting(pTemp->hContact, "CList", "StatusMsg");
+
+ mir_free(pTemp->pszModule);
+ mir_free(pTemp->ptszID);
+ mir_free(pTemp->ptszName);
+ mir_free(pTemp->ptszStatusbarText);
+ mir_free(pTemp->ptszTopic);
+ mir_free(pTemp->pszID);
+ mir_free(pTemp->pszName);
+
+ // delete commands
+ pCurComm = pTemp->lpCommands;
+ while (pCurComm != NULL) {
+ COMMAND_INFO *pNext = pCurComm->next;
+ mir_free(pCurComm->lpCommand);
+ mir_free(pCurComm);
+ pCurComm = pNext;
+ }
+
+ mir_free(pTemp);
+ if (pszID)
+ return (int)dw;
+ if (pLast)
+ pTemp = pLast->next;
+ else
+ pTemp = m_WndList;
+ } else {
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ }
+ return FALSE;
+}
+
+SESSION_INFO* SM_FindSession(const TCHAR* pszID, const char* pszModule)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszID || !pszModule)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule))
+ return pTemp;
+
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return NULL;
+}
+
+BOOL SM_SetOffline(const TCHAR* pszID, const char* pszModule)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszModule)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ UM_RemoveAll(&pTemp->pUsers);
+ pTemp->nUsersInNicklist = 0;
+ if (pTemp->iType != GCW_SERVER)
+ pTemp->bInitDone = FALSE;
+
+ if (pszID)
+ return TRUE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return TRUE;
+}
+
+BOOL SM_SetStatusEx(const TCHAR* pszID, const char* pszModule, const TCHAR* pszText, int flags)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszModule)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ UM_SetStatusEx(pTemp->pUsers, pszText, flags);
+ if (pTemp->hWnd)
+ RedrawWindow(GetDlgItem(pTemp->hWnd, IDC_LIST), NULL, NULL, RDW_INVALIDATE);
+ if (pszID)
+ return TRUE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return TRUE;
+}
+
+HICON SM_GetStatusIcon(SESSION_INFO* si, USERINFO* ui, char *szIndicator)
+{
+ STATUSINFO * ti;
+ if (!ui || !si)
+ return NULL;
+
+ *szIndicator = 0;
+
+ ti = TM_FindStatus(si->pStatuses, TM_WordToString(si->pStatuses, ui->Status));
+ if (ti) {
+ if ((INT_PTR)ti->hIcon < STATUSICONCOUNT) {
+ int id = si->iStatusCount - (int)ti->hIcon - 1;
+ if (id == 0) {
+ *szIndicator = 0;
+ return hIcons[ICON_STATUS0];
+ }
+ if (id == 1) {
+ *szIndicator = '+';
+ return hIcons[ICON_STATUS1];
+ }
+ if (id == 2) {
+ *szIndicator = '%';
+ return hIcons[ICON_STATUS2];
+ }
+ if (id == 3) {
+ *szIndicator = '@';
+ return hIcons[ICON_STATUS3];
+ }
+ if (id == 4) {
+ *szIndicator = '!';
+ return hIcons[ICON_STATUS4];
+ }
+ if (id == 5) {
+ *szIndicator = '*';
+ return hIcons[ICON_STATUS5];
+ }
+ } else
+ return ti->hIcon;
+ }
+ return hIcons[ICON_STATUS0];
+}
+
+BOOL SM_AddEventToAllMatchingUID(GCEVENT * gce, BOOL bIsHighLight)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+ int bManyFix = 0;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpiA(pTemp->pszModule, gce->pDest->pszModule)) {
+ if (UM_FindUser(pTemp->pUsers, gce->ptszUID)) {
+ if (pTemp->bInitDone) {
+ if (SM_AddEvent(pTemp->ptszID, pTemp->pszModule, gce, FALSE) && pTemp->hWnd && pTemp->bInitDone) {
+ SendMessage(pTemp->hWnd, GC_ADDLOG, 0, 0);
+ } else if (pTemp->hWnd && pTemp->bInitDone) {
+ SendMessage(pTemp->hWnd, GC_REDRAWLOG2, 0, 0);
+ }
+ DoSoundsFlashPopupTrayStuff(pTemp, gce, bIsHighLight, bManyFix);
+ bManyFix ++;
+ if ((gce->dwFlags & GCEF_ADDTOLOG) && g_Settings.LoggingEnabled)
+ LogToFile(pTemp, gce);
+ }
+ }
+ }
+
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+
+ return 0;
+}
+
+BOOL SM_AddEvent(const TCHAR* pszID, const char* pszModule, GCEVENT * gce, BOOL bIsHighlighted)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszID || !pszModule)
+ return TRUE;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ LOGINFO * li = LM_AddEvent(&pTemp->pLog, &pTemp->pLogEnd);
+ pTemp->iEventCount += 1;
+
+ li->iType = gce->pDest->iType;
+ li->ptszNick = mir_tstrdup(gce->ptszNick);
+ li->ptszText = mir_tstrdup(gce->ptszText);
+ li->ptszStatus = mir_tstrdup(gce->ptszStatus);
+ li->ptszUserInfo = mir_tstrdup(gce->ptszUserInfo);
+
+ li->bIsMe = gce->bIsMe;
+ li->time = gce->time;
+ li->bIsHighlighted = bIsHighlighted;
+
+ if (g_Settings.iEventLimit > 0 && pTemp->iEventCount > g_Settings.iEventLimit + g_Settings.iEventLimitThreshold) {
+ LM_TrimLog(&pTemp->pLog, &pTemp->pLogEnd, pTemp->iEventCount - g_Settings.iEventLimit);
+ pTemp->wasTrimmed = TRUE;
+ pTemp->iEventCount = g_Settings.iEventLimit;
+ }
+ return TRUE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return TRUE;
+}
+
+USERINFO * SM_AddUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszID || !pszModule)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ USERINFO * p = UM_AddUser(pTemp->pStatuses, &pTemp->pUsers, pszUID, pszNick, wStatus);
+ pTemp->nUsersInNicklist++;
+ return p;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+
+ return 0;
+}
+
+BOOL SM_MoveUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID)
+{
+ SESSION_INFO* pTemp = m_WndList;
+
+ if (!pszID || !pszModule || !pszUID)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ UM_SortUser(&pTemp->pUsers, pszUID);
+ return TRUE;
+ }
+ pTemp = pTemp->next;
+ }
+
+ return FALSE;
+}
+
+BOOL SM_RemoveUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszModule || !pszUID)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ DWORD dw;
+ USERINFO * ui = UM_FindUser(pTemp->pUsers, pszUID);
+ if (ui) {
+ pTemp->nUsersInNicklist--;
+
+ dw = UM_RemoveUser(&pTemp->pUsers, pszUID);
+
+ if (pTemp->hWnd)
+ SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0);
+
+ if (pszID)
+ return TRUE;
+ }
+ }
+
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+
+ return 0;
+}
+
+USERINFO * SM_GetUserFromIndex(const TCHAR* pszID, const char* pszModule, int index)
+{
+ SESSION_INFO* pTemp = m_WndList;
+
+ if (!pszModule)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule))
+ return UM_FindUserFromIndex(pTemp->pUsers, index);
+ pTemp = pTemp->next;
+ }
+
+ return NULL;
+}
+
+
+STATUSINFO * SM_AddStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszStatus)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszID || !pszModule)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ STATUSINFO* ti = TM_AddStatus(&pTemp->pStatuses, pszStatus, &pTemp->iStatusCount);
+ if (ti)
+ pTemp->iStatusCount++;
+ return ti;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+
+ return 0;
+}
+
+BOOL SM_GiveStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszStatus)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszID || !pszModule)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ USERINFO * ui = UM_GiveStatus(pTemp->pUsers, pszUID, TM_StringToWord(pTemp->pStatuses, pszStatus));
+ if (ui) {
+ SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID);
+ if (pTemp->hWnd)
+ SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0);
+ }
+ return TRUE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+
+ return FALSE;
+}
+
+BOOL SM_SetContactStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, WORD wStatus)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszID || !pszModule)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ USERINFO * ui = UM_SetContactStatus(pTemp->pUsers, pszUID, wStatus);
+ if (ui) {
+ SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID);
+ if (pTemp->hWnd)
+ SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0);
+ }
+ return TRUE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+
+ return FALSE;
+}
+
+BOOL SM_TakeStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszStatus)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszID || !pszModule)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ USERINFO* ui = UM_TakeStatus(pTemp->pUsers, pszUID, TM_StringToWord(pTemp->pStatuses, pszStatus));
+ if (ui) {
+ SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID);
+ if (pTemp->hWnd)
+ SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0);
+ }
+ return TRUE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+
+ return FALSE;
+}
+LRESULT SM_SendMessage(const TCHAR* pszID, const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ while (pTemp && pszModule) {
+ if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ if (pTemp->hWnd) {
+ LRESULT i = SendMessage(pTemp->hWnd, msg, wParam, lParam);
+ if (pszID)
+ return i;
+ }
+ if (pszID)
+ return 0;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return 0;
+}
+
+BOOL SM_PostMessage(const TCHAR* pszID, const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszID || !pszModule)
+ return 0;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ if (pTemp->hWnd)
+ return PostMessage(pTemp->hWnd, msg, wParam, lParam);
+
+ return FALSE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return FALSE;
+}
+
+BOOL SM_BroadcastMessage(const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam, BOOL bAsync)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ while (pTemp != NULL) {
+ if (!pszModule || !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ if (pTemp->hWnd) {
+ if (bAsync)
+ PostMessage(pTemp->hWnd, msg, wParam, lParam);
+ else
+ SendMessage(pTemp->hWnd, msg, wParam, lParam);
+ }
+
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return TRUE;
+}
+
+BOOL SM_ReconfigureFilters()
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ while (pTemp != NULL) {
+ Chat_SetFilters(pTemp);
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return TRUE;
+}
+
+BOOL SM_InvalidateLogDirectories()
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ EnterCriticalSection(&cs);
+
+ while (pTemp != NULL) {
+ pTemp->pszLogFileName[0] = 0;
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+
+ LeaveCriticalSection(&cs);
+ return TRUE;
+}
+
+BOOL SM_SetStatus(const TCHAR* pszID, const char* pszModule, int wStatus)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszModule)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ pTemp->wStatus = wStatus;
+
+ if (pTemp->hContact) {
+ if (pTemp->iType != GCW_SERVER && wStatus != ID_STATUS_OFFLINE)
+ DBDeleteContactSetting(pTemp->hContact, "CList", "Hidden");
+
+ DBWriteContactSettingWord(pTemp->hContact, pTemp->pszModule, "Status", (WORD)wStatus);
+ }
+
+ if (pszID)
+ return TRUE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return TRUE;
+}
+
+BOOL SM_SendUserMessage(const TCHAR* pszID, const char* pszModule, const TCHAR* pszText)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszModule || !pszText)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ if (pTemp->iType == GCW_CHATROOM)
+ DoEventHook(pTemp->ptszID, pTemp->pszModule, GC_USER_MESSAGE, NULL, pszText, (LPARAM)NULL);
+ if (pszID)
+ return TRUE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return TRUE;
+}
+
+BOOL SM_ChangeUID(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszNewUID)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszModule)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ USERINFO* ui = UM_FindUser(pTemp->pUsers, pszUID);
+ if (ui)
+ replaceStr(&ui->pszUID, pszNewUID);
+
+ if (pszID)
+ return TRUE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return TRUE;
+}
+
+BOOL SM_ChangeNick(const TCHAR* pszID, const char* pszModule, GCEVENT * gce)
+{
+ SESSION_INFO* pTemp = m_WndList, *pLast = NULL;
+
+ if (!pszModule)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) {
+ USERINFO* ui = UM_FindUser(pTemp->pUsers, gce->ptszUID);
+ if (ui) {
+ replaceStr(&ui->pszNick, gce->ptszText);
+ SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID);
+ if (pTemp->hWnd) {
+ SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, 0, 0);
+ if(pTemp->dat)
+ GetMyNick(pTemp->dat);
+ SendMessage(pTemp->hWnd, GC_UPDATESTATUSBAR, 0, 0);
+ }
+ }
+ if (pszID)
+ return TRUE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return TRUE;
+}
+BOOL SM_RemoveAll(void)
+{
+ while (m_WndList) {
+ SESSION_INFO*pLast = m_WndList->next;
+
+ if (m_WndList->hWnd)
+ SendMessage(m_WndList->hWnd, GC_EVENT_CONTROL + WM_USER + 500, SESSION_TERMINATE, 0);
+ DoEventHook(m_WndList->ptszID, m_WndList->pszModule, GC_SESSION_TERMINATE, NULL, NULL, (DWORD)m_WndList->dwItemData);
+ if (m_WndList->hContact)
+ CList_SetOffline(m_WndList->hContact, m_WndList->iType == GCW_CHATROOM ? TRUE : FALSE);
+ DBWriteContactSettingString(m_WndList->hContact, m_WndList->pszModule , "Topic", "");
+ DBDeleteContactSetting(m_WndList->hContact, "CList", "StatusMsg");
+ DBWriteContactSettingString(m_WndList->hContact, m_WndList->pszModule, "StatusBar", "");
+
+ UM_RemoveAll(&m_WndList->pUsers);
+ TM_RemoveAll(&m_WndList->pStatuses);
+ LM_RemoveAll(&m_WndList->pLog, &m_WndList->pLogEnd);
+ m_WndList->iStatusCount = 0;
+ m_WndList->nUsersInNicklist = 0;
+
+ mir_free(m_WndList->pszModule);
+ mir_free(m_WndList->ptszID);
+ mir_free(m_WndList->ptszName);
+ mir_free(m_WndList->ptszStatusbarText);
+ mir_free(m_WndList->ptszTopic);
+
+ while (m_WndList->lpCommands != NULL) {
+ COMMAND_INFO *pNext = m_WndList->lpCommands->next;
+ mir_free(m_WndList->lpCommands->lpCommand);
+ mir_free(m_WndList->lpCommands);
+ m_WndList->lpCommands = pNext;
+ }
+
+ mir_free(m_WndList);
+ m_WndList = pLast;
+ }
+ m_WndList = NULL;
+ return TRUE;
+}
+
+void SM_AddCommand(const TCHAR* pszID, const char* pszModule, const char* lpNewCommand)
+{
+ SESSION_INFO* pTemp = m_WndList;
+ while (pTemp != NULL) {
+ if (lstrcmpi(pTemp->ptszID, pszID) == 0 && lstrcmpiA(pTemp->pszModule, pszModule) == 0) { // match
+ COMMAND_INFO *node = (COMMAND_INFO *)mir_alloc(sizeof(COMMAND_INFO));
+ node->lpCommand = mir_strdup(lpNewCommand);
+ node->last = NULL; // always added at beginning!
+ // new commands are added at start
+ if (pTemp->lpCommands == NULL) {
+ node->next = NULL;
+ pTemp->lpCommands = node;
+ } else {
+ node->next = pTemp->lpCommands;
+ pTemp->lpCommands->last = node; // hmm, weird
+ pTemp->lpCommands = node;
+ }
+ pTemp->lpCurrentCommand = NULL; // current command
+ pTemp->wCommandsNum++;
+
+ if (pTemp->wCommandsNum > WINDOWS_COMMANDS_MAX) {
+ COMMAND_INFO *pCurComm = pTemp->lpCommands;
+ COMMAND_INFO *pLast;
+ while (pCurComm->next != NULL) {
+ pCurComm = pCurComm->next;
+ }
+ pLast = pCurComm->last;
+ mir_free(pCurComm->lpCommand);
+ mir_free(pCurComm);
+ pLast->next = NULL;
+ // done
+ pTemp->wCommandsNum--;
+ }
+ }
+ pTemp = pTemp->next;
+ }
+}
+
+char* SM_GetPrevCommand(const TCHAR* pszID, const char* pszModule) // get previous command. returns NULL if previous command does not exist. current command remains as it was.
+{
+ SESSION_INFO* pTemp = m_WndList;
+ while (pTemp != NULL) {
+ if (lstrcmpi(pTemp->ptszID, pszID) == 0 && lstrcmpiA(pTemp->pszModule, pszModule) == 0) { // match
+ COMMAND_INFO *pPrevCmd = NULL;
+ if (pTemp->lpCurrentCommand != NULL) {
+ if (pTemp->lpCurrentCommand->next != NULL) // not NULL
+ pPrevCmd = pTemp->lpCurrentCommand->next; // next command (newest at beginning)
+ else
+ pPrevCmd = pTemp->lpCurrentCommand;
+ } else pPrevCmd = pTemp->lpCommands;
+
+ pTemp->lpCurrentCommand = pPrevCmd; // make it the new command
+ return(((pPrevCmd) ? (pPrevCmd->lpCommand) : (NULL)));
+ }
+ pTemp = pTemp->next;
+ }
+ return(NULL);
+}
+
+char* SM_GetNextCommand(const TCHAR* pszID, const char* pszModule) // get next command. returns NULL if next command does not exist. current command becomes NULL (a prev command after this one will get you the last command)
+{
+ SESSION_INFO* pTemp = m_WndList;
+ while (pTemp != NULL) {
+ if (lstrcmpi(pTemp->ptszID, pszID) == 0 && lstrcmpiA(pTemp->pszModule, pszModule) == 0) { // match
+ COMMAND_INFO *pNextCmd = NULL;
+ if (pTemp->lpCurrentCommand != NULL)
+ pNextCmd = pTemp->lpCurrentCommand->last; // last command (newest at beginning)
+
+ pTemp->lpCurrentCommand = pNextCmd; // make it the new command
+ return(((pNextCmd) ? (pNextCmd->lpCommand) : (NULL)));
+ }
+ pTemp = pTemp->next;
+ }
+ return(NULL);
+}
+
+int SM_GetCount(const char* pszModule)
+{
+ SESSION_INFO* pTemp = m_WndList;
+ int count = 0;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpiA(pszModule, pTemp->pszModule))
+ count++;
+
+ pTemp = pTemp->next;
+ }
+ return count;
+}
+
+SESSION_INFO* SM_FindSessionByHWND(HWND hWnd)
+{
+ SESSION_INFO *pTemp = m_WndList;
+
+ while (pTemp) {
+ if (pTemp->hWnd == hWnd)
+ return pTemp;
+ pTemp = pTemp->next;
+ }
+ return NULL;
+}
+
+SESSION_INFO * SM_FindSessionByHCONTACT(HANDLE h)
+{
+ SESSION_INFO *pTemp = m_WndList;
+
+ while (pTemp) {
+ if (pTemp->hContact == h)
+ return pTemp;
+ pTemp = pTemp->next;
+ }
+ return NULL;
+}
+
+SESSION_INFO* SM_FindSessionByIndex(const char* pszModule, int iItem)
+{
+ SESSION_INFO* pTemp = m_WndList;
+ int count = 0;
+ while (pTemp != NULL) {
+ if (!lstrcmpiA(pszModule, pTemp->pszModule)) {
+ if (iItem == count)
+ return pTemp;
+ else
+ count++;
+ }
+
+ pTemp = pTemp->next;
+ }
+ return NULL;
+
+}
+
+SESSION_INFO* SM_FindSessionAutoComplete(const char* pszModule, SESSION_INFO* currSession, SESSION_INFO* prevSession, const TCHAR* pszOriginal, const TCHAR* pszCurrent)
+{
+ SESSION_INFO* pResult = NULL;
+ if (prevSession == NULL && my_strstri(currSession->ptszName, pszOriginal) == currSession->ptszName) {
+ pResult = currSession;
+ } else {
+ TCHAR* pszName = NULL;
+ SESSION_INFO* pTemp = m_WndList;
+ if (currSession == prevSession) {
+ pszCurrent = pszOriginal;
+ }
+ while (pTemp != NULL) {
+ if (pTemp != currSession && !lstrcmpiA(pszModule, pTemp->pszModule)) {
+ if (my_strstri(pTemp->ptszName, pszOriginal) == pTemp->ptszName) {
+ if (prevSession != pTemp && lstrcmpi(pTemp->ptszName, pszCurrent) > 0 && (!pszName || lstrcmpi(pTemp->ptszName, pszName) < 0)) {
+ pResult = pTemp;
+ pszName = pTemp->ptszName;
+ }
+ }
+ }
+ pTemp = pTemp->next;
+ }
+ }
+ return pResult;
+
+}
+
+char* SM_GetUsers(SESSION_INFO* si)
+{
+ SESSION_INFO* pTemp = m_WndList;
+ USERINFO* utemp;
+ int count = 0;
+ char* p = NULL;
+ int alloced = 0;
+
+ if (si == NULL)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (si == pTemp) {
+ if ((utemp = pTemp->pUsers) == NULL)
+ return NULL;
+
+ break;
+ }
+ pTemp = pTemp->next;
+ }
+
+ do {
+ int pLen = lstrlenA(p), nameLen = lstrlen(utemp->pszUID);
+ if (pLen + nameLen + 2 > alloced)
+ p = (char *)mir_realloc(p, alloced += 4096);
+ WideCharToMultiByte(CP_ACP, 0, utemp->pszUID, -1, p + pLen, nameLen + 1, 0, 0);
+ lstrcpyA(p + pLen + nameLen, " ");
+ utemp = utemp->next;
+ } while (utemp != NULL);
+ return p;
+}
+
+
+
+
+
+
+//---------------------------------------------------
+// Module Manager functions
+//
+// Necessary to keep track of all modules
+// that has registered with the plugin
+//---------------------------------------------------
+
+MODULEINFO* MM_AddModule(const char* pszModule)
+{
+ if (!pszModule)
+ return NULL;
+ if (!MM_FindModule(pszModule)) {
+ MODULEINFO *node = (MODULEINFO*) mir_alloc(sizeof(MODULEINFO));
+ ZeroMemory(node, sizeof(MODULEINFO));
+
+ node->pszModule = (char*)mir_alloc(lstrlenA(pszModule) + 1);
+ lstrcpyA(node->pszModule, pszModule);
+ node->idleTimeStamp = time(0);
+ if (m_ModList == NULL) { // list is empty
+ m_ModList = node;
+ node->next = NULL;
+ } else {
+ node->next = m_ModList;
+ m_ModList = node;
+ }
+ return node;
+ }
+ return FALSE;
+}
+
+/*
+void MM_IconsChanged(void)
+{
+ MODULEINFO *pTemp = m_ModList, *pLast = NULL;
+ while (pTemp != NULL) {
+ if (pTemp->hOfflineIcon)
+ DestroyIcon(pTemp->hOfflineIcon);
+ if (pTemp->hOnlineIcon)
+ DestroyIcon(pTemp->hOnlineIcon);
+ if (pTemp->hOnlineTalkIcon)
+ DestroyIcon(pTemp->hOnlineTalkIcon);
+ if (pTemp->hOfflineTalkIcon)
+ DestroyIcon(pTemp->hOfflineTalkIcon);
+
+ pTemp->hOfflineIcon = ImageList_GetIcon(hIconsList, pTemp->OfflineIconIndex, ILD_TRANSPARENT);
+ pTemp->hOnlineIcon = ImageList_GetIcon(hIconsList, pTemp->OnlineIconIndex, ILD_TRANSPARENT);
+
+ pTemp->hOnlineTalkIcon = ImageList_GetIcon(hIconsList, pTemp->OnlineIconIndex, ILD_TRANSPARENT|INDEXTOOVERLAYMASK(1));
+ ImageList_ReplaceIcon(hIconsList, pTemp->OnlineIconIndex+1, pTemp->hOnlineTalkIcon);
+
+ pTemp->hOfflineTalkIcon = ImageList_GetIcon(hIconsList, pTemp->OfflineIconIndex, ILD_TRANSPARENT|INDEXTOOVERLAYMASK(1));
+ ImageList_ReplaceIcon(hIconsList, pTemp->OfflineIconIndex+1, pTemp->hOfflineTalkIcon);
+
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return;
+}
+*/
+
+void MM_FontsChanged(void)
+{
+ MODULEINFO *pTemp = m_ModList;
+ while (pTemp != NULL) {
+ pTemp->pszHeader = Log_CreateRtfHeader(pTemp);
+ pTemp = pTemp->next;
+ }
+ return;
+}
+MODULEINFO* MM_FindModule(const char* pszModule)
+{
+ MODULEINFO *pTemp = m_ModList, *pLast = NULL;
+
+ if (!pszModule)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (lstrcmpiA(pTemp->pszModule, pszModule) == 0)
+ return pTemp;
+
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return 0;
+}
+
+// stupid thing..
+void MM_FixColors()
+{
+ MODULEINFO *pTemp = m_ModList;
+
+ while (pTemp != NULL) {
+ CheckColorsInModule(pTemp->pszModule);
+ pTemp = pTemp->next;
+ }
+ return;
+}
+
+BOOL MM_RemoveAll(void)
+{
+ while (m_ModList != NULL) {
+ MODULEINFO *pLast = m_ModList->next;
+ mir_free(m_ModList->pszModule);
+ mir_free(m_ModList->ptszModDispName);
+ if(m_ModList->pszHeader)
+ mir_free(m_ModList->pszHeader);
+ mir_free(m_ModList->crColors);
+
+ mir_free(m_ModList);
+ m_ModList = pLast;
+ }
+ m_ModList = NULL;
+ return TRUE;
+}
+
+//---------------------------------------------------
+// Status manager functions
+//
+// Necessary to keep track of what user statuses
+// per window nicklist that is available
+//---------------------------------------------------
+
+STATUSINFO * TM_AddStatus(STATUSINFO** ppStatusList, const TCHAR* pszStatus, int* iCount)
+{
+ if (!ppStatusList || !pszStatus)
+ return NULL;
+
+ if (!TM_FindStatus(*ppStatusList, pszStatus)) {
+ STATUSINFO *node = (STATUSINFO*) mir_alloc(sizeof(STATUSINFO));
+ ZeroMemory(node, sizeof(STATUSINFO));
+ replaceStr(&node->pszGroup, pszStatus);
+ node->hIcon = (HICON)(*iCount);
+ while ((int)node->hIcon > STATUSICONCOUNT - 1)
+ node->hIcon--;
+
+ if (*ppStatusList == NULL) { // list is empty
+ node->Status = 1;
+ *ppStatusList = node;
+ node->next = NULL;
+ } else {
+ node->Status = ppStatusList[0]->Status * 2;
+ node->next = *ppStatusList;
+ *ppStatusList = node;
+ }
+ return node;
+
+ }
+ return FALSE;
+}
+
+STATUSINFO * TM_FindStatus(STATUSINFO* pStatusList, const TCHAR* pszStatus)
+{
+ STATUSINFO *pTemp = pStatusList, *pLast = NULL;
+
+ if (!pStatusList || !pszStatus)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (lstrcmpi(pTemp->pszGroup, pszStatus) == 0)
+ return pTemp;
+
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return 0;
+}
+
+WORD TM_StringToWord(STATUSINFO* pStatusList, const TCHAR* pszStatus)
+{
+ STATUSINFO *pTemp = pStatusList, *pLast = NULL;
+
+ if (!pStatusList || !pszStatus)
+ return 0;
+
+ while (pTemp != NULL) {
+ if (lstrcmpi(pTemp->pszGroup, pszStatus) == 0)
+ return pTemp->Status;
+
+ if (pTemp->next == NULL)
+ return pStatusList->Status;
+
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return 0;
+}
+
+TCHAR* TM_WordToString(STATUSINFO* pStatusList, WORD Status)
+{
+ STATUSINFO *pTemp = pStatusList, *pLast = NULL;
+
+ if (!pStatusList)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (pTemp->Status&Status) {
+ Status -= pTemp->Status;
+ if (Status == 0)
+ return pTemp->pszGroup;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return 0;
+}
+
+BOOL TM_RemoveAll(STATUSINFO** ppStatusList)
+{
+
+ if (!ppStatusList)
+ return FALSE;
+
+ while (*ppStatusList != NULL) {
+ STATUSINFO *pLast = ppStatusList[0]->next;
+ mir_free(ppStatusList[0]->pszGroup);
+ if ((int)ppStatusList[0]->hIcon > 10)
+ DestroyIcon(ppStatusList[0]->hIcon);
+ mir_free(*ppStatusList);
+ *ppStatusList = pLast;
+ }
+ *ppStatusList = NULL;
+ return TRUE;
+}
+
+//---------------------------------------------------
+// User manager functions
+//
+// Necessary to keep track of the users
+// in a window nicklist
+//---------------------------------------------------
+
+//MAD: alternative sorting by Nullbie
+static int sttCompareNicknames(const TCHAR *s1, const TCHAR *s2)
+{
+ // skip rubbish
+ while (*s1 && !_istalpha(*s1)) ++s1;
+ while (*s2 && !_istalpha(*s2)) ++s2;
+
+ // are there ~0veRy^kEwL_n1kz?
+ if (!*s1 && !*s2) return 0;
+ if (!*s1 && *s2) return +1;
+ if (*s1 && !*s2) return -1;
+
+ // compare tails
+ return lstrcmpi(s1, s2);
+}
+//
+
+static int UM_CompareItem(USERINFO * u1, const TCHAR* pszNick, WORD wStatus)
+{
+ int i;
+
+ WORD dw1 = u1->Status;
+ WORD dw2 = wStatus;
+
+ for (i = 0; i < 8; i++) {
+ if ((dw1 & 1) && !(dw2 & 1))
+ return -1;
+ if ((dw2 & 1) && !(dw1 & 1))
+ return 1;
+ if ((dw1 & 1) && (dw2 & 1))
+ //
+ {
+ if (g_Settings.AlternativeSorting)
+ return sttCompareNicknames(u1->pszNick, pszNick);
+ else
+ return lstrcmp(u1->pszNick, pszNick);
+ }//
+ dw1 = dw1 >> 1;
+ dw2 = dw2 >> 1;
+ }
+ if (g_Settings.AlternativeSorting)
+ //
+ return sttCompareNicknames(u1->pszNick, pszNick);
+ else
+ return lstrcmp(u1->pszNick, pszNick);
+ //
+}
+
+USERINFO * UM_SortUser(USERINFO** ppUserList, const TCHAR* pszUID)
+{
+ USERINFO * pTemp = *ppUserList, *pLast = NULL;
+ USERINFO * node = NULL;
+
+ if (!pTemp || !pszUID)
+ return NULL;
+
+ while (pTemp && lstrcmpi(pTemp->pszUID, pszUID)) {
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+
+ if (pTemp) {
+ node = pTemp;
+ if (pLast)
+ pLast->next = pTemp->next;
+ else
+ *ppUserList = pTemp->next;
+ pTemp = *ppUserList;
+
+ pLast = NULL;
+
+ while (pTemp && UM_CompareItem(pTemp, node->pszNick, node->Status) <= 0) {
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+
+ if (*ppUserList == NULL) { // list is empty
+ *ppUserList = node;
+ node->next = NULL;
+ } else {
+ if (pLast) {
+ node->next = pTemp;
+ pLast->next = node;
+ } else {
+ node->next = *ppUserList;
+ *ppUserList = node;
+ }
+ }
+
+ return node;
+ }
+ return NULL;
+}
+
+USERINFO* UM_AddUser(STATUSINFO* pStatusList, USERINFO** ppUserList, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus)
+{
+ USERINFO * pTemp = *ppUserList, *pLast = NULL;
+
+ if (!pStatusList || !ppUserList || !ppUserList)
+ return NULL;
+
+ while (pTemp && UM_CompareItem(pTemp, pszNick, wStatus) <= 0) {
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+
+ // if (!UM_FindUser(*ppUserList, pszUI, wStatus)
+ {
+ USERINFO *node = (USERINFO*) mir_alloc(sizeof(USERINFO));
+ ZeroMemory(node, sizeof(USERINFO));
+ replaceStr(&node->pszUID, pszUID);
+
+ if (*ppUserList == NULL) { // list is empty
+ *ppUserList = node;
+ node->next = NULL;
+ } else {
+ if (pLast) {
+ node->next = pTemp;
+ pLast->next = node;
+ } else {
+ node->next = *ppUserList;
+ *ppUserList = node;
+ }
+ }
+
+ return node;
+ }
+ return NULL;
+}
+
+USERINFO* UM_FindUser(USERINFO* pUserList, const TCHAR* pszUID)
+{
+ USERINFO *pTemp = pUserList, *pLast = NULL;
+
+ if (!pUserList || !pszUID)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->pszUID, pszUID))
+ return pTemp;
+
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return 0;
+}
+
+USERINFO* UM_FindUserFromIndex(USERINFO* pUserList, int index)
+{
+ int i = 0;
+ USERINFO *pTemp = pUserList;
+
+ if (!pUserList)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (i == index) {
+ return pTemp;
+ }
+ pTemp = pTemp->next;
+ i++;
+ }
+ return NULL;
+}
+
+USERINFO* UM_GiveStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status)
+{
+ USERINFO *pTemp = pUserList, *pLast = NULL;
+
+ if (!pUserList || !pszUID)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->pszUID, pszUID)) {
+ pTemp->Status |= status;
+ return pTemp;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return 0;
+}
+
+USERINFO* UM_SetContactStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status)
+{
+ USERINFO *pTemp = pUserList, *pLast = NULL;
+
+ if (!pUserList || !pszUID)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->pszUID, pszUID)) {
+ pTemp->ContactStatus = status;
+ return pTemp;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return 0;
+}
+
+BOOL UM_SetStatusEx(USERINFO* pUserList, const TCHAR* pszText, int flags)
+{
+ USERINFO *pTemp = pUserList, *pLast = NULL;
+ int bOnlyMe = (flags & GC_SSE_ONLYLISTED) != 0, bSetStatus = (flags & GC_SSE_ONLINE) != 0;
+ char cDelimiter = (flags & GC_SSE_TABDELIMITED) ? '\t' : ' ';
+
+ while (pTemp != NULL) {
+ if (!bOnlyMe)
+ pTemp->iStatusEx = 0;
+
+ if (pszText != NULL) {
+ TCHAR* s = (TCHAR *)_tcsstr(pszText, pTemp->pszUID);
+ if (s) {
+ pTemp->iStatusEx = 0;
+ if (s == pszText || s[-1] == cDelimiter) {
+ int len = lstrlen(pTemp->pszUID);
+ if (s[len] == cDelimiter || s[len] == '\0')
+ pTemp->iStatusEx = (!bOnlyMe || bSetStatus) ? 1 : 0;
+ }
+ }
+ }
+
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return TRUE;
+}
+
+USERINFO* UM_TakeStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status)
+{
+ USERINFO *pTemp = pUserList, *pLast = NULL;
+
+ if (!pUserList || !pszUID)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->pszUID, pszUID)) {
+ pTemp->Status &= ~status;
+ return pTemp;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return 0;
+}
+
+TCHAR* UM_FindUserAutoComplete(USERINFO* pUserList, const TCHAR* pszOriginal, const TCHAR* pszCurrent)
+{
+ TCHAR* pszName = NULL;
+ USERINFO *pTemp = pUserList;
+
+ if (!pUserList || !pszOriginal || !pszCurrent)
+ return NULL;
+
+ while (pTemp != NULL) {
+ if (my_strstri(pTemp->pszNick, pszOriginal) == pTemp->pszNick)
+ if (lstrcmpi(pTemp->pszNick, pszCurrent) > 0 && (!pszName || lstrcmpi(pTemp->pszNick, pszName) < 0))
+ pszName = pTemp->pszNick;
+
+ pTemp = pTemp->next;
+ }
+ return pszName;
+}
+
+BOOL UM_RemoveUser(USERINFO** ppUserList, const TCHAR* pszUID)
+{
+ USERINFO *pTemp = *ppUserList, *pLast = NULL;
+
+ if (!ppUserList || !pszUID)
+ return FALSE;
+
+ while (pTemp != NULL) {
+ if (!lstrcmpi(pTemp->pszUID, pszUID)) {
+ if (pLast == NULL)
+ *ppUserList = pTemp->next;
+ else
+ pLast->next = pTemp->next;
+ mir_free(pTemp->pszNick);
+ mir_free(pTemp->pszUID);
+ mir_free(pTemp);
+ return TRUE;
+ }
+ pLast = pTemp;
+ pTemp = pTemp->next;
+ }
+ return FALSE;
+}
+
+BOOL UM_RemoveAll(USERINFO** ppUserList)
+{
+ if (!ppUserList)
+ return FALSE;
+
+ while (*ppUserList != NULL) {
+ USERINFO *pLast = ppUserList[0]->next;
+ mir_free(ppUserList[0]->pszUID);
+ mir_free(ppUserList[0]->pszNick);
+ mir_free(*ppUserList);
+ *ppUserList = pLast;
+ }
+ *ppUserList = NULL;
+ return TRUE;
+}
+
+//---------------------------------------------------
+// Log manager functions
+//
+// Necessary to keep track of events
+// in a window log
+//---------------------------------------------------
+
+LOGINFO * LM_AddEvent(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd)
+{
+
+ LOGINFO *node = NULL;
+
+ if (!ppLogListStart || !ppLogListEnd)
+ return NULL;
+
+ node = (LOGINFO*) mir_alloc(sizeof(LOGINFO));
+ ZeroMemory(node, sizeof(LOGINFO));
+
+
+ if (*ppLogListStart == NULL) { // list is empty
+ *ppLogListStart = node;
+ *ppLogListEnd = node;
+ node->next = NULL;
+ node->prev = NULL;
+ } else {
+ ppLogListStart[0]->prev = node;
+ node->next = *ppLogListStart;
+ *ppLogListStart = node;
+ ppLogListStart[0]->prev = NULL;
+ }
+
+ return node;
+}
+
+BOOL LM_TrimLog(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd, int iCount)
+{
+ LOGINFO *pTemp = *ppLogListEnd;
+ while (pTemp != NULL && iCount > 0) {
+ *ppLogListEnd = pTemp->prev;
+ if (*ppLogListEnd == NULL)
+ *ppLogListStart = NULL;
+
+ mir_free(pTemp->ptszNick);
+ mir_free(pTemp->ptszUserInfo);
+ mir_free(pTemp->ptszText);
+ mir_free(pTemp->ptszStatus);
+ mir_free(pTemp);
+ pTemp = *ppLogListEnd;
+ iCount--;
+ }
+ ppLogListEnd[0]->next = NULL;
+
+ return TRUE;
+}
+
+BOOL LM_RemoveAll(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd)
+{
+ while (*ppLogListStart != NULL) {
+ LOGINFO *pLast = ppLogListStart[0]->next;
+ mir_free(ppLogListStart[0]->ptszText);
+ mir_free(ppLogListStart[0]->ptszNick);
+ mir_free(ppLogListStart[0]->ptszStatus);
+ mir_free(ppLogListStart[0]->ptszUserInfo);
+ mir_free(*ppLogListStart);
+ *ppLogListStart = pLast;
+ }
+ *ppLogListStart = NULL;
+ *ppLogListEnd = NULL;
+ return TRUE;
+}
diff --git a/plugins/TabSRMM/chat/message.cpp b/plugins/TabSRMM/chat/message.cpp
new file mode 100644
index 0000000000..0a7f56b594
--- /dev/null
+++ b/plugins/TabSRMM/chat/message.cpp
@@ -0,0 +1,341 @@
+/*
+astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ --pad=oper --one-line=keep-blocks --unpad=paren
+
+Chat module plugin for Miranda IM
+
+Copyright (C) 2003 Jörgen Persson
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+$Id: message.c 10402 2009-07-24 00:35:21Z silvercircle $
+*/
+
+#include "../src/commonheaders.h"
+#include <math.h>
+
+static int RTFColorToIndex(int *pIndex, int iCol, SESSION_INFO* si)
+{
+ int i;
+ MODULEINFO * pMod = MM_FindModule(si->pszModule);
+
+ for (i = 0; i < pMod->nColorCount ; i++)
+ if (pIndex[i] == iCol)
+ return i;
+
+ return -1;
+}
+
+static void CreateColorMap(char* Text, int *pIndex, SESSION_INFO* si)
+{
+ char *p1, *p2, *pEnd;
+ int iIndex = 1;
+
+ static const char* lpszFmt = "\\red%[^ \x5b\\]\\green%[^ \x5b\\]\\blue%[^ \x5b;];";
+ char szRed[10], szGreen[10], szBlue[10];
+
+ p1 = strstr(Text, "\\colortbl");
+ if (!p1)
+ return;
+
+ pEnd = strchr(p1, '}');
+ p2 = strstr(p1, "\\red");
+
+ while (p2 && p2 < pEnd) {
+ if (sscanf(p2, lpszFmt, &szRed, &szGreen, &szBlue) > 0) {
+ int i;
+ MODULEINFO * pMod = MM_FindModule(si->pszModule);
+ for (i = 0; i < pMod->nColorCount ; i ++)
+ if (pMod->crColors[i] == RGB(atoi(szRed), atoi(szGreen), atoi(szBlue)))
+ pIndex[i] = iIndex;
+ }
+ iIndex++;
+ p1 = p2;
+ p1 ++;
+ p2 = strstr(p1, "\\red");
+ }
+}
+
+static int ReadInteger(const char* p, int* result)
+{
+ char temp[10];
+ int i = 0;
+ while (isdigit(*p) && i < 9)
+ temp[i++] = *p++;
+ temp[i] = 0;
+
+ if (result != NULL)
+ *result = atoi(temp);
+
+ return i;
+}
+
+TCHAR* Chat_DoRtfToTags(char* pszText, SESSION_INFO* si)
+{
+ char *p1;
+ int* pIndex;
+ int i, iRemoveChars, cp = CP_ACP;
+ char InsertThis[50];
+ BOOL bJustRemovedRTF = TRUE;
+ BOOL bTextHasStarted = FALSE;
+ TCHAR *ptszResult; //, *d;
+ int iUcMode = 0;
+
+ if (!pszText)
+ return FALSE;
+
+ // create an index of colors in the module and map them to
+ // corresponding colors in the RTF color table
+ pIndex = (int *)mir_alloc(sizeof(int) * MM_FindModule(si->pszModule)->nColorCount);
+ for (i = 0; i < MM_FindModule(si->pszModule)->nColorCount ; i++)
+ pIndex[i] = -1;
+
+ CreateColorMap(pszText, pIndex, si);
+
+ // scan the file for rtf commands and remove or parse them
+ p1 = strstr(pszText, "\\pard");
+ if (p1 == NULL) {
+ mir_free(pIndex);
+ return FALSE;
+ }
+
+ p1 += 5;
+
+ MoveMemory(pszText, p1, lstrlenA(p1) + 1);
+ p1 = pszText;
+
+ // iterate through all characters, if rtf control character found then take action
+ while (*p1 != '\0') {
+ InsertThis[0] = 0;
+ iRemoveChars = 0;
+
+ switch (*p1) {
+ case '\\':
+ if (!memcmp(p1, "\\cf", 3)) { // foreground color
+ int iCol, iInd;
+ iRemoveChars = 3 + ReadInteger(p1 + 3, &iCol);
+ iInd = RTFColorToIndex(pIndex, iCol, si);
+ bJustRemovedRTF = TRUE;
+
+ if (bTextHasStarted || iInd >= 0)
+ mir_snprintf(InsertThis, SIZEOF(InsertThis), (iInd >= 0) ? "%%c%02u" : "%%C", iInd);
+ } else if (!memcmp(p1, "\\highlight", 10)) { //background color
+ int iCol, iInd;
+ iRemoveChars = 10 + ReadInteger(p1 + 10, &iCol);
+ iInd = RTFColorToIndex(pIndex, iCol, si);
+ bJustRemovedRTF = TRUE;
+
+ if (bTextHasStarted || iInd >= 0)
+ mir_snprintf(InsertThis, SIZEOF(InsertThis), (iInd >= 0) ? "%%f%02u" : "%%F", iInd);
+ } else if (!memcmp(p1, "\\lang", 5)) { // language id
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ iRemoveChars = 5 + ReadInteger(p1 + 5, NULL);
+ } else if (!memcmp(p1, "\\par", 4)) { // newline
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ iRemoveChars = 4;
+ strcpy(InsertThis, "\n");
+ } else if (!memcmp(p1, "\\endash", 7)) {
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ iRemoveChars = 7;
+ strcpy(InsertThis, "\xE2\x80\x93");
+ } else if (!memcmp(p1, "\\emdash", 7)) {
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ iRemoveChars = 7;
+ strcpy(InsertThis, "\xE2\x80\x94");
+ } else if (!memcmp(p1, "\\bullet", 7)) {
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ iRemoveChars = 7;
+ strcpy(InsertThis, "\xE2\x80\xA2");
+ } else if (!memcmp(p1, "\\line", 5)) { // newline
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ iRemoveChars = 5;
+ strcpy(InsertThis, "\n");
+ } else if (!memcmp(p1, "\\b", 2)) { //bold
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ iRemoveChars = (p1[2] != '0') ? 2 : 3;
+ strcpy(InsertThis, (p1[2] != '0') ? "%b" : "%B");
+ } else if (!memcmp(p1, "\\i", 2)) { // italics
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ iRemoveChars = (p1[2] != '0') ? 2 : 3;
+ strcpy(InsertThis, (p1[2] != '0') ? "%i" : "%I");
+ } else if (!memcmp(p1, "\\uc", 3)) { // number of Unicode chars
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ iUcMode = p1[3] - '0';
+ iRemoveChars = 4;
+ } else if (!memcmp(p1, "\\ul", 3)) { // underlined
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ if (p1[3] == 'n')
+ iRemoveChars = 7;
+ else if (p1[3] == '0')
+ iRemoveChars = 4;
+ else
+ iRemoveChars = 3;
+ mir_snprintf(InsertThis, SIZEOF(InsertThis), (p1[3] != '0' && p1[3] != 'n') ? "%%u" : "%%U");
+ } else if (p1[1] == 'f' && isdigit(p1[2])) { // unicode char
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ iRemoveChars = 2 + ReadInteger(p1 + 2, NULL);
+ } else if (p1[1] == '\\' || p1[1] == '{' || p1[1] == '}') { // escaped characters
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = FALSE;
+ iRemoveChars = 2;
+ mir_snprintf(InsertThis, SIZEOF(InsertThis), "%c", p1[1]);
+ } else if (p1[1] == '~') { // non-breaking space
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = FALSE;
+ iRemoveChars = 2;
+ strcpy(InsertThis, "\xC2\xA0");
+ }
+
+
+ else if (!memcmp(p1, "\\tab",4)) { // tab
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 4;
+ strcpy(InsertThis, "\x09");
+ }
+ else if (!memcmp(p1, "\\ldblquote",10)) {
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 10;
+ strcpy(InsertThis, "\xe2\x80\x9c");
+ }
+ else if (!memcmp(p1, "\\rdblquote",10)) {
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 10;
+ strcpy(InsertThis, "\xe2\x80\x9d");
+ }
+ else if (!memcmp(p1, "\\lquote",7)) {
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 7;
+ strcpy(InsertThis, "\xE2\x80\x98");
+ }
+ else if (!memcmp(p1, "\\rquote",7)) {
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 7;
+ strcpy(InsertThis, "\xE2\x80\x99");
+ }
+
+ else if (p1[1] == '\'') { // special character
+ char tmp[4], *p3 = tmp;
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = FALSE;
+ if (p1[2] != ' ' && p1[2] != '\\') {
+ *p3++ = p1[2];
+ iRemoveChars = 3;
+ if (p1[3] != ' ' && p1[3] != '\\') {
+ *p3++ = p1[3];
+ iRemoveChars++;
+ }
+ *p3 = 0;
+ sscanf(tmp, "%x", InsertThis);
+
+ InsertThis[1] = 0;
+ } else iRemoveChars = 2;
+ } else if (bJustRemovedRTF) { // remove unknown RTF command
+ int j = 1;
+ bJustRemovedRTF = TRUE;
+ while (p1[j] != ' ' && p1[j] != '\\' && p1[j] != '\0')
+ j++;
+ iRemoveChars = j;
+ }
+ break;
+
+ case '{': // other RTF control characters
+ case '}':
+ iRemoveChars = 1;
+ break;
+
+ case '\r': case '\n':
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = FALSE;
+ iRemoveChars = 1;
+ break;
+
+ case '%': // escape chat -> protocol control character
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = FALSE;
+ iRemoveChars = 1;
+ strcpy(InsertThis, "%%");
+ break;
+ case ' ': // remove spaces following a RTF command
+ if (bJustRemovedRTF)
+ iRemoveChars = 1;
+ bJustRemovedRTF = FALSE;
+ bTextHasStarted = TRUE;
+ break;
+
+ default: // other text that should not be touched
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = FALSE;
+ break;
+ }
+
+ // move the memory and paste in new commands instead of the old RTF
+ if (InsertThis[0] || iRemoveChars) {
+ MoveMemory(p1 + lstrlenA(InsertThis) , p1 + iRemoveChars, lstrlenA(p1) - iRemoveChars + 1);
+ CopyMemory(p1, InsertThis, lstrlenA(InsertThis));
+ p1 += lstrlenA(InsertThis);
+ } else p1++;
+ }
+
+ mir_free(pIndex);
+ ptszResult = M->utf8_decodeW(pszText);
+ return ptszResult;
+}
+
+static DWORD CALLBACK Chat_Message_StreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb)
+{
+ static DWORD dwRead;
+ char ** ppText = (char **) dwCookie;
+
+ if (*ppText == NULL) {
+ *ppText = (char *)mir_alloc(cb + 1);
+ memcpy(*ppText, pbBuff, cb);
+ (*ppText)[cb] = 0;
+ *pcb = cb;
+ dwRead = cb;
+ } else {
+ char *p = (char *)mir_alloc(dwRead + cb + 1);
+ memcpy(p, *ppText, dwRead);
+ memcpy(p + dwRead, pbBuff, cb);
+ p[dwRead + cb] = 0;
+ mir_free(*ppText);
+ *ppText = p;
+ *pcb = cb;
+ dwRead += cb;
+ }
+ return 0;
+}
+
+char* Chat_Message_GetFromStream(HWND hwndDlg, SESSION_INFO* si)
+{
+ EDITSTREAM stream;
+ char* pszText = NULL;
+ DWORD dwFlags;
+
+ if (hwndDlg == 0 || si == 0)
+ return NULL;
+
+ ZeroMemory(&stream, sizeof(stream));
+ stream.pfnCallback = Chat_Message_StreamCallback;
+ stream.dwCookie = (DWORD_PTR) & pszText; // pass pointer to pointer
+
+ dwFlags = SF_RTFNOOBJS | SFF_PLAINRTF | SF_USECODEPAGE | (CP_UTF8 << 16);
+ SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), EM_STREAMOUT, dwFlags, (LPARAM) & stream);
+ return pszText; // pszText contains the text
+}
diff --git a/plugins/TabSRMM/chat/muchighlight.cpp b/plugins/TabSRMM/chat/muchighlight.cpp
new file mode 100644
index 0000000000..d790cc1d2b
--- /dev/null
+++ b/plugins/TabSRMM/chat/muchighlight.cpp
@@ -0,0 +1,427 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: muchighlight.cpp 13184 2010-12-07 14:16:58Z silvercircle $
+ *
+ * highlighter class for multi user chats
+ *
+ */
+
+#include "../src/commonheaders.h"
+
+//#define __HLT_PERFSTATS 0
+
+void CMUCHighlight::cleanup()
+{
+ if(m_NickPatternString)
+ mir_free(m_NickPatternString);
+ if(m_TextPatternString)
+ mir_free(m_TextPatternString);
+
+ m_TextPatternString = m_NickPatternString = 0;
+
+ if(m_NickPatterns)
+ mir_free(m_NickPatterns);
+ if(m_TextPatterns)
+ mir_free(m_TextPatterns);
+
+ m_iNickPatterns = m_iTextPatterns = 0;
+ m_NickPatterns = m_TextPatterns = 0;
+}
+
+void CMUCHighlight::init()
+{
+ DBVARIANT dbv = {0};
+
+ if(m_fInitialized)
+ cleanup(); // clean up first, if we were already initialized
+
+ m_fInitialized = true;
+
+ if(0 == M->GetTString(0, "Chat", "HighlightWords", &dbv)) {
+ m_TextPatternString = dbv.ptszVal;
+ _wsetlocale(LC_ALL, L"");
+ wcslwr(m_TextPatternString);
+ }
+
+ if(0 == M->GetTString(0, "Chat", "HighlightNames", &dbv))
+ m_NickPatternString = dbv.ptszVal;
+
+ m_dwFlags = M->GetByte("Chat", "HighlightEnabled", MATCH_TEXT);
+ m_fHighlightMe = (M->GetByte("Chat", "HighlightMe", 1) ? true : false);
+
+ __try {
+ tokenize(m_TextPatternString, m_TextPatterns, m_iTextPatterns);
+ tokenize(m_NickPatternString, m_NickPatterns, m_iNickPatterns);
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"MUC_HLT_TOKENIZER", false)) {
+ m_Valid = false;
+ }
+}
+
+void CMUCHighlight::tokenize(TCHAR *tszString, TCHAR**& patterns, UINT& nr)
+{
+ if(tszString == 0)
+ return;
+
+ TCHAR *p = tszString;
+
+ if(*p == 0)
+ return;
+
+ nr = 0;
+
+ if(*p != ' ')
+ nr++;
+
+ while(*p) {
+ if(*p == ' ') {
+ p++;
+ while(*p && _istspace(*p))
+ p++;
+ if(*p)
+ nr++;
+ }
+ p++;
+ }
+ patterns = (TCHAR **)mir_alloc(nr * sizeof(TCHAR *));
+
+ p = tszString;
+ nr = 0;
+
+ if(*p != ' ')
+ patterns[nr++] = p;
+
+ while(*p) {
+ if(*p == ' ') {
+ *p++ = 0;
+ while(*p && _istspace(*p))
+ p++;
+ if(*p)
+ patterns[nr++] = p;
+ }
+ p++;
+ }
+}
+
+int CMUCHighlight::match(const GCEVENT *pgce, const SESSION_INFO *psi, DWORD dwFlags)
+{
+ int result = 0, nResult = 0;
+
+ if(pgce == 0 || m_Valid == false)
+ return(0);
+
+ __try {
+ if((m_dwFlags & MATCH_TEXT) && (dwFlags & MATCH_TEXT) && (m_fHighlightMe || m_iTextPatterns > 0) && psi != 0) {
+ #ifdef __HLT_PERFSTATS
+ int words = 0;
+ M->startTimer();
+ #endif
+ TCHAR *tszCleaned = ::RemoveFormatting(pgce->ptszText, true, true);
+ TCHAR *p = tszCleaned;
+ TCHAR *p1;
+ UINT i = 0;
+
+ TCHAR *tszMe = ((psi && psi->pMe) ? mir_tstrdup(psi->pMe->pszNick) : 0);
+ if(tszMe) {
+ _wsetlocale(LC_ALL, L"");
+ wcslwr(tszMe);
+ }
+
+ if(m_fHighlightMe && tszMe) {
+ result = wcsstr(p, tszMe) ? MATCH_TEXT : 0;
+ if(0 == m_iTextPatterns)
+ goto skip_textpatterns;
+ }
+ while(p && !result) {
+ while(*p && (*p == ' ' || *p == ',' || *p == '.' || *p == ':' || *p == ';' || *p == '?' || *p == '!'))
+ p++;
+
+ if(*p) {
+ p1 = p;
+ while(*p1 && *p1 != ' ' && *p1 != ',' && *p1 != '.' && *p1 != ':' && *p1 != ';' && *p1 != '?' && *p1 != '!')
+ p1++;
+
+ if(*p1)
+ *p1 = 0;
+ else
+ p1 = 0;
+
+ for(i = 0; i < m_iTextPatterns && !result; i++)
+ result = wildmatch(m_TextPatterns[i], p) ? MATCH_TEXT : 0;
+
+ if(p1) {
+ *p1 = ' ';
+ p = p1 + 1;
+ }
+ else
+ p = 0;
+ #ifdef __HLT_PERFSTATS
+ words++;
+ #endif
+ }
+ else
+ break;
+ }
+skip_textpatterns:
+
+ #ifdef __HLT_PERFSTATS
+ M->stopTimer(0);
+ if(psi && psi->dat) {
+ mir_sntprintf(psi->dat->szStatusBar, 100, _T("PERF text match: %d ticks = %f msec (%d words, %d patterns)"), (int)M->getTicks(), M->getMsec(), words, m_iTextPatterns);
+ if(psi->dat->pContainer->hwndStatus)
+ ::SendMessage(psi->dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)psi->dat->szStatusBar);
+ }
+ #endif
+ if(tszMe)
+ mir_free(tszMe);
+ }
+
+ /*
+ * optinally, match the nickname against the list of nicks to highlight
+ */
+ if((m_dwFlags & MATCH_NICKNAME) && (dwFlags & MATCH_NICKNAME) && pgce->ptszNick && m_iNickPatterns > 0) {
+ for(UINT i = 0; i < m_iNickPatterns && !nResult; i++) {
+ if(pgce->ptszNick)
+ nResult = wildmatch(m_NickPatterns[i], pgce->ptszNick) ? MATCH_NICKNAME : 0;
+ if((m_dwFlags & MATCH_UIN) && pgce->ptszUserInfo)
+ nResult = wildmatch(m_NickPatterns[i], pgce->ptszUserInfo) ? MATCH_NICKNAME : 0;
+ }
+ }
+
+ return(result | nResult);
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"MUC_HIGHLIGHT_EXCEPTION", false)) {
+ m_Valid = false;
+ return(0);
+ }
+ return(0);
+}
+
+int CMUCHighlight::wildmatch(const TCHAR *pattern, const TCHAR *tszString) {
+
+ const TCHAR *cp = 0, *mp = 0;
+
+ while ((*tszString) && (*pattern != '*')) {
+ if ((*pattern != *tszString) && (*pattern != '?')) {
+ return 0;
+ }
+ pattern++;
+ tszString++;
+ }
+
+ while (*tszString) {
+ if (*pattern == '*') {
+ if (!*++pattern)
+ return 1;
+ mp = pattern;
+ cp = tszString + 1;
+ }
+ else if ((*pattern == *tszString) || (*pattern == '?')) {
+ pattern++;
+ tszString++;
+ }
+ else {
+ pattern = mp;
+ tszString = cp++;
+ }
+ }
+
+ while (*pattern == '*')
+ pattern++;
+
+ return(!*pattern);
+}
+
+/**
+ * Dialog procedure to handle global highlight settings
+ *
+ * @param Standard Windows dialog procedure parameters
+ */
+
+INT_PTR CALLBACK CMUCHighlight::dlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG: {
+ DBVARIANT dbv = {0};
+
+ TranslateDialogDefault(hwndDlg);
+
+ if(0 == M->GetTString(0, "Chat", "HighlightWords", &dbv)) {
+ ::SetDlgItemTextW(hwndDlg, IDC_HIGHLIGHTTEXTPATTERN, dbv.ptszVal);
+ ::DBFreeVariant(&dbv);
+ }
+
+ if(0 == M->GetTString(0, "Chat", "HighlightNames", &dbv)) {
+ ::SetDlgItemTextW(hwndDlg, IDC_HIGHLIGHTNICKPATTERN, dbv.ptszVal);
+ ::DBFreeVariant(&dbv);
+ }
+
+ DWORD dwFlags = M->GetByte("Chat", "HighlightEnabled", MATCH_TEXT);
+
+ ::CheckDlgButton(hwndDlg, IDC_HIGHLIGHTNICKENABLE, dwFlags & MATCH_NICKNAME ? BST_CHECKED : BST_UNCHECKED);
+ ::CheckDlgButton(hwndDlg, IDC_HIGHLIGHTNICKUID, dwFlags & MATCH_UIN ? BST_CHECKED : BST_UNCHECKED);
+ ::CheckDlgButton(hwndDlg, IDC_HIGHLIGHTTEXTENABLE, dwFlags & MATCH_TEXT ? BST_CHECKED : BST_UNCHECKED);
+ ::CheckDlgButton(hwndDlg, IDC_HIGHLIGHTME, M->GetByte("Chat", "HighlightMe", 1) ? BST_CHECKED : BST_UNCHECKED);
+
+ ::SendMessageW(hwndDlg, WM_USER + 100, 0, 0);
+ return(TRUE);
+ }
+
+ case WM_USER + 100:
+ Utils::enableDlgControl(hwndDlg, IDC_HIGHLIGHTTEXTPATTERN,
+ ::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTTEXTENABLE) ? TRUE : FALSE);
+
+ Utils::enableDlgControl(hwndDlg, IDC_HIGHLIGHTNICKPATTERN,
+ ::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTNICKENABLE) ? TRUE : FALSE);
+
+ Utils::enableDlgControl(hwndDlg, IDC_HIGHLIGHTNICKUID,
+ ::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTNICKENABLE) ? TRUE : FALSE);
+
+ Utils::enableDlgControl(hwndDlg, IDC_HIGHLIGHTME,
+ ::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTTEXTENABLE) ? TRUE : FALSE);
+ return(FALSE);
+
+ case WM_COMMAND:
+ if ((LOWORD(wParam) == IDC_HIGHLIGHTNICKPATTERN
+ || LOWORD(wParam) == IDC_HIGHLIGHTTEXTPATTERN)
+ && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != ::GetFocus()))
+ return 0;
+
+ ::SendMessage(hwndDlg, WM_USER + 100, 0, 0);
+ if (lParam != (LPARAM)NULL)
+ ::SendMessage(::GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY: {
+ wchar_t* szBuf = 0;
+ int iLen = ::GetWindowTextLengthW(::GetDlgItem(hwndDlg, IDC_HIGHLIGHTNICKPATTERN));
+
+ if(iLen) {
+ szBuf = reinterpret_cast<wchar_t *>(mir_alloc((iLen + 2) * sizeof(wchar_t)));
+ ::GetDlgItemTextW(hwndDlg, IDC_HIGHLIGHTNICKPATTERN, szBuf, iLen + 1);
+ M->WriteTString(0, "Chat", "HighlightNames",szBuf);
+ }
+
+ iLen = ::GetWindowTextLengthW(::GetDlgItem(hwndDlg, IDC_HIGHLIGHTTEXTPATTERN));
+ if(iLen) {
+ szBuf = reinterpret_cast<TCHAR *>(mir_realloc(szBuf, sizeof(wchar_t) * (iLen + 2)));
+ ::GetDlgItemTextW(hwndDlg, IDC_HIGHLIGHTTEXTPATTERN, szBuf, iLen + 1);
+ M->WriteTString(0, "Chat", "HighlightWords", szBuf);
+ }
+ else
+ M->WriteTString(0, "Chat", "HighlightWords", L"");
+
+ mir_free(szBuf);
+ BYTE dwFlags = (::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTNICKENABLE) ? MATCH_NICKNAME : 0) |
+ (::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTTEXTENABLE) ? MATCH_TEXT : 0);
+
+ if(dwFlags & MATCH_NICKNAME)
+ dwFlags |= (::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTNICKUID) ? MATCH_UIN : 0);
+
+ M->WriteByte("Chat", "HighlightEnabled", dwFlags);
+ M->WriteByte("Chat", "HighlightMe", ::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTME) ? 1 : 0);
+ g_Settings.Highlight->init();
+ }
+ return TRUE;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+/**
+ * dialog procedure for the small "add user to highlight list" dialog box
+ * TODO: finish it
+ */
+INT_PTR CALLBACK CMUCHighlight::dlgProcAdd(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ UINT uCmd = ::GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch(msg) {
+ case WM_INITDIALOG: {
+ HFONT hFont = (HFONT)::SendDlgItemMessage(hwndDlg, IDC_ADDHIGHLIGHTTITLE, WM_GETFONT, 0, 0);
+ LOGFONTW lf = {0};
+
+ THighLightEdit *the = reinterpret_cast<THighLightEdit *>(lParam);
+ ::SetWindowLongPtr(hwndDlg, GWLP_USERDATA, the->uCmd);
+
+ ::GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ lf.lfHeight = (int)(lf.lfHeight * 1.2);
+ hFont = ::CreateFontIndirectW(&lf);
+
+ ::SendDlgItemMessage(hwndDlg, IDC_ADDHIGHLIGHTTITLE, WM_SETFONT, (WPARAM)hFont, FALSE);
+ if(the->uCmd == THighLightEdit::CMD_ADD) {
+ Utils::showDlgControl(hwndDlg, IDC_ADDHIGHLIGHTEDITLIST, SW_HIDE);
+ ::SetDlgItemTextW(hwndDlg, IDC_ADDHIGHLIGHTTITLE, CTranslator::get(CTranslator::GEN_MUC_HIGHLIGHT_ADD));
+ ::SendDlgItemMessageW(hwndDlg, IDC_ADDHIGHLIGHTNAME, CB_INSERTSTRING, -1, (LPARAM)the->ui->pszNick);
+ ::SendDlgItemMessageW(hwndDlg, IDC_ADDHIGHLIGHTNAME, CB_INSERTSTRING, -1, (LPARAM)the->ui->pszUID);
+ ::SendDlgItemMessageW(hwndDlg, IDC_ADDHIGHLIGHTNAME, CB_SETCURSEL, 1, 0);
+ } else {
+ Utils::showDlgControl(hwndDlg, IDC_ADDHIGHLIGHTNAME, SW_HIDE);
+ Utils::showDlgControl(hwndDlg, IDC_ADDHIGHLIGHTEXPLAIN, SW_HIDE);
+ ::SetDlgItemTextW(hwndDlg, IDC_ADDHIGHLIGHTTITLE, CTranslator::get(CTranslator::GEN_MUC_HIGHLIGHT_EDIT));
+ }
+ break;
+ }
+
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ {
+ HWND hwndChild = (HWND)lParam;
+ UINT id = ::GetDlgCtrlID(hwndChild);
+
+ if(hwndChild == ::GetDlgItem(hwndDlg, IDC_ADDHIGHLIGHTTITLE))
+ ::SetTextColor((HDC)wParam, RGB(60, 60, 150));
+ ::SetBkColor((HDC)wParam, ::GetSysColor(COLOR_WINDOW));
+ return (INT_PTR)::GetSysColorBrush(COLOR_WINDOW);
+ }
+
+ case WM_COMMAND: {
+ if(LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
+ ::DestroyWindow(hwndDlg);
+ break;
+ }
+
+ case WM_DESTROY: {
+ HFONT hFont = (HFONT)::SendDlgItemMessage(hwndDlg, IDC_ADDHIGHLIGHTTITLE, WM_GETFONT, 0, 0);
+ ::DeleteObject(hFont);
+ break;
+ }
+ }
+ return(FALSE);
+}
+
diff --git a/plugins/TabSRMM/chat/muchighlight.h b/plugins/TabSRMM/chat/muchighlight.h
new file mode 100644
index 0000000000..cffac2ad39
--- /dev/null
+++ b/plugins/TabSRMM/chat/muchighlight.h
@@ -0,0 +1,94 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: muchighlight.h 12299 2010-08-10 02:39:36Z silvercircle $
+ *
+ * highlighter class for multi user chats
+ *
+ */
+
+class CMUCHighlight {
+
+public:
+
+ enum {
+ MATCH_TEXT = 1,
+ MATCH_NICKNAME = 2,
+ MATCH_UIN = 4,
+ };
+
+ CMUCHighlight()
+ {
+ m_fInitialized = false;
+ m_TextPatternString = m_NickPatternString = 0;
+ m_NickPatterns = m_TextPatterns = 0;
+ m_iNickPatterns = m_iTextPatterns = 0;
+ m_dwFlags = 0;
+ m_Valid = true;
+ init();
+ }
+
+ ~CMUCHighlight()
+ {
+ cleanup();
+ }
+
+ void init ();
+ void cleanup ();
+ int match (const GCEVENT *pgce, const SESSION_INFO *psi,
+ DWORD dwFlags = MATCH_NICKNAME);
+
+ static INT_PTR CALLBACK dlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); // option page dlg proc
+ static INT_PTR CALLBACK dlgProcAdd (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); // for the "add to" dialog
+private:
+ void tokenize(TCHAR *tszString, TCHAR**& patterns, UINT& nr);
+ int wildmatch (const TCHAR *pattern, const TCHAR *tszString);
+ DWORD m_dwFlags;
+ bool m_fInitialized;
+ TCHAR** m_NickPatterns;
+ TCHAR** m_TextPatterns;
+ UINT m_iNickPatterns;
+ UINT m_iTextPatterns;
+ TCHAR* m_NickPatternString;
+ TCHAR* m_TextPatternString;
+ bool m_Valid;
+ bool m_fHighlightMe;
+};
+
+struct THighLightEdit
+{
+ enum {
+ CMD_ADD = 1,
+ CMD_EDIT = 2
+ };
+
+ UINT uCmd;
+ SESSION_INFO *si;
+ USERINFO *ui;
+};
+
diff --git a/plugins/TabSRMM/chat/options.cpp b/plugins/TabSRMM/chat/options.cpp
new file mode 100644
index 0000000000..e3e40db2ac
--- /dev/null
+++ b/plugins/TabSRMM/chat/options.cpp
@@ -0,0 +1,1496 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * This code is based on and still contains large parts of the the
+ * original chat module for Miranda IM, written and copyrighted
+ * by Joergen Persson in 2005.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: options.cpp 13412 2011-03-08 19:13:11Z george.hazan $
+ *
+ * group chat options and generic font handling
+ *
+ */
+
+#include "../src/commonheaders.h"
+#undef Translate
+
+#define TranslateA(s) ((char*)CallService(MS_LANGPACK_TRANSLATESTRING,0,(LPARAM)(s)))
+#include <shlobj.h>
+#include <shlwapi.h>
+
+extern HBRUSH hListBkgBrush;
+extern HICON hIcons[30];
+extern FONTINFO aFonts[OPTIONS_FONTCOUNT];
+extern HMODULE g_hIconDLL;
+
+extern HIMAGELIST CreateStateImageList();
+
+HANDLE g_hOptions = NULL;
+
+
+#define FONTF_BOLD 1
+#define FONTF_ITALIC 2
+
+struct FontOptionsList {
+ TCHAR* szDescr;
+ COLORREF defColour;
+ TCHAR* szDefFace;
+ BYTE defCharset, defStyle;
+ char defSize;
+ COLORREF colour;
+ TCHAR szFace[LF_FACESIZE];
+ BYTE charset, style;
+ char size;
+};
+
+struct ColorOptionsList {
+ int order;
+ TCHAR* tszGroup;
+ TCHAR* tszName;
+ char* szSetting;
+ COLORREF def;
+};
+
+/*
+ * note: bits 24-31 in default color indicates that color is a system color index
+ * (GetSysColor(default_color & 0x00ffffff)), not a rgb value.
+ */
+static ColorOptionsList _clrs[] = {
+ 0, LPGENT("TabSRMM/Group Chats"), LPGENT("Group chat log background"), SRMSGSET_BKGCOLOUR_MUC, SRMSGDEFSET_BKGCOLOUR,
+ 1, LPGENT("TabSRMM"), LPGENT("Input area background"), "inputbg", SRMSGDEFSET_BKGCOLOUR,
+ 2, LPGENT("TabSRMM"), LPGENT("Log background"), SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR,
+ 0, LPGENT("TabSRMM/Single Messaging"), LPGENT("Outgoing background"), "outbg", SRMSGDEFSET_BKGOUTCOLOUR,
+ 1, LPGENT("TabSRMM/Single Messaging"), LPGENT("Incoming background"), "inbg", SRMSGDEFSET_BKGINCOLOUR,
+ 2, LPGENT("TabSRMM/Single Messaging"), LPGENT("Status background"), "statbg", SRMSGDEFSET_BKGCOLOUR,
+ 3, LPGENT("TabSRMM/Single Messaging"), LPGENT("Incoming background(old)"), "oldinbg", SRMSGDEFSET_BKGINCOLOUR,
+ 4, LPGENT("TabSRMM/Single Messaging"), LPGENT("Outgoing background(old)"), "oldoutbg", SRMSGDEFSET_BKGOUTCOLOUR,
+ 5, LPGENT("TabSRMM/Single Messaging"), LPGENT("Horizontal Grid Lines"), "hgrid", RGB(224, 224, 224),
+ 0, LPGENT("TabSRMM/Info Panel"), LPGENT("Panel background low"), "ipfieldsbg", 0x62caff,
+ 1, LPGENT("TabSRMM/Info Panel"), LPGENT("Panel background high"), "ipfieldsbgHigh", 0xf0f0f0,
+ 0, LPGENT("TabSRMM/Common colors"), LPGENT("Toolbar background high"), "tbBgHigh", 0,
+ 1, LPGENT("TabSRMM/Common colors"), LPGENT("Toolbar background low"), "tbBgLow", 0,
+ 2, LPGENT("TabSRMM/Common colors"), LPGENT("Window fill color"), "fillColor", 0,
+ 3, LPGENT("TabSRMM/Common colors"), LPGENT("Text area borders"), "cRichBorders", 0,
+ 4, LPGENT("TabSRMM/Common colors"), LPGENT("Aero glow effect"), "aeroGlow", RGB(40, 40, 255),
+ 4, LPGENT("TabSRMM/Common colors"), LPGENT("Generic text color (only when fill color is set)"), "genericTxtClr", 0xff000000 | COLOR_BTNTEXT,
+};
+
+static ColorOptionsList _tabclrs[] = {
+ 0, LPGENT("TabSRMM/Tabs"), LPGENT("Normal text"), "tab_txt_normal", 0xff000000 | COLOR_BTNTEXT,
+ 1, LPGENT("TabSRMM/Tabs"), LPGENT("Active text"), "tab_txt_active", 0xff000000 | COLOR_BTNTEXT,
+ 2, LPGENT("TabSRMM/Tabs"), LPGENT("Hovered text"), "tab_txt_hottrack", 0xff000000 | COLOR_HOTLIGHT,
+ 3, LPGENT("TabSRMM/Tabs"), LPGENT("Unread text"), "tab_txt_unread", 0xff000000 | COLOR_HOTLIGHT,
+
+ 4, LPGENT("TabSRMM/Tabs"), LPGENT("Normal background"), "tab_bg_normal", 0xff000000 | COLOR_3DFACE,
+ 5, LPGENT("TabSRMM/Tabs"), LPGENT("Active background"), "tab_bg_active", 0xff000000 | COLOR_3DFACE,
+ 6, LPGENT("TabSRMM/Tabs"), LPGENT("Hovered background"), "tab_bg_hottrack", 0xff000000 | COLOR_3DFACE,
+ 7, LPGENT("TabSRMM/Tabs"), LPGENT("Unread background"), "tab_bg_unread", 0xff000000 | COLOR_3DFACE
+};
+
+extern LOGFONT lfDefault;
+
+//remember to put these in the Translate( ) template file too
+static FontOptionsList CHAT_fontOptionsList[] = {
+ {LPGENT("Timestamp"), RGB(50, 50, 240), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Others nicknames"), RGB(0, 0, 192), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {LPGENT("Your nickname"), RGB(0, 0, 192), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {LPGENT("User has joined"), RGB(90, 160, 90), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("User has left"), RGB(160, 160, 90), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("User has disconnected"), RGB(160, 90, 90), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("User kicked ..."), RGB(100, 100, 100), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("User is now known as ..."), RGB(90, 90, 160), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Notice from user"), RGB(160, 130, 60), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Incoming message"), RGB(90, 90, 90), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Outgoing message"), RGB(90, 90, 90), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("The topic is ..."), RGB(70, 70, 160), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Information messages"), RGB(130, 130, 195), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("User enables status for ..."), RGB(70, 150, 70), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("User disables status for ..."), RGB(150, 70, 70), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Action message"), RGB(160, 90, 160), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Highlighted message"), RGB(180, 150, 80), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Chat log symbols (Webdings)"), RGB(170, 170, 170), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("User list members (Online)"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("User list members (away)"), RGB(170, 170, 170), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+};
+
+const int msgDlgFontCount = SIZEOF(CHAT_fontOptionsList);
+
+static FontOptionsList IM_fontOptionsList[] = {
+ {LPGENT(">> Outgoing messages"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT(">> Outgoing misc events"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("<< Incoming messages"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("<< Incoming misc events"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT(">> Outgoing name"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {LPGENT(">> Outgoing timestamp"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {LPGENT("<< Incoming name"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {LPGENT("<< Incoming timestamp"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {LPGENT(">> Outgoing messages (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT(">> Outgoing misc events (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("<< Incoming messages (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("<< Incoming misc events (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT(">> Outgoing name (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {LPGENT(">> Outgoing timestamp (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {LPGENT("<< Incoming name (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {LPGENT("<< Incoming timestamp (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12},
+ {LPGENT("* Message Input Area"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("* Status changes"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("* Dividers"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("* Error and warning Messages"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("* Symbols (incoming)"), RGB(50, 50, 50), _T("Webdings"), SYMBOL_CHARSET, 0, -12},
+ {LPGENT("* Symbols (outgoing)"), RGB(50, 50, 50), _T("Webdings"), SYMBOL_CHARSET, 0, -12},
+};
+
+static FontOptionsList IP_fontOptionsList[] = {
+ {LPGENT("Nickname"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("UIN"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Status"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Protocol"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Contacts local time"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+ {LPGENT("Window caption (skinned mode)"), RGB(255, 255, 255), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12},
+};
+
+static FontOptionsList *fontOptionsList = IM_fontOptionsList;
+static int fontCount = MSGDLGFONTCOUNT;
+
+struct branch_t {
+ TCHAR* szDescr;
+ char* szDBName;
+ int iMode;
+ BYTE bDefault;
+ HTREEITEM hItem;
+};
+static struct branch_t branch1[] = {
+ {LPGENT("Open new chat rooms in the default container"), "DefaultContainer", 0, 1, NULL},
+ {LPGENT("Flash window when someone speaks"), "FlashWindow", 0, 0, NULL},
+ {LPGENT("Flash window when a word is highlighted"), "FlashWindowHighlight", 0, 1, NULL},
+//TODO Fix for 3.0 !!!
+
+#if !defined(__DELAYED_FOR_3_1)
+ {LPGENT("Create tabs or windows for highlight events"), "CreateWindowOnHighlight", 0,0, NULL},
+ {LPGENT("Activate chat window on highlight"), "AnnoyingHighlight", 0,0, NULL},
+#endif
+
+ {LPGENT("Show list of users in the chat room"), "ShowNicklist", 0, 1, NULL},
+ {LPGENT("Colorize nicknames in member list"), "ColorizeNicks", 0, 1, NULL},
+ {LPGENT("Show button menus when right clicking the buttons"), "RightClickFilter", 0, 0, NULL},
+ {LPGENT("Show topic as status message on the contact list"), "TopicOnClist", 0, 1, NULL},
+ {LPGENT("Do not pop up the window when joining a chat room"), "PopupOnJoin", 0, 0, NULL},
+ {LPGENT("Hide or show the window by double click in the contact list"), "ToggleVisibility", 0, 0, NULL},
+ {LPGENT("Sync splitter position with standard IM sessions"), "SyncSplitter", 0, 0, NULL},
+ {LPGENT("Show contact's status modes if supported by the protocol"), "ShowContactStatus", 0, 1, NULL},
+ {LPGENT("Display contact's status icon before user role icon"), "ContactStatusFirst", 0, 0, NULL},
+ //MAD: simple customization improvement
+ {LPGENT("Use IRC style status indicators in the user list"), "ClassicIndicators", 0, 0, NULL},
+ {LPGENT("Use alternative sorting method in member list"), "AlternativeSorting", 0, 1, NULL},
+
+};
+static struct branch_t branch2[] = {
+ {LPGENT("Prefix all events with a timestamp"), "ShowTimeStamp", 0, 1, NULL},
+ {LPGENT("Timestamp only when event time differs"), "ShowTimeStampIfChanged", 0, 0, NULL},
+ {LPGENT("Timestamp has same color as the event"), "TimeStampEventColour", 0, 0, NULL},
+ {LPGENT("Indent the second line of a message"), "LogIndentEnabled", 0, 1, NULL},
+ {LPGENT("Limit user names in the message log to 20 characters"), "LogLimitNames", 0, 1, NULL},
+ {LPGENT("Add a colon (:) to auto-completed user names"), "AddColonToAutoComplete", 0, 1, NULL},
+ {LPGENT("Start private conversation on doubleclick in nick list (insert nick if unchecked)"), "DoubleClick4Privat", 0, 0, NULL},
+ {LPGENT("Strip colors from messages in the log"), "StripFormatting", 0, 0, NULL},
+ {LPGENT("Enable the \'event filter\' for new rooms"), "FilterEnabled", 0, 0, NULL},
+//MAD: simple customization improvement
+ {LPGENT("Use IRC style status indicators in the log"), "LogClassicIndicators", 0,0, NULL},
+//
+ {LPGENT("Allow clickable user names in the message log"), "ClickableNicks", 0, 1, NULL},
+ {LPGENT("Colorize user names in message log"), "ColorizeNicksInLog", 0, 1, NULL},
+ {LPGENT("Scale down icons to 10x10 pixels in the chat log"), "ScaleIcons", 0, 1, NULL},
+ {LPGENT("Place a separator in the log after a window lost its foreground status"), "UseDividers", 0, 1, NULL},
+ {LPGENT("Only place a separator when an incoming event is announced with a popup"), "DividersUsePopupConfig", 0, 1, NULL},
+ {LPGENT("Support the math module plugin"), "MathModSupport", 0, 0, NULL}
+};
+
+static HWND hPathTip = 0;
+
+void LoadMsgDlgFont(int section, int i, LOGFONT *lf, COLORREF* colour, char *szMod)
+{
+ char str[32];
+ int style;
+ DBVARIANT dbv;
+ int j = (i >= 100 ? i - 100 : i);
+
+ struct FontOptionsList *fol = fontOptionsList;
+ switch (section)
+ {
+ case FONTSECTION_CHAT: fol = CHAT_fontOptionsList; break;
+ case FONTSECTION_IM: fol = IM_fontOptionsList; break;
+ case FONTSECTION_IP: fol = IP_fontOptionsList; break;
+ }
+
+ if (colour) {
+ wsprintfA(str, "Font%dCol", i);
+ *colour = M->GetDword(szMod, str, fol[j].defColour);
+ }
+ if (lf) {
+ wsprintfA(str, "Font%dSize", i);
+ lf->lfHeight = (char) M->GetByte(szMod, str, fol[j].defSize);
+ lf->lfWidth = 0;
+ lf->lfEscapement = 0;
+ lf->lfOrientation = 0;
+ wsprintfA(str, "Font%dSty", i);
+ style = M->GetByte(szMod, str, fol[j].defStyle);
+ if(i == MSGFONTID_MESSAGEAREA && section == FONTSECTION_IM && M->GetByte(0, SRMSGMOD_T, "inputFontFix", 1) == 1) {
+ lf->lfWeight = FW_NORMAL;
+ lf->lfItalic = 0;
+ lf->lfUnderline = 0;
+ lf->lfStrikeOut = 0;
+ }
+ else {
+ lf->lfWeight = style & FONTF_BOLD ? FW_BOLD : FW_NORMAL;
+ lf->lfItalic = style & FONTF_ITALIC ? 1 : 0;
+ lf->lfUnderline = style & FONTF_UNDERLINE ? 1 : 0;
+ lf->lfStrikeOut = style & FONTF_STRIKEOUT ? 1 : 0;
+ }
+ wsprintfA(str, "Font%dSet", i);
+ lf->lfCharSet = M->GetByte(szMod, str, fol[j].defCharset);
+ lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf->lfQuality = DEFAULT_QUALITY;
+ lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ wsprintfA(str, "Font%d", i);
+ if ((i == 17 && !strcmp(szMod, CHAT_FONTMODULE)) || ((i == 20 || i == 21) && !strcmp(szMod, FONTMODULE))) {
+ lf->lfCharSet = SYMBOL_CHARSET;
+ lstrcpyn(lf->lfFaceName, _T("Webdings"), SIZEOF(lf->lfFaceName));
+ } else {
+ if (M->GetTString(NULL, szMod, str, &dbv)) {
+ lstrcpy(lf->lfFaceName, fol[j].szDefFace);
+ } else {
+ lstrcpyn(lf->lfFaceName, dbv.ptszVal, SIZEOF(lf->lfFaceName));
+ DBFreeVariant(&dbv);
+ }
+ }
+ }
+}
+
+static HTREEITEM InsertBranch(HWND hwndTree, TCHAR* pszDescr, BOOL bExpanded)
+{
+ TVINSERTSTRUCT tvis;
+
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_TEXT | TVIF_STATE;
+ tvis.item.pszText = TranslateTS(pszDescr);
+ tvis.item.stateMask = (bExpanded ? TVIS_STATEIMAGEMASK | TVIS_EXPANDED : TVIS_STATEIMAGEMASK) | TVIS_BOLD;
+ tvis.item.state = (bExpanded ? INDEXTOSTATEIMAGEMASK(0) | TVIS_EXPANDED : INDEXTOSTATEIMAGEMASK(0)) | TVIS_BOLD;
+ return TreeView_InsertItem(hwndTree, &tvis);
+}
+
+static void FillBranch(HWND hwndTree, HTREEITEM hParent, struct branch_t *branch, int nValues, DWORD defaultval)
+{
+ TVINSERTSTRUCT tvis;
+ int i;
+ int iState;
+
+ if (hParent == 0)
+ return;
+
+ tvis.hParent = hParent;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_TEXT | TVIF_STATE;
+ for (i = 0;i < nValues;i++) {
+ tvis.item.pszText = TranslateTS(branch[i].szDescr);
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ if (branch[i].iMode)
+ iState = ((M->GetDword("Chat", branch[i].szDBName, defaultval) & branch[i].iMode) & branch[i].iMode) != 0 ? 3 : 2;
+ else
+ iState = M->GetByte("Chat", branch[i].szDBName, branch[i].bDefault) != 0 ? 3 : 2;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK(iState);
+ branch[i].hItem = TreeView_InsertItem(hwndTree, &tvis);
+ }
+}
+
+static void SaveBranch(HWND hwndTree, struct branch_t *branch, int nValues)
+{
+ TVITEM tvi;
+ BYTE bChecked;
+ int i;
+ int iState = 0;
+
+ tvi.mask = TVIF_HANDLE | TVIF_STATE;
+ for (i = 0;i < nValues;i++) {
+ tvi.hItem = branch[i].hItem;
+ TreeView_GetItem(hwndTree, &tvi);
+ bChecked = ((tvi.state & TVIS_STATEIMAGEMASK) >> 12 == 2) ? 0 : 1;
+ if (branch[i].iMode) {
+ if (bChecked)
+ iState |= branch[i].iMode;
+ if (iState & GC_EVENT_ADDSTATUS)
+ iState |= GC_EVENT_REMOVESTATUS;
+ M->WriteDword("Chat", branch[i].szDBName, (DWORD)iState);
+ } else M->WriteByte("Chat", branch[i].szDBName, bChecked);
+ }
+}
+
+static void CheckHeading(HWND hwndTree, HTREEITEM hHeading)
+{
+ BOOL bChecked = TRUE;
+ TVITEM tvi;
+
+ if (hHeading == 0)
+ return;
+
+ tvi.mask = TVIF_HANDLE | TVIF_STATE;
+ tvi.hItem = TreeView_GetNextItem(hwndTree, hHeading, TVGN_CHILD);
+ while (tvi.hItem && bChecked) {
+ if (tvi.hItem != branch1[0].hItem && tvi.hItem != branch1[1].hItem) {
+ TreeView_GetItem(hwndTree, &tvi);
+ if (((tvi.state&TVIS_STATEIMAGEMASK) >> 12 == 2))
+ bChecked = FALSE;
+ }
+ tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem);
+ }
+ tvi.stateMask = TVIS_STATEIMAGEMASK;
+ tvi.state = INDEXTOSTATEIMAGEMASK(1); //bChecked ? 3 : 2);
+ tvi.hItem = hHeading;
+ TreeView_SetItem(hwndTree, &tvi);
+}
+
+static void CheckBranches(HWND hwndTree, HTREEITEM hHeading)
+{
+ BOOL bChecked = TRUE;
+ TVITEM tvi;
+
+ if (hHeading == 0)
+ return;
+
+ tvi.mask = TVIF_HANDLE | TVIF_STATE;
+ tvi.hItem = hHeading;
+ TreeView_GetItem(hwndTree, &tvi);
+ if (((tvi.state&TVIS_STATEIMAGEMASK) >> 12 == 3)||((tvi.state & TVIS_STATEIMAGEMASK) >> 12 == 1))
+ bChecked = FALSE;
+
+ tvi.stateMask = TVIS_STATEIMAGEMASK;
+ tvi.state = INDEXTOSTATEIMAGEMASK(bChecked ? 2 : 1);
+ TreeView_SetItem(hwndTree, &tvi);
+ tvi.hItem = TreeView_GetNextItem(hwndTree, hHeading, TVGN_CHILD);
+ while (tvi.hItem) {
+ tvi.state = INDEXTOSTATEIMAGEMASK(bChecked ? 3:2);
+ if (tvi.hItem != branch1[0].hItem && tvi.hItem != branch1[1].hItem)
+ TreeView_SetItem(hwndTree, &tvi);
+ tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem);
+ }
+}
+
+static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData)
+{
+ char szDir[MAX_PATH];
+ switch (uMsg) {
+ case BFFM_INITIALIZED: {
+ const TCHAR *szData = M->getUserDir();
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szData);
+ break;
+ }
+ case BFFM_SELCHANGED:
+ if (SHGetPathFromIDListA((LPITEMIDLIST) lp , szDir))
+ SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)szDir);
+ break;
+ }
+ return 0;
+}
+
+static void LoadLogFonts(void)
+{
+ int i;
+
+ for (i = 0; i < OPTIONS_FONTCOUNT; i++)
+ LoadMsgDlgFont(FONTSECTION_CHAT, i, &aFonts[i].lf, &aFonts[i].color, CHAT_FONTMODULE);
+}
+
+static struct _tagicons { char *szDesc; char *szName; int id; UINT size;} _icons[] = {
+ LPGEN("Window Icon"), "chat_window", IDI_CHANMGR, 16,
+ LPGEN("Icon overlay"), "chat_overlay", IDI_OVERLAY, 16,
+
+ LPGEN("Status 1 (10x10)"), "chat_status0", IDI_STATUS0, 16,
+ LPGEN("Status 2 (10x10)"), "chat_status1", IDI_STATUS1, 16,
+ LPGEN("Status 3 (10x10)"), "chat_status2", IDI_STATUS2, 16,
+ LPGEN("Status 4 (10x10)"), "chat_status3", IDI_STATUS3, 16,
+ LPGEN("Status 5 (10x10)"), "chat_status4", IDI_STATUS4, 16,
+ LPGEN("Status 6 (10x10)"), "chat_status5", IDI_STATUS5, 16,
+ NULL, NULL, -1, 0
+};
+
+static struct _tag1icons { char *szDesc; char *szName; int id; UINT size;} _logicons[] = {
+ LPGEN("Message in (10x10)"), "chat_log_message_in", IDI_MESSAGE, 16,
+ LPGEN("Message out (10x10)"), "chat_log_message_out", IDI_MESSAGEOUT, 16,
+ LPGEN("Action (10x10)"), "chat_log_action", IDI_ACTION, 16,
+ LPGEN("Add Status (10x10)"), "chat_log_addstatus", IDI_ADDSTATUS, 16,
+ LPGEN("Remove Status (10x10)"), "chat_log_removestatus", IDI_REMSTATUS, 16,
+ LPGEN("Join (10x10)"), "chat_log_join", IDI_JOIN, 16,
+ LPGEN("Leave (10x10)"), "chat_log_part", IDI_PART, 16,
+ LPGEN("Quit (10x10)"), "chat_log_quit", IDI_QUIT, 16,
+ LPGEN("Kick (10x10)"), "chat_log_kick", IDI_KICK, 16,
+ LPGEN("Notice (10x10)"), "chat_log_notice", IDI_NOTICE, 16,
+ LPGEN("Nickchange (10x10)"), "chat_log_nick", IDI_NICK, 16,
+ LPGEN("Topic (10x10)"), "chat_log_topic", IDI_TOPIC, 16,
+ LPGEN("Highlight (10x10)"), "chat_log_highlight", IDI_HIGHLIGHT, 16,
+ LPGEN("Information (10x10)"), "chat_log_info", IDI_INFO, 16,
+ NULL, NULL, 0, 0
+};
+
+// add icons to the skinning module
+void Chat_AddIcons(void)
+{
+ if (ServiceExists(MS_SKIN2_ADDICON)) {
+ SKINICONDESC sid = {0};
+ char szFile[MAX_PATH];
+ int i = 0;
+
+ // 16x16 icons
+ sid.cbSize = sizeof(SKINICONDESC);
+ sid.pszSection = TranslateA("TabSRMM/Group chat windows");
+ GetModuleFileNameA(g_hIconDLL, szFile, MAX_PATH);
+ sid.pszDefaultFile = szFile;
+
+ while (_icons[i].szDesc != NULL) {
+ sid.cx = sid.cy = _icons[i].size;
+ sid.pszDescription = _icons[i].szDesc;
+ sid.pszName = _icons[i].szName;
+ sid.iDefaultIndex = -_icons[i].id;
+ CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+ i++;
+ }
+ i = 0;
+ sid.pszSection = TranslateA("TabSRMM/Group chat log");
+ while (_logicons[i].szDesc != NULL) {
+ sid.cx = sid.cy = _logicons[i].size;
+ sid.pszDescription = _logicons[i].szDesc;
+ sid.pszName = _logicons[i].szName;
+ sid.iDefaultIndex = -_logicons[i].id;
+ CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+ i++;
+ }
+ }
+ return;
+}
+
+/*
+ * get icon by name from the core icon library service
+ */
+
+HICON LoadIconEx(int iIndex, char * pszIcoLibName, int iX, int iY)
+{
+ char szTemp[256];
+ mir_snprintf(szTemp, sizeof(szTemp), "chat_%s", pszIcoLibName);
+ return (HICON) CallService(MS_SKIN2_GETICON, 0, (LPARAM)szTemp);
+}
+
+static void InitSetting(TCHAR** ppPointer, char* pszSetting, TCHAR* pszDefault)
+{
+ DBVARIANT dbv;
+ if (!M->GetTString(NULL, "Chat", pszSetting, &dbv)) {
+ replaceStr(ppPointer, dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ } else
+ replaceStr(ppPointer, pszDefault);
+}
+
+#define OPT_FIXHEADINGS (WM_USER+1)
+
+static UINT _o1controls[] = {IDC_CHECKBOXES, IDC_GROUP, IDC_STATIC_ADD, 0};
+
+HWND CreateToolTip(HWND hwndParent, LPTSTR ptszText, LPTSTR ptszTitle)
+{
+ TOOLINFO ti = { 0 };
+ HWND hwndTT;
+ hwndTT = CreateWindowEx(WS_EX_TOPMOST,
+ TOOLTIPS_CLASS, NULL,
+ WS_POPUP | TTS_NOPREFIX,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ hwndParent, NULL, g_hInst, NULL);
+
+ SetWindowPos(hwndTT, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+
+ ti.cbSize = sizeof(TOOLINFO);
+ ti.uFlags = TTF_SUBCLASS | TTF_CENTERTIP;
+ ti.hwnd = hwndParent;
+ ti.hinst = g_hInst;
+ ti.lpszText = ptszText;
+ GetClientRect (hwndParent, &ti.rect);
+ ti.rect.left =- 85;
+
+ SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
+ SendMessage(hwndTT, TTM_SETTITLE, 1, (LPARAM)ptszTitle);
+ return hwndTT;
+}
+
+INT_PTR CALLBACK DlgProcOptions1(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static HTREEITEM hListHeading1 = 0;
+ static HTREEITEM hListHeading2 = 0;
+
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ if (PluginConfig.m_chat_enabled) {
+ HIMAGELIST himlOptions;
+
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHECKBOXES), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHECKBOXES), GWL_STYLE) | TVS_NOHSCROLL | TVS_CHECKBOXES);
+
+ himlOptions = (HIMAGELIST)SendDlgItemMessage(hwndDlg, IDC_CHECKBOXES, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)CreateStateImageList());
+ ImageList_Destroy(himlOptions);
+
+ hListHeading1 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_MUC_OPTHEADER1)), TRUE);
+ hListHeading2 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_MUC_OPTHEADER2)), TRUE);
+
+ FillBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading1, branch1, SIZEOF(branch1), 0x0000);
+ FillBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading2, branch2, SIZEOF(branch2), 0x0000);
+
+ {
+ TCHAR* pszGroup = NULL;
+ InitSetting(&pszGroup, "AddToGroup", _T("Chat rooms"));
+ SetWindowText(GetDlgItem(hwndDlg, IDC_GROUP), pszGroup);
+ mir_free(pszGroup);
+ Utils::showDlgControl(hwndDlg, IDC_STATIC_MESSAGE, SW_HIDE);
+ }
+ } else {
+ int i = 0;
+
+ while (_o1controls[i])
+ Utils::showDlgControl(hwndDlg, _o1controls[i++], SW_HIDE);
+ }
+ break;
+
+ case WM_COMMAND:
+ if ((LOWORD(wParam) == IDC_GROUP)
+ && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return 0;
+
+ if (lParam != (LPARAM)NULL)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_NOTIFY: {
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case IDC_CHECKBOXES:
+ if (((LPNMHDR)lParam)->code == NM_CLICK || (((LPNMHDR)lParam)->code == TVN_KEYDOWN && ((LPNMTVKEYDOWN)lParam)->wVKey == VK_SPACE)) {
+ TVHITTESTINFO hti;
+ hti.pt.x = (short)LOWORD(GetMessagePos());
+ hti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt);
+ if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti) || ((LPNMHDR)lParam)->code == TVN_KEYDOWN) {
+ if (((LPNMHDR)lParam)->code == TVN_KEYDOWN)
+ hti.flags |= TVHT_ONITEMSTATEICON;
+ if (hti.flags&TVHT_ONITEMSTATEICON) {
+ TVITEM tvi = {0};
+
+ tvi.mask = TVIF_HANDLE | TVIF_STATE;
+ tvi.stateMask = TVIS_STATEIMAGEMASK | TVIS_BOLD;
+
+ if (((LPNMHDR)lParam)->code == TVN_KEYDOWN)
+ tvi.hItem = TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom);
+ else
+ tvi.hItem = (HTREEITEM)hti.hItem;
+
+ TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom, &tvi);
+
+ if (tvi.state & TVIS_BOLD && hti.flags & TVHT_ONITEMSTATEICON) {
+ tvi.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_BOLD;
+ SendDlgItemMessageA(hwndDlg, IDC_CHECKBOXES, TVM_SETITEMA, 0, (LPARAM)&tvi);
+ } else if (hti.flags&TVHT_ONITEMSTATEICON) {
+ if (((tvi.state & TVIS_STATEIMAGEMASK) >> 12) == 3) {
+ tvi.state = INDEXTOSTATEIMAGEMASK(1);
+ SendDlgItemMessageA(hwndDlg, IDC_CHECKBOXES, TVM_SETITEMA, 0, (LPARAM)&tvi);
+ }
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ }
+
+ break;
+
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY: {
+ if (PluginConfig.m_chat_enabled) {
+ int iLen;
+ TCHAR *pszText = NULL;
+ BYTE b;
+
+ iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_GROUP));
+ if (iLen > 0) {
+ pszText = (TCHAR *)realloc(pszText, (iLen + 2) * sizeof(TCHAR));
+ GetDlgItemText(hwndDlg, IDC_GROUP, pszText, iLen + 1);
+ M->WriteTString(NULL, "Chat", "AddToGroup", pszText);
+ } else
+ M->WriteTString(NULL, "Chat", "AddToGroup", _T(""));
+
+ g_Settings.hGroup = 0;
+
+ if (pszText)
+ free(pszText);
+
+ b = M->GetByte("Chat", "Tabs", 1);
+ SaveBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), branch1, sizeof(branch1) / sizeof(branch1[0]));
+ SaveBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), branch2, sizeof(branch2) / sizeof(branch2[0]));
+
+ LoadGlobalSettings();
+ MM_FontsChanged();
+ FreeMsgLogBitmaps();
+ LoadMsgLogBitmaps();
+ SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE);
+ SM_ReconfigureFilters();
+ }
+ }
+ return TRUE;
+ }
+ }
+ }
+ break;
+ case WM_DESTROY: {
+ BYTE b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading1, TVIS_EXPANDED) & TVIS_EXPANDED ? 1 : 0;
+ M->WriteByte("Chat", "Branch1Exp", b);
+ b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading2, TVIS_EXPANDED) & TVIS_EXPANDED ? 1 : 0;
+ M->WriteByte("Chat", "Branch2Exp", b);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+static TCHAR* chatcolorsnames[] ={
+// LPGENT("Your nickname"),
+ LPGENT("Channel operators"),
+ LPGENT("Half operators"),
+ LPGENT("Voiced"),
+// LPGENT("Others nicknames"),
+ LPGENT("Extended mode 1"),
+ LPGENT("Extended mode 2"),
+ LPGENT("Selection background"),
+ LPGENT("Selected text"),
+ LPGENT("Incremental search highlight")
+ };
+
+void RegisterFontServiceFonts() {
+ int i;
+ char szTemp[100];
+ LOGFONT lf;
+ FontIDT fid = {0};
+ ColourIDT cid = {0};
+
+ fid.cbSize = sizeof(FontIDT);
+ cid.cbSize = sizeof(ColourIDT);
+
+ strncpy(fid.dbSettingsGroup, FONTMODULE, SIZEOF(fid.dbSettingsGroup));
+
+ for (i = 0; i < SIZEOF(IM_fontOptionsList); i++) {
+ fid.flags = FIDF_DEFAULTVALID|FIDF_ALLOWEFFECTS;
+ LoadMsgDlgFont(FONTSECTION_IM, i , &lf, &fontOptionsList[i].colour, FONTMODULE);
+ mir_snprintf(szTemp, SIZEOF(szTemp), "Font%d", i);
+ strncpy(fid.prefix, szTemp, SIZEOF(fid.prefix));
+ fid.order = i;
+ _tcsncpy(fid.name, fontOptionsList[i].szDescr, SIZEOF(fid.name));
+ fid.deffontsettings.colour = fontOptionsList[i].colour;
+ fid.deffontsettings.size = (char) lf.lfHeight;
+ fid.deffontsettings.style = (lf.lfWeight >= FW_BOLD ? FONTF_BOLD : 0) | (lf.lfItalic ? FONTF_ITALIC : 0);
+ fid.deffontsettings.charset = lf.lfCharSet;
+ fid.flags = fid.flags & ~FIDF_CLASSMASK | (fid.deffontsettings.style&FONTF_BOLD ? FIDF_CLASSHEADER : FIDF_CLASSGENERAL);
+ _tcsncpy(fid.deffontsettings.szFace, lf.lfFaceName, LF_FACESIZE);
+ _tcsncpy(fid.backgroundGroup, _T("TabSRMM/Single Messaging"), SIZEOF(fid.backgroundGroup));
+ _tcsncpy(fid.group, _T("TabSRMM/Single Messaging"), SIZEOF(fid.group));
+ switch (i) {
+ case MSGFONTID_MYMSG:
+ case 1:
+ case MSGFONTID_MYNAME:
+ case MSGFONTID_MYTIME:
+ case 21:
+ _tcsncpy(fid.backgroundName, _T("Outgoing background"), SIZEOF(fid.backgroundName));
+ break;
+ case 8:
+ case 9:
+ case 12:
+ case 13:
+ _tcsncpy(fid.backgroundName, _T("Outgoing background(old)"), SIZEOF(fid.backgroundName));
+ break;
+ case 10:
+ case 11:
+ case 14:
+ case 15:
+ _tcsncpy(fid.backgroundName, _T("Incoming background(old)"), SIZEOF(fid.backgroundName));
+ break;
+ case MSGFONTID_MESSAGEAREA:
+ _tcsncpy(fid.group, _T("TabSRMM"), SIZEOF(fid.group));
+ _tcsncpy(fid.backgroundGroup, _T("TabSRMM"), SIZEOF(fid.backgroundGroup));
+ _tcsncpy(fid.backgroundName, _T("Input area background"), SIZEOF(fid.backgroundName));
+ fid.flags |= FIDF_DISABLESTYLES;
+ fid.flags &= ~FIDF_ALLOWEFFECTS;
+ break;
+ case 17:
+ _tcsncpy(fid.backgroundName, _T("Status background"), SIZEOF(fid.backgroundName));
+ break;
+ case 18:
+ _tcsncpy(fid.backgroundGroup, _T("TabSRMM"), SIZEOF(fid.backgroundGroup));
+ _tcsncpy(fid.backgroundName, _T("Log background"), SIZEOF(fid.backgroundName));
+ break;
+ case 19:
+ _tcsncpy(fid.backgroundName, _T(""), SIZEOF(fid.backgroundName));
+ break;
+ default:
+ _tcsncpy(fid.backgroundName, _T("Incoming background"), SIZEOF(fid.backgroundName));
+ break;
+ }
+ CallService(MS_FONT_REGISTERT, (WPARAM)&fid, 0);
+ }
+
+ fontOptionsList = IP_fontOptionsList;
+ fid.flags = FIDF_DEFAULTVALID|FIDF_ALLOWEFFECTS;
+ //fid.flags|=FIDF_SAVEPOINTSIZE;
+ _tcsncpy(fid.group, _T("TabSRMM/Info Panel"), SIZEOF(fid.group));
+ _tcsncpy(fid.backgroundGroup, _T("TabSRMM/Info Panel"), SIZEOF(fid.backgroundGroup));
+ _tcsncpy(fid.backgroundName, _T("Fields background"), SIZEOF(fid.backgroundName));
+ for (i =0; i < IPFONTCOUNT; i++) {
+ LoadMsgDlgFont(FONTSECTION_IP, i + 100 , &lf, &fontOptionsList[i].colour, FONTMODULE);
+ mir_snprintf(szTemp, SIZEOF(szTemp), "Font%d", i + 100);
+ strncpy(fid.prefix, szTemp, SIZEOF(fid.prefix));
+ fid.order = i + 100 ;
+ _tcsncpy(fid.name, fontOptionsList[i].szDescr, SIZEOF(fid.name));
+ fid.deffontsettings.colour = fontOptionsList[i].colour;
+ fid.deffontsettings.size = (char) lf.lfHeight;
+ fid.deffontsettings.style = (lf.lfWeight >= FW_BOLD ? FONTF_BOLD : 0) | (lf.lfItalic ? FONTF_ITALIC : 0);
+ fid.deffontsettings.charset = lf.lfCharSet;
+ fid.flags = fid.flags & ~FIDF_CLASSMASK | (fid.deffontsettings.style&FONTF_BOLD ? FIDF_CLASSHEADER : FIDF_CLASSGENERAL);
+ fid.deffontsettings.charset = lf.lfCharSet;
+ _tcsncpy(fid.deffontsettings.szFace, lf.lfFaceName, LF_FACESIZE);
+ if(i==IPFONTCOUNT-1){
+ _tcsncpy(fid.backgroundGroup, _T(""), SIZEOF(fid.backgroundGroup));
+ _tcsncpy(fid.backgroundName, _T(""), SIZEOF(fid.backgroundName));
+ _tcsncpy(fid.group, _T("TabSRMM"), SIZEOF(fid.group));
+ }
+ CallService(MS_FONT_REGISTERT, (WPARAM)&fid, 0);
+ }
+
+ fontOptionsList = CHAT_fontOptionsList;
+ fid.flags = FIDF_DEFAULTVALID|FIDF_ALLOWEFFECTS;
+ fid.flags&=~FIDF_SAVEPOINTSIZE;
+ _tcsncpy(fid.group, _T("TabSRMM/Group Chats"), SIZEOF(fid.group));
+ strncpy(fid.dbSettingsGroup, CHAT_FONTMODULE, SIZEOF(fid.dbSettingsGroup));
+ for (i = 0; i < msgDlgFontCount; i++) {
+ LoadMsgDlgFont(FONTSECTION_CHAT, i , &lf, &fontOptionsList[i].colour, CHAT_FONTMODULE);
+ mir_snprintf(szTemp, SIZEOF(szTemp), "Font%d", i);
+ strncpy(fid.prefix, szTemp, SIZEOF(fid.prefix));
+ fid.order = i;
+ _tcsncpy(fid.name, fontOptionsList[i].szDescr, SIZEOF(fid.name));
+ fid.deffontsettings.colour = fontOptionsList[i].colour;
+ fid.deffontsettings.size = (char) lf.lfHeight;
+ fid.deffontsettings.style = (lf.lfWeight >= FW_BOLD ? FONTF_BOLD : 0) | (lf.lfItalic ? FONTF_ITALIC : 0);
+ fid.flags = fid.flags & ~FIDF_CLASSMASK | (fid.deffontsettings.style&FONTF_BOLD ? FIDF_CLASSHEADER : FIDF_CLASSGENERAL);
+ fid.deffontsettings.charset = lf.lfCharSet;
+ _tcsncpy(fid.deffontsettings.szFace, lf.lfFaceName, LF_FACESIZE);
+ _tcsncpy(fid.backgroundGroup, _T("TabSRMM/Group Chats"), SIZEOF(fid.backgroundGroup));
+ _tcsncpy(fid.backgroundName, _T("Group chat log background"), SIZEOF(fid.backgroundName));
+ if(i == 18 || i == 19)
+ _tcsncpy(fid.backgroundName, _T("Userlist background"), SIZEOF(fid.backgroundName));
+ CallService(MS_FONT_REGISTERT, (WPARAM)&fid, 0);
+ }
+
+ _tcsncpy(cid.group, _T("TabSRMM/Group Chats"), SIZEOF(cid.group));
+ strncpy(cid.dbSettingsGroup, "Chat", SIZEOF(cid.dbSettingsGroup));
+ for (i = 0; i <= 7; i++) {
+ mir_snprintf(szTemp, SIZEOF(szTemp), "NickColor%d", i);
+ _tcsncpy(cid.name, chatcolorsnames[i], SIZEOF(cid.name));
+ cid.order=i+1;
+ strncpy(cid.setting, szTemp, SIZEOF(cid.setting));
+ switch (i) {
+ case 5:
+ cid.defcolour = GetSysColor(COLOR_HIGHLIGHT);
+ break;
+ case 6:
+ cid.defcolour = GetSysColor(COLOR_HIGHLIGHTTEXT);
+ break;
+ default:
+ cid.defcolour =RGB(0, 0, 0);
+ break;
+ }
+ CallService(MS_COLOUR_REGISTERT, (WPARAM)&cid, 0);
+ }
+ cid.order=8;
+ _tcsncpy(cid.name, _T("Userlist background"), SIZEOF(cid.name));
+ strncpy(cid.setting, "ColorNicklistBG", SIZEOF(cid.setting));
+ cid.defcolour = SRMSGDEFSET_BKGCOLOUR;
+ CallService(MS_COLOUR_REGISTERT, (WPARAM)&cid, 0);
+
+ /*
+ * static colors (info panel, tool bar background etc...)
+ */
+ strncpy(fid.dbSettingsGroup, FONTMODULE, SIZEOF(fid.dbSettingsGroup));
+ strncpy(cid.dbSettingsGroup, FONTMODULE, SIZEOF(fid.dbSettingsGroup));
+
+ for(i = 0; i < (sizeof(_clrs) / sizeof(_clrs[0])); i++) {
+ cid.order = _clrs[i].order;
+ _tcsncpy(cid.group, _clrs[i].tszGroup, SIZEOF(fid.group));
+ _tcsncpy(cid.name, _clrs[i].tszName, SIZEOF(cid.name));
+ strncpy(cid.setting, _clrs[i].szSetting, SIZEOF(cid.setting));
+ if(_clrs[i].def & 0xff000000)
+ cid.defcolour = GetSysColor(_clrs[i].def & 0x000000ff);
+ else
+ cid.defcolour = _clrs[i].def;
+ CallService(MS_COLOUR_REGISTERT, (WPARAM)&cid, 0);
+ }
+
+ strncpy(cid.dbSettingsGroup, SRMSGMOD_T, SIZEOF(fid.dbSettingsGroup));
+
+ /*
+ * text and background colors for tabs
+ */
+ for(i = 0; i < (sizeof(_tabclrs) / sizeof(_tabclrs[0])); i++) {
+ cid.order = _tabclrs[i].order;
+ _tcsncpy(cid.group, _tabclrs[i].tszGroup, SIZEOF(fid.group));
+ _tcsncpy(cid.name, _tabclrs[i].tszName, SIZEOF(cid.name));
+ strncpy(cid.setting, _tabclrs[i].szSetting, SIZEOF(cid.setting));
+ if(_tabclrs[i].def & 0xff000000)
+ cid.defcolour = GetSysColor(_tabclrs[i].def & 0x000000ff);
+ else
+ cid.defcolour = _tabclrs[i].def;
+
+ CallService(MS_COLOUR_REGISTERT, (WPARAM)&cid, 0);
+ }
+}
+
+int FontServiceFontsChanged(WPARAM wParam, LPARAM lParam)
+{
+ if (PluginConfig.m_chat_enabled) {
+ LOGFONT lf;
+ HFONT hFont;
+ int iText;
+
+ LoadLogFonts();
+ FreeMsgLogBitmaps();
+ LoadMsgLogBitmaps();
+
+ LoadMsgDlgFont(FONTSECTION_CHAT, 0, &lf, NULL, CHAT_FONTMODULE);
+ hFont = CreateFontIndirect(&lf);
+ iText = GetTextPixelSize(MakeTimeStamp(g_Settings.pszTimeStamp, time(NULL)), hFont, TRUE);
+ DeleteObject(hFont);
+ g_Settings.LogTextIndent = iText;
+ g_Settings.LogTextIndent = g_Settings.LogTextIndent * 12 / 10;
+ g_Settings.LogIndentEnabled = (M->GetByte("Chat", "LogIndentEnabled", 1) != 0) ? TRUE : FALSE;
+
+ LoadGlobalSettings();
+ MM_FontsChanged();
+ MM_FixColors();
+ SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE);
+ }
+
+ PluginConfig.reloadSettings();
+ CSkin::initAeroEffect();
+ CacheMsgLogIcons();
+ CacheLogFonts();
+ FreeTabConfig();
+ ReloadTabConfig();
+ Skin->setupAeroSkins();
+ M->BroadcastMessage(DM_OPTIONSAPPLIED, 1, 0);
+ return 0;
+}
+
+
+static UINT _o2chatcontrols[] = { IDC_CHAT_SPIN2, IDC_LIMIT, IDC_CHAT_SPIN4, IDC_LOGTIMESTAMP, IDC_TIMESTAMP,
+ IDC_OUTSTAMP, IDC_FONTCHOOSE, IDC_LOGGING, IDC_LOGDIRECTORY, IDC_INSTAMP, IDC_CHAT_SPIN2, IDC_CHAT_SPIN3, IDC_NICKROW2, IDC_LOGLIMIT,
+ IDC_STATIC110, IDC_STATIC112, 0};
+
+static UINT _o3chatcontrols[] = {0};
+
+INT_PTR CALLBACK DlgProcOptions2(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg) {
+ case WM_INITDIALOG: {
+
+ TranslateDialogDefault(hwndDlg);
+
+ if (PluginConfig.m_chat_enabled) {
+
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN2, UDM_SETRANGE, 0, MAKELONG(5000, 0));
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN2, UDM_SETPOS, 0, MAKELONG(DBGetContactSettingWord(NULL, "Chat", "LogLimit", 100), 0));
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN3, UDM_SETRANGE, 0, MAKELONG(255, 10));
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN3, UDM_SETPOS, 0, MAKELONG(M->GetByte("Chat", "NicklistRowDist", 12), 0));
+ SetDlgItemText(hwndDlg, IDC_LOGTIMESTAMP, g_Settings.pszTimeStampLog);
+ SetDlgItemText(hwndDlg, IDC_TIMESTAMP, g_Settings.pszTimeStamp);
+ SetDlgItemText(hwndDlg, IDC_OUTSTAMP, g_Settings.pszOutgoingNick);
+ SetDlgItemText(hwndDlg, IDC_INSTAMP, g_Settings.pszIncomingNick);
+ CheckDlgButton(hwndDlg, IDC_LOGGING, g_Settings.LoggingEnabled);
+ SetDlgItemText(hwndDlg, IDC_LOGDIRECTORY, g_Settings.pszLogDir);
+ Utils::enableDlgControl(hwndDlg, IDC_LOGDIRECTORY, g_Settings.LoggingEnabled ? TRUE : FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_FONTCHOOSE, g_Settings.LoggingEnabled ? TRUE : FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN4, UDM_SETRANGE, 0, MAKELONG(10000, 0));
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN4, UDM_SETPOS, 0, MAKELONG(DBGetContactSettingWord(NULL, "Chat", "LoggingLimit", 100), 0));
+ Utils::enableDlgControl(hwndDlg, IDC_LIMIT, g_Settings.LoggingEnabled ? TRUE : FALSE);
+
+ if (ServiceExists(MS_UTILS_REPLACEVARS)) {
+ TCHAR tszTooltipText[2048];
+
+ mir_sntprintf(tszTooltipText, SIZEOF(tszTooltipText),
+ _T("%s - %s\n%s - %s\n%s - %s\n\n")
+ _T("%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n\n")
+ _T("%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s"),
+ // contact vars
+ _T("%nick%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP1),
+ _T("%proto%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP2),
+ _T("%userid%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP3),
+ // global vars
+ _T("%miranda_path%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP4),
+ _T("%miranda_profile%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP5),
+ _T("%miranda_profilename%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP6),
+ _T("%miranda_userdata%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP7),
+ _T("%appdata%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP8),
+ _T("%username%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP9),
+ _T("%mydocuments%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP10),
+ _T("%desktop%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP11),
+ _T("%xxxxxxx%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP12),
+ // date/time vars
+ _T("%d%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP13),
+ _T("%dd%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP14),
+ _T("%m%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP15),
+ _T("%mm%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP16),
+ _T("%mon%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP17),
+ _T("%month%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP18),
+ _T("%yy%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP19),
+ _T("%yyyy%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP20),
+ _T("%wday%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP21),
+ _T("%weekday%"), CTranslator::getOpt(CTranslator::OPT_MUC_LOGTIP22));
+ hPathTip = CreateToolTip(GetDlgItem(hwndDlg, IDC_LOGDIRECTORY), tszTooltipText, const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_MUC_VARIABLES)));
+ }
+
+ } else {
+ int i = 0;
+
+ while (_o2chatcontrols[i])
+ Utils::enableDlgControl(hwndDlg, _o2chatcontrols[i++], FALSE);
+ }
+ if (hPathTip)
+ SetTimer(hwndDlg, 0, 3000, NULL);
+ break;
+ }
+ case WM_COMMAND:
+ if ((LOWORD(wParam) == IDC_INSTAMP
+ || LOWORD(wParam) == IDC_OUTSTAMP
+ || LOWORD(wParam) == IDC_TIMESTAMP
+ || LOWORD(wParam) == IDC_LOGLIMIT
+ || LOWORD(wParam) == IDC_NICKROW2
+ || LOWORD(wParam) == IDC_LOGDIRECTORY
+ || LOWORD(wParam) == IDC_LIMIT
+ || LOWORD(wParam) == IDC_LOGTIMESTAMP)
+ && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return 0;
+
+ switch (LOWORD(wParam)) {
+ /*
+ * open the base directory for MUC logs, using a standard file selector
+ * dialog. Simply allows the user to view what log files are there
+ * and possibly delete archived logs.
+ */
+ case IDC_MUC_OPENLOGBASEDIR: {
+ OPENFILENAME ofn = {0};
+ SESSION_INFO si = {0};
+ TCHAR tszReturnName[MAX_PATH];
+ TCHAR tszInitialDir[_MAX_DRIVE + _MAX_PATH + 10];
+ TCHAR tszTemp[MAX_PATH + 20], *p = 0, *p1 = 0;
+
+ mir_sntprintf(tszTemp, MAX_PATH + 20, _T("%s"), g_Settings.pszLogDir);
+
+ p = tszTemp;
+ while(*p && (*p == '\\' || *p == '.'))
+ p++;
+
+ if(*p) {
+ if((p1 = _tcschr(p, '\\')))
+ *p1 = 0;
+ }
+
+ mir_sntprintf(tszInitialDir, MAX_PATH, _T("%s%s"), M->getChatLogPath(), p);
+ if(PathFileExists(tszInitialDir))
+ ofn.lpstrInitialDir = tszInitialDir;
+ else {
+ mir_sntprintf(tszInitialDir, MAX_PATH, _T("%s"), M->getChatLogPath());
+ ofn.lpstrInitialDir = tszInitialDir;
+ }
+
+ tszReturnName[0] = 0;
+ mir_sntprintf(tszTemp, SIZEOF(tszTemp), _T("%s%c*.*%c%c"), TranslateT("All Files"), 0, 0, 0);
+
+ ofn.lpstrFilter = tszTemp;
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = 0;
+ ofn.lpstrFile = tszReturnName;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.Flags = OFN_HIDEREADONLY | OFN_DONTADDTORECENT;
+ ofn.lpstrDefExt = _T("log");
+ GetOpenFileName(&ofn);
+ break;
+ }
+
+ case IDC_FONTCHOOSE: {
+ TCHAR tszDirectory[MAX_PATH];
+ LPITEMIDLIST idList;
+ LPMALLOC psMalloc;
+ BROWSEINFO bi = {0};
+
+ if (SUCCEEDED(CoGetMalloc(1, &psMalloc))) {
+ TCHAR tszTemp[MAX_PATH];
+ bi.hwndOwner = hwndDlg;
+ bi.pszDisplayName = tszDirectory;
+ bi.lpszTitle = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_MUC_SELECTFOLDER));
+ bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_RETURNONLYFSDIRS;
+ bi.lpfn = BrowseCallbackProc;
+ bi.lParam = (LPARAM)tszDirectory;
+
+
+ idList = SHBrowseForFolder(&bi);
+ if (idList) {
+ const TCHAR *szUserDir = M->getUserDir();
+ SHGetPathFromIDList(idList, tszDirectory);
+ lstrcat(tszDirectory, _T("\\"));
+ M->pathToRelative(tszDirectory, tszTemp, const_cast<TCHAR *>(szUserDir));
+ SetWindowText(GetDlgItem(hwndDlg, IDC_LOGDIRECTORY), lstrlen(tszTemp) > 1 ? tszTemp : DEFLOGFILENAME);
+ }
+ psMalloc->Free(idList);
+ psMalloc->Release();
+ }
+ break;
+ }
+
+ case IDC_LOGGING:
+ if (PluginConfig.m_chat_enabled) {
+ Utils::enableDlgControl(hwndDlg, IDC_LOGDIRECTORY, IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED ? TRUE : FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_FONTCHOOSE, IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED ? TRUE : FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_LIMIT, IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED ? TRUE : FALSE);
+ }
+ break;
+ }
+
+ if (lParam != (LPARAM)NULL)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->idFrom == 0 && ((LPNMHDR)lParam)->code == PSN_APPLY) {
+ int iLen;
+ TCHAR *p2 = NULL;
+ char *pszText = NULL;
+ TCHAR *ptszPath = NULL;
+
+ if (PluginConfig.m_chat_enabled) {
+
+ iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOGDIRECTORY));
+ if (iLen > 0) {
+ TCHAR *pszText1 = (TCHAR *)malloc(iLen*sizeof(TCHAR) + 2);
+ GetDlgItemText(hwndDlg, IDC_LOGDIRECTORY, pszText1, iLen + 1);
+ M->WriteTString(NULL, "Chat", "LogDirectory", pszText1);
+ free(pszText1);
+ g_Settings.LoggingEnabled = IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED ? TRUE : FALSE;
+ M->WriteByte("Chat", "LoggingEnabled", (BYTE)g_Settings.LoggingEnabled);
+ } else {
+ DBDeleteContactSetting(NULL, "Chat", "LogDirectory");
+ M->WriteByte("Chat", "LoggingEnabled", 0);
+ }
+ SM_InvalidateLogDirectories();
+
+ iLen = SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN4, UDM_GETPOS, 0, 0);
+ DBWriteContactSettingWord(NULL, "Chat", "LoggingLimit", (WORD)iLen);
+
+ iLen = SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN3, UDM_GETPOS, 0, 0);
+ if (iLen > 0)
+ M->WriteByte("Chat", "NicklistRowDist", (BYTE)iLen);
+ else
+ DBDeleteContactSetting(NULL, "Chat", "NicklistRowDist");
+
+ iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOGTIMESTAMP));
+ if (iLen > 0) {
+ pszText = (char *)realloc(pszText, iLen + 1);
+ GetDlgItemTextA(hwndDlg, IDC_LOGTIMESTAMP, pszText, iLen + 1);
+ DBWriteContactSettingString(NULL, "Chat", "LogTimestamp", pszText);
+ } else DBDeleteContactSetting(NULL, "Chat", "LogTimestamp");
+
+ iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_TIMESTAMP));
+ if (iLen > 0) {
+ pszText = (char *)realloc(pszText, iLen + 1);
+ GetDlgItemTextA(hwndDlg, IDC_TIMESTAMP, pszText, iLen + 1);
+ DBWriteContactSettingString(NULL, "Chat", "HeaderTime", pszText);
+ } else DBDeleteContactSetting(NULL, "Chat", "HeaderTime");
+
+ iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_INSTAMP));
+ if (iLen > 0) {
+ pszText = (char *)realloc(pszText, iLen + 1);
+ GetDlgItemTextA(hwndDlg, IDC_INSTAMP, pszText, iLen + 1);
+ DBWriteContactSettingString(NULL, "Chat", "HeaderIncoming", pszText);
+ } else DBDeleteContactSetting(NULL, "Chat", "HeaderIncoming");
+
+ iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_OUTSTAMP));
+ if (iLen > 0) {
+ pszText = (char *)realloc(pszText, iLen + 1);
+ GetDlgItemTextA(hwndDlg, IDC_OUTSTAMP, pszText, iLen + 1);
+ DBWriteContactSettingString(NULL, "Chat", "HeaderOutgoing", pszText);
+ } else DBDeleteContactSetting(NULL, "Chat", "HeaderOutgoing");
+
+ iLen = SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN2, UDM_GETPOS, 0, 0);
+ DBWriteContactSettingWord(NULL, "Chat", "LogLimit", (WORD)iLen);
+ }
+
+
+ if (pszText != NULL)
+ free(pszText);
+ if (hListBkgBrush)
+ DeleteObject(hListBkgBrush);
+ hListBkgBrush = CreateSolidBrush(M->GetDword("Chat", "ColorNicklistBG", SRMSGDEFSET_BKGCOLOUR));
+
+
+ if (PluginConfig.m_chat_enabled) {
+ LOGFONT lf;
+ HFONT hFont;
+ int iText;
+
+ LoadLogFonts();
+ FreeMsgLogBitmaps();
+ LoadMsgLogBitmaps();
+
+ LoadMsgDlgFont(FONTSECTION_CHAT, 0, &lf, NULL, CHAT_FONTMODULE);
+ hFont = CreateFontIndirect(&lf);
+ iText = GetTextPixelSize(MakeTimeStamp(g_Settings.pszTimeStamp, time(NULL)), hFont, TRUE);
+ DeleteObject(hFont);
+ g_Settings.LogTextIndent = iText;
+ g_Settings.LogTextIndent = g_Settings.LogTextIndent * 12 / 10;
+ g_Settings.LogIndentEnabled = (M->GetByte("Chat", "LogIndentEnabled", 1) != 0) ? TRUE : FALSE;
+
+ LoadGlobalSettings();
+ MM_FontsChanged();
+ MM_FixColors();
+ SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE);
+ }
+
+ PluginConfig.reloadSettings();
+ CacheMsgLogIcons();
+ CacheLogFonts();
+ return TRUE;
+ }
+ break;
+ case WM_TIMER:
+ if(IsWindow(hPathTip))
+ KillTimer(hPathTip, 4); // It will prevent tooltip autoclosing
+ break;
+ case WM_DESTROY:
+ if (hPathTip)
+ {
+ KillTimer(hwndDlg, 0);
+ DestroyWindow(hPathTip);
+ hPathTip = 0;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+#define NR_GC_EVENTS 12
+
+static UINT _eventorder[] = { GC_EVENT_ACTION,
+ GC_EVENT_MESSAGE,
+ GC_EVENT_NICK,
+ GC_EVENT_JOIN,
+ GC_EVENT_PART,
+ GC_EVENT_TOPIC,
+ GC_EVENT_ADDSTATUS,
+ GC_EVENT_INFORMATION,
+ GC_EVENT_QUIT,
+ GC_EVENT_KICK,
+ GC_EVENT_NOTICE,
+ GC_EVENT_HIGHLIGHT,
+ 0
+};
+
+#define GC_EVENT_ALL (GC_EVENT_ACTION | GC_EVENT_MESSAGE | GC_EVENT_NICK | GC_EVENT_JOIN | \
+ GC_EVENT_PART | GC_EVENT_TOPIC | GC_EVENT_ADDSTATUS | GC_EVENT_INFORMATION | GC_EVENT_QUIT | \
+ GC_EVENT_KICK | GC_EVENT_NOTICE)
+
+/**
+ * Dialog procedure for group chat options tab #3 (event filter configuration)
+ *
+ * @return
+ */
+INT_PTR CALLBACK DlgProcOptions3(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg) {
+ case WM_INITDIALOG: {
+
+ TranslateDialogDefault(hwndDlg);
+
+ if (PluginConfig.m_chat_enabled) {
+ DWORD dwFilterFlags = M->GetDword("Chat", "FilterFlags", GC_EVENT_ALL);
+ DWORD dwTrayFlags = M->GetDword("Chat", "TrayIconFlags", GC_EVENT_ALL);
+ DWORD dwPopupFlags = M->GetDword("Chat", "PopupFlags", GC_EVENT_ALL);
+ DWORD dwLogFlags = M->GetDword("Chat", "DiskLogFlags", GC_EVENT_ALL);
+
+ for(int i = 0; _eventorder[i]; i++) {
+ if(_eventorder[i] != GC_EVENT_HIGHLIGHT) {
+ CheckDlgButton(hwndDlg, IDC_1 + i, dwFilterFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_L1 + i, dwLogFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED);
+ }
+ CheckDlgButton(hwndDlg, IDC_P1 + i, dwPopupFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_T1 + i, dwTrayFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_LOGICONTYPE, CB_ADDSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_MUC_NOMARKERS));
+ SendDlgItemMessage(hwndDlg, IDC_LOGICONTYPE, CB_ADDSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_MUC_ASICONS));
+ SendDlgItemMessage(hwndDlg, IDC_LOGICONTYPE, CB_ADDSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_MUC_ASSYMBOLS));
+
+ SendDlgItemMessage(hwndDlg, IDC_LOGICONTYPE, CB_SETCURSEL, (g_Settings.LogSymbols ? 2 : (g_Settings.dwIconFlags ? 1 : 0)), 0);
+
+ CheckDlgButton(hwndDlg, IDC_NOPOPUPSFORCLOSEDWINDOWS, M->GetByte("Chat", "SkipWhenNoWindow", 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_TRAYONLYFORINACTIVE, M->GetByte("Chat", "TrayIconInactiveOnly", 0) ? BST_CHECKED : BST_UNCHECKED);
+ }
+ break;
+ }
+ case WM_COMMAND:
+ if (lParam != (LPARAM)NULL)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY: {
+ DWORD dwFilterFlags = 0, dwTrayFlags = 0,
+ dwPopupFlags = 0, dwLogFlags = 0;
+
+ for(int i = 0; _eventorder[i]; i++) {
+ if(_eventorder[i] != GC_EVENT_HIGHLIGHT) {
+ dwFilterFlags |= (IsDlgButtonChecked(hwndDlg, IDC_1 + i) ? _eventorder[i] : 0);
+ dwLogFlags |= (IsDlgButtonChecked(hwndDlg, IDC_L1 + i) ? _eventorder[i] : 0);
+ }
+ dwPopupFlags |= (IsDlgButtonChecked(hwndDlg, IDC_P1 + i) ? _eventorder[i] : 0);
+ dwTrayFlags |= (IsDlgButtonChecked(hwndDlg, IDC_T1 + i) ? _eventorder[i] : 0);
+ }
+ M->WriteDword("Chat", "FilterFlags", dwFilterFlags);
+ M->WriteDword("Chat", "PopupFlags", dwPopupFlags);
+ M->WriteDword("Chat", "TrayIconFlags", dwTrayFlags);
+ M->WriteDword("Chat", "DiskLogFlags", dwLogFlags);
+
+ LRESULT lr = SendDlgItemMessage(hwndDlg, IDC_LOGICONTYPE, CB_GETCURSEL, 0, 0);
+
+ M->WriteDword("Chat", "IconFlags", lr == 1 ? 1 : 0);
+ M->WriteByte("Chat", "LogSymbols", lr == 2 ? 1 : 0);
+
+ M->WriteByte("Chat", "SkipWhenNoWindow", IsDlgButtonChecked(hwndDlg, IDC_NOPOPUPSFORCLOSEDWINDOWS) ? 1 : 0);
+ M->WriteByte("Chat", "TrayIconInactiveOnly", IsDlgButtonChecked(hwndDlg, IDC_TRAYONLYFORINACTIVE) ? 1 : 0);
+ LoadGlobalSettings();
+ MM_FontsChanged();
+ SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE);
+ SM_ReconfigureFilters();
+ break;
+ }
+ return TRUE;
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ break;
+
+ }
+ return FALSE;
+}
+
+void LoadGlobalSettings(void)
+{
+ LOGFONT lf;
+ int i;
+ char szBuf[40];
+
+ g_Settings.LogLimitNames = M->GetByte("Chat", "LogLimitNames", 1);
+ g_Settings.ShowTime = M->GetByte("Chat", "ShowTimeStamp", 1);
+ g_Settings.ShowTimeIfChanged = (BOOL)M->GetByte("Chat", "ShowTimeStampIfChanged", 0);
+ g_Settings.TimeStampEventColour = (BOOL)M->GetByte("Chat", "TimeStampEventColour", 0);
+ g_Settings.iEventLimit = DBGetContactSettingWord(NULL, "Chat", "LogLimit", 100);
+ g_Settings.iEventLimitThreshold = DBGetContactSettingWord(NULL, "Chat", "LogLimitThreshold", 20);
+ g_Settings.dwIconFlags = M->GetDword("Chat", "IconFlags", 0x0000);
+ g_Settings.LoggingLimit = (size_t)DBGetContactSettingWord(NULL, "Chat", "LoggingLimit", 100);
+ g_Settings.LoggingEnabled = (BOOL)M->GetByte("Chat", "LoggingEnabled", 0);
+ g_Settings.OpenInDefault = (BOOL)M->GetByte("Chat", "DefaultContainer", 1);
+ g_Settings.FlashWindow = (BOOL)M->GetByte("Chat", "FlashWindow", 0);
+ g_Settings.FlashWindowHightlight = (BOOL)M->GetByte("Chat", "FlashWindowHighlight", 0);
+ g_Settings.HighlightEnabled = (BOOL)M->GetByte("Chat", "HighlightEnabled", 1);
+ g_Settings.crUserListColor = (BOOL)M->GetDword(CHAT_FONTMODULE, "Font18Col", RGB(0, 0, 0));
+ g_Settings.crUserListBGColor = (BOOL)M->GetDword("Chat", "ColorNicklistBG", SRMSGDEFSET_BKGCOLOUR);
+ g_Settings.crUserListHeadingsColor = (BOOL)M->GetDword(CHAT_FONTMODULE, "Font19Col", RGB(170, 170, 170));
+ g_Settings.StripFormat = (BOOL)M->GetByte("Chat", "StripFormatting", 0);
+ g_Settings.TrayIconInactiveOnly = (BOOL)M->GetByte("Chat", "TrayIconInactiveOnly", 1);
+ g_Settings.BBCodeInPopups = (BOOL)M->GetByte("Chat", "BBCodeInPopups", 0);
+ g_Settings.AddColonToAutoComplete = (BOOL)M->GetByte("Chat", "AddColonToAutoComplete", 1);
+ g_Settings.iPopupStyle = M->GetByte("Chat", "PopupStyle", 1);
+ g_Settings.iPopupTimeout = DBGetContactSettingWord(NULL, "Chat", "PopupTimeout", 3);
+ g_Settings.crPUBkgColour = M->GetDword("Chat", "PopupColorBG", GetSysColor(COLOR_WINDOW));
+ g_Settings.crPUTextColour = M->GetDword("Chat", "PopupColorText", 0);
+ g_Settings.ClassicIndicators = M->GetByte("Chat", "ClassicIndicators", 0);
+ //MAD
+ g_Settings.LogClassicIndicators = M->GetByte("Chat", "LogClassicIndicators", 0);
+ g_Settings.AlternativeSorting = M->GetByte("Chat", "AlternativeSorting", 1);
+ g_Settings.AnnoyingHighlight = M->GetByte("Chat", "AnnoyingHighlight", 0);
+ g_Settings.CreateWindowOnHighlight = M->GetByte("Chat", "CreateWindowOnHighlight", 1);
+ //MAD_
+ g_Settings.LogSymbols = M->GetByte("Chat", "LogSymbols", 1);
+ g_Settings.ClickableNicks = M->GetByte("Chat", "ClickableNicks", 1);
+ g_Settings.ColorizeNicks = M->GetByte("Chat", "ColorizeNicks", 1);
+ g_Settings.ColorizeNicksInLog = M->GetByte("Chat", "ColorizeNicksInLog", 1);
+ g_Settings.ScaleIcons = M->GetByte("Chat", "ScaleIcons", 1);
+ g_Settings.UseDividers = M->GetByte("Chat", "UseDividers", 1);
+ g_Settings.DividersUsePopupConfig = M->GetByte("Chat", "DividersUsePopupConfig", 1);
+ g_Settings.MathMod = ServiceExists(MATH_RTF_REPLACE_FORMULAE) && M->GetByte("Chat", "MathModSupport", 0);
+
+ g_Settings.DoubleClick4Privat = (BOOL)M->GetByte("Chat", "DoubleClick4Privat", 0);
+ g_Settings.ShowContactStatus = M->GetByte("Chat", "ShowContactStatus", 1);
+ g_Settings.ContactStatusFirst = M->GetByte("Chat", "ContactStatusFirst", 0);
+
+
+ if (hListBkgBrush)
+ DeleteObject(hListBkgBrush);
+ hListBkgBrush = CreateSolidBrush(M->GetDword("Chat", "ColorNicklistBG", SRMSGDEFSET_BKGCOLOUR));
+
+ InitSetting(&g_Settings.pszTimeStamp, "HeaderTime", _T("[%H:%M]"));
+ InitSetting(&g_Settings.pszTimeStampLog, "LogTimestamp", _T("[%d %b %y %H:%M]"));
+ InitSetting(&g_Settings.pszIncomingNick, "HeaderIncoming", _T("%n:"));
+ InitSetting(&g_Settings.pszOutgoingNick, "HeaderOutgoing", _T("%n:"));
+
+ DBVARIANT dbv;
+
+ if (!M->GetTString(NULL, "Chat", "LogDirectory", &dbv)) {
+ lstrcpyn(g_Settings.pszLogDir, dbv.ptszVal, MAX_PATH);
+ DBFreeVariant(&dbv);
+ } else
+ lstrcpyn(g_Settings.pszLogDir, DEFLOGFILENAME, MAX_PATH);
+
+ g_Settings.pszLogDir[MAX_PATH - 1] = 0;
+
+ g_Settings.LogIndentEnabled = (M->GetByte("Chat", "LogIndentEnabled", 1) != 0) ? TRUE : FALSE;
+
+
+ // nicklist
+
+ if(g_Settings.UserListFont) {
+ DeleteObject(g_Settings.UserListFont);
+ DeleteObject(g_Settings.UserListHeadingsFont);
+ }
+
+ LoadMsgDlgFont(FONTSECTION_CHAT, 18, &lf, NULL, CHAT_FONTMODULE);
+ g_Settings.UserListFont = CreateFontIndirect(&lf);
+
+ LoadMsgDlgFont(FONTSECTION_CHAT, 19, &lf, NULL, CHAT_FONTMODULE);
+ g_Settings.UserListHeadingsFont = CreateFontIndirect(&lf);
+
+ int ih;
+ int ih2;
+
+ ih = GetTextPixelSize(_T("AQGglo"), g_Settings.UserListFont, FALSE);
+ ih2 = GetTextPixelSize(_T("AQGglo"), g_Settings.UserListHeadingsFont, FALSE);
+ g_Settings.iNickListFontHeight = max(M->GetByte("Chat", "NicklistRowDist", 12), (ih > ih2 ? ih : ih2));
+
+ for (i = 0; i < 7; i++) {
+ mir_snprintf(szBuf, 20, "NickColor%d", i);
+ g_Settings.nickColors[i] = M->GetDword("Chat", szBuf, g_Settings.crUserListColor);
+ }
+ g_Settings.nickColors[5] = M->GetDword("Chat", "NickColor5", GetSysColor(COLOR_HIGHLIGHT));
+ g_Settings.nickColors[6] = M->GetDword("Chat", "NickColor6", GetSysColor(COLOR_HIGHLIGHTTEXT));
+ if (g_Settings.SelectionBGBrush)
+ DeleteObject(g_Settings.SelectionBGBrush);
+ g_Settings.SelectionBGBrush = CreateSolidBrush(g_Settings.nickColors[5]);
+}
+
+static void FreeGlobalSettings(void)
+{
+ mir_free(g_Settings.pszTimeStamp);
+ mir_free(g_Settings.pszTimeStampLog);
+ mir_free(g_Settings.pszIncomingNick);
+ mir_free(g_Settings.pszOutgoingNick);
+ if(g_Settings.UserListFont) {
+ DeleteObject(g_Settings.UserListFont);
+ DeleteObject(g_Settings.UserListHeadingsFont);
+ }
+ if (g_Settings.SelectionBGBrush)
+ DeleteObject(g_Settings.SelectionBGBrush);
+
+ delete g_Settings.Highlight;
+}
+
+int OptionsInit(void)
+{
+ LOGFONT lf;
+ HFONT hFont;
+ int iText;
+
+ LoadLogFonts();
+ LoadMsgDlgFont(FONTSECTION_CHAT, 17, &lf, NULL, CHAT_FONTMODULE);
+ lstrcpy(lf.lfFaceName, _T("MS Shell Dlg"));
+ lf.lfUnderline = lf.lfItalic = lf.lfStrikeOut = 0;
+ lf.lfHeight = -17;
+ lf.lfWeight = FW_BOLD;
+ ZeroMemory(&g_Settings, sizeof(TMUCSettings));
+ g_Settings.NameFont = CreateFontIndirect(&lf);
+ g_Settings.iSplitterX = DBGetContactSettingWord(NULL, "Chat", "SplitterX", 105);
+ if(g_Settings.iSplitterX <= 50)
+ g_Settings.iSplitterX = 105;
+ g_Settings.iSplitterY = DBGetContactSettingWord(NULL, "Chat", "splitY", 50);
+ if(g_Settings.iSplitterY <= 20)
+ g_Settings.iSplitterY = 50;
+ g_Settings.hGroup = 0;
+ LoadGlobalSettings();
+ g_Settings.Highlight = new CMUCHighlight();
+ SkinAddNewSoundEx("ChatMessage", "Group chats", "Incoming message");
+ SkinAddNewSoundEx("ChatSent", "Group chats", "Outgoing message");
+ SkinAddNewSoundEx("ChatHighlight", "Group chats", "Message is highlighted");
+ SkinAddNewSoundEx("ChatAction", "Group chats", "User has performed an action");
+ SkinAddNewSoundEx("ChatJoin", "Group chats", "User has joined");
+ SkinAddNewSoundEx("ChatPart", "Group chats", "User has left");
+ SkinAddNewSoundEx("ChatKick", "Group chats", "User has kicked some other user");
+ SkinAddNewSoundEx("ChatMode", "Group chats", "User's status was changed");
+ SkinAddNewSoundEx("ChatNick", "Group chats", "User has changed name");
+ SkinAddNewSoundEx("ChatNotice", "Group chats", "User has sent a notice");
+ SkinAddNewSoundEx("ChatQuit", "Group chats", "User has disconnected");
+ SkinAddNewSoundEx("ChatTopic", "Group chats", "The topic has been changed");
+
+ LoadMsgDlgFont(FONTSECTION_CHAT, 0, &lf, NULL, CHAT_FONTMODULE);
+ hFont = CreateFontIndirect(&lf);
+ iText = GetTextPixelSize(MakeTimeStamp(g_Settings.pszTimeStamp, time(NULL)), hFont, TRUE);
+ DeleteObject(hFont);
+ g_Settings.LogTextIndent = iText;
+ g_Settings.LogTextIndent = g_Settings.LogTextIndent * 12 / 10;
+ return 0;
+}
+
+
+int OptionsUnInit(void)
+{
+ FreeGlobalSettings();
+ UnhookEvent(g_hOptions);
+ DeleteObject(hListBkgBrush);
+ DeleteObject(g_Settings.NameFont);
+ return 0;
+}
diff --git a/plugins/TabSRMM/chat/services.cpp b/plugins/TabSRMM/chat/services.cpp
new file mode 100644
index 0000000000..e165763861
--- /dev/null
+++ b/plugins/TabSRMM/chat/services.cpp
@@ -0,0 +1,909 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * This code is based on and still contains large parts of the the
+ * original chat module for Miranda IM, written and copyrighted
+ * by Joergen Persson in 2005.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: services.cpp 13046 2010-10-28 10:02:50Z silvercircle $
+ *
+ * This implements the services that form the group chat API
+ *
+ */
+
+#include "../src/commonheaders.h"
+
+// defs
+extern HICON hIcons[30];
+
+HANDLE hSendEvent;
+HANDLE hBuildMenuEvent;
+HANDLE hJoinMenuItem, hLeaveMenuItem;
+HANDLE g_hHookPrebuildMenu;
+CRITICAL_SECTION cs;
+
+static HANDLE hServiceRegister = NULL,
+ hServiceNewChat = NULL,
+ hServiceAddEvent = NULL,
+ hServiceGetAddEventPtr = NULL,
+ hServiceGetInfo = NULL,
+ hServiceGetCount = NULL,
+ hEventPrebuildMenu = NULL,
+ hEventDoubleclicked = NULL,
+ hEventJoinChat = NULL,
+ hEventLeaveChat = NULL;
+
+#ifdef _WIN64
+
+#define SIZEOF_STRUCT_GCREGISTER_V1 40
+#define SIZEOF_STRUCT_GCWINDOW_V1 48
+#define SIZEOF_STRUCT_GCEVENT_V1 76
+#define SIZEOF_STRUCT_GCEVENT_V2 80
+
+#else
+
+#define SIZEOF_STRUCT_GCREGISTER_V1 28
+#define SIZEOF_STRUCT_GCWINDOW_V1 32
+#define SIZEOF_STRUCT_GCEVENT_V1 44
+#define SIZEOF_STRUCT_GCEVENT_V2 48
+
+#endif
+
+int Chat_ModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ if (!PluginConfig.m_chat_enabled)
+ return 0;
+
+ char * mods[3] = {"Chat", CHAT_FONTMODULE};
+ CallService("DBEditorpp/RegisterModule", (WPARAM)mods, (LPARAM)2);
+
+ LoadIcons();
+
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000090001;
+ mi.flags = CMIF_DEFAULT | CMIF_ICONFROMICOLIB;
+ mi.icolibItem = LoadSkinnedIconHandle( SKINICON_CHAT_JOIN );
+ mi.pszName = LPGEN("&Join");
+ mi.pszService = "GChat/JoinChat";
+ hJoinMenuItem = ( HANDLE )CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+
+ mi.position = -2000090000;
+ mi.flags = CMIF_NOTOFFLINE | CMIF_ICONFROMICOLIB;
+ mi.icolibItem = LoadSkinnedIconHandle( SKINICON_CHAT_LEAVE );
+ mi.pszName = LPGEN("&Leave");
+ mi.pszService = "GChat/LeaveChat";
+ hLeaveMenuItem = ( HANDLE )CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+
+ CList_SetAllOffline(TRUE, NULL);
+
+ g_Settings.MathMod = ServiceExists(MATH_RTF_REPLACE_FORMULAE) && M->GetByte("Chat", "MathModSupport", 0);
+ return 0;
+}
+
+int Chat_PreShutdown()
+{
+ SM_RemoveAll();
+ MM_RemoveAll();
+ return 0;
+}
+
+int Chat_IconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ FreeMsgLogBitmaps();
+
+ LoadLogIcons();
+ LoadMsgLogBitmaps();
+ //MM_IconsChanged();
+ SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, FALSE);
+ return 0;
+}
+
+INT_PTR Service_GetCount(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+
+ if (!lParam)
+ return -1;
+
+ EnterCriticalSection(&cs);
+
+ i = SM_GetCount((char *)lParam);
+
+ LeaveCriticalSection(&cs);
+ return i;
+}
+
+INT_PTR Service_GetInfo(WPARAM wParam, LPARAM lParam)
+{
+ GC_INFO * gci = (GC_INFO *) lParam;
+ SESSION_INFO* si = NULL;
+
+ if (!gci || !gci->pszModule)
+ return 1;
+
+ EnterCriticalSection(&cs);
+
+ if (gci->Flags&BYINDEX)
+ si = SM_FindSessionByIndex(gci->pszModule, gci->iItem);
+ else
+ si = SM_FindSession(gci->pszID, gci->pszModule);
+
+ if (si) {
+ if (gci->Flags & DATA) gci->dwItemData = si->dwItemData;
+ if (gci->Flags & HCONTACT) gci->hContact = si->hContact;
+ if (gci->Flags & TYPE) gci->iType = si->iType;
+ if (gci->Flags & COUNT) gci->iCount = si->nUsersInNicklist;
+ if (gci->Flags & USERS) gci->pszUsers = SM_GetUsers(si);
+
+ if (si->dwFlags & GC_UNICODE) {
+ if (gci->Flags & ID) gci->pszID = si->ptszID;
+ if (gci->Flags & NAME) gci->pszName = si->ptszName;
+ }
+ else {
+ if (gci->Flags & ID) gci->pszID = (TCHAR*)si->pszID;
+ if (gci->Flags & NAME) gci->pszName = (TCHAR*)si->pszName;
+ }
+ LeaveCriticalSection(&cs);
+ return 0;
+ }
+
+ LeaveCriticalSection(&cs);
+ return 1;
+}
+
+INT_PTR Service_Register(WPARAM wParam, LPARAM lParam)
+{
+
+ GCREGISTER *gcr = (GCREGISTER *)lParam;
+ MODULEINFO * mi = NULL;
+ if (gcr == NULL)
+ return GC_REGISTER_ERROR;
+
+ if (gcr->cbSize != SIZEOF_STRUCT_GCREGISTER_V1)
+ return GC_REGISTER_WRONGVER;
+
+ EnterCriticalSection(&cs);
+
+ mi = MM_AddModule(gcr->pszModule);
+ if (mi) {
+ mi->ptszModDispName = a2tf( gcr->ptszModuleDispName, gcr->dwFlags, 0);
+ mi->bBold = gcr->dwFlags & GC_BOLD;
+ mi->bUnderline = gcr->dwFlags & GC_UNDERLINE ;
+ mi->bItalics = gcr->dwFlags & GC_ITALICS ;
+ mi->bColor = gcr->dwFlags & GC_COLOR ;
+ mi->bBkgColor = gcr->dwFlags & GC_BKGCOLOR ;
+ mi->bAckMsg = gcr->dwFlags & GC_ACKMSG ;
+ mi->bChanMgr = gcr->dwFlags & GC_CHANMGR ;
+ mi->iMaxText = gcr->iMaxText;
+ mi->nColorCount = gcr->nColors;
+ if (gcr->nColors > 0) {
+ mi->crColors = (COLORREF *)mir_alloc(sizeof(COLORREF) * gcr->nColors);
+ memcpy(mi->crColors, gcr->pColors, sizeof(COLORREF) * gcr->nColors);
+ }
+ mi->pszHeader = 0;
+
+ CheckColorsInModule((char*)gcr->pszModule);
+ CList_SetAllOffline(TRUE, gcr->pszModule);
+
+ LeaveCriticalSection(&cs);
+ return 0;
+ }
+
+ LeaveCriticalSection(&cs);
+ return GC_REGISTER_ERROR;
+}
+
+INT_PTR Service_NewChat(WPARAM wParam, LPARAM lParam)
+{
+ MODULEINFO* mi;
+ GCSESSION *gcw = (GCSESSION *)lParam;
+ if (gcw == NULL)
+ return GC_NEWSESSION_ERROR;
+
+ if (gcw->cbSize != SIZEOF_STRUCT_GCWINDOW_V1)
+ return GC_NEWSESSION_WRONGVER;
+
+ EnterCriticalSection(&cs);
+
+ if ((mi = MM_FindModule(gcw->pszModule)) != NULL) {
+ TCHAR* ptszID = a2tf(gcw->ptszID, gcw->dwFlags, 0);
+ SESSION_INFO* si = SM_AddSession(ptszID, gcw->pszModule);
+
+ // create a new session and set the defaults
+ if (si != NULL) {
+ TCHAR szTemp[256];
+
+ si->dwItemData = gcw->dwItemData;
+ if (gcw->iType != GCW_SERVER)
+ si->wStatus = ID_STATUS_ONLINE;
+ si->iType = gcw->iType;
+ si->dwFlags = gcw->dwFlags;
+ si->ptszName = a2tf(gcw->ptszName, gcw->dwFlags, 0);
+ si->ptszStatusbarText = a2tf(gcw->ptszStatusbarText, gcw->dwFlags, 0);
+ si->iSplitterX = g_Settings.iSplitterX;
+ si->bFilterEnabled = M->GetByte(si->hContact, "Chat", "FilterEnabled", M->GetByte("Chat", "FilterEnabled", 0));
+ si->bNicklistEnabled = M->GetByte("Chat", "ShowNicklist", 1);
+ if (!(gcw->dwFlags & GC_UNICODE)) {
+ si->pszID = mir_strdup(gcw->pszID);
+ si->pszName = mir_strdup(gcw->pszName);
+ }
+
+ if (mi->bColor) {
+ si->iFG = 4;
+ si->bFGSet = TRUE;
+ }
+ if (mi->bBkgColor) {
+ si->iBG = 2;
+ si->bBGSet = TRUE;
+ }
+ if (si->iType == GCW_SERVER)
+ mir_sntprintf(szTemp, SIZEOF(szTemp), _T("Server: %s"), si->ptszName);
+ else
+ mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s"), si->ptszName);
+ si->hContact = CList_AddRoom(gcw->pszModule, ptszID, szTemp, si->iType);
+ DBWriteContactSettingString(si->hContact, si->pszModule , "Topic", "");
+ DBDeleteContactSetting(si->hContact, "CList", "StatusMsg");
+ if (si->ptszStatusbarText)
+ M->WriteTString(si->hContact, si->pszModule, "StatusBar", si->ptszStatusbarText);
+ else
+ DBWriteContactSettingString(si->hContact, si->pszModule, "StatusBar", "");
+ if (si->hContact)
+ Chat_SetFilters(si);
+ } else {
+ SESSION_INFO* si2 = SM_FindSession(ptszID, gcw->pszModule);
+ if (si2) {
+
+ UM_RemoveAll(&si2->pUsers);
+ TM_RemoveAll(&si2->pStatuses);
+
+ si2->iStatusCount = 0;
+ si2->nUsersInNicklist = 0;
+
+ if (si2->hContact)
+ Chat_SetFilters(si2);
+ if (si2->hWnd)
+ RedrawWindow(GetDlgItem(si2->hWnd, IDC_LIST), NULL, NULL, RDW_INVALIDATE);
+ }
+ }
+
+ LeaveCriticalSection(&cs);
+ mir_free(ptszID);
+ return 0;
+ }
+
+ LeaveCriticalSection(&cs);
+ return GC_NEWSESSION_ERROR;
+}
+
+static int DoControl(GCEVENT * gce, WPARAM wp)
+{
+ if (gce->pDest->iType == GC_EVENT_CONTROL) {
+ switch (wp) {
+ case WINDOW_HIDDEN:
+ {
+ SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule);
+ if (si) {
+ si->bInitDone = TRUE;
+ SetActiveSession(si->ptszID, si->pszModule);
+ if (si->hWnd)
+ ShowRoom(si, wp, FALSE);
+ }
+ }
+ return 0;
+
+ case WINDOW_MINIMIZE:
+ case WINDOW_MAXIMIZE:
+ case WINDOW_VISIBLE:
+ case SESSION_INITDONE:
+ {
+ SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule);
+ if (si) {
+ si->bInitDone = TRUE;
+ if (wp != SESSION_INITDONE || M->GetByte("Chat", "PopupOnJoin", 0) == 0)
+ ShowRoom(si, wp, TRUE);
+ return 0;
+ } }
+ break;
+
+ case SESSION_OFFLINE:
+ SM_SetOffline(gce->pDest->ptszID, gce->pDest->pszModule);
+ // fall through
+
+ case SESSION_ONLINE:
+ SM_SetStatus(gce->pDest->ptszID, gce->pDest->pszModule, wp == SESSION_ONLINE ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE);
+ break;
+
+ case WINDOW_CLEARLOG:
+ {
+ SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule);
+ if (si) {
+ LM_RemoveAll(&si->pLog, &si->pLogEnd);
+ si->iEventCount = 0;
+ si->LastTime = 0;
+ }
+ break;
+ }
+ case SESSION_TERMINATE:
+ return SM_RemoveSession(gce->pDest->ptszID, gce->pDest->pszModule);
+ }
+ SM_SendMessage(gce->pDest->ptszID, gce->pDest->pszModule, GC_EVENT_CONTROL + WM_USER + 500, wp, 0);
+ }
+
+ else if (gce->pDest->iType == GC_EVENT_CHUID && gce->pszText)
+ {
+ SM_ChangeUID(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszNick, gce->ptszText);
+ }
+
+ else if (gce->pDest->iType == GC_EVENT_CHANGESESSIONAME && gce->pszText)
+ {
+ SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule);
+ if (si) {
+ replaceStr(&si->ptszName, gce->ptszText);
+ if (si->hWnd)
+ SendMessage(si->hWnd, GC_UPDATETITLE, 0, 0);
+ }
+ }
+
+ else if (gce->pDest->iType == GC_EVENT_SETITEMDATA) {
+ SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule);
+ if (si)
+ si->dwItemData = gce->dwItemData;
+ }
+
+ else if (gce->pDest->iType == GC_EVENT_GETITEMDATA) {
+ SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule);
+ if (si) {
+ gce->dwItemData = si->dwItemData;
+ return si->dwItemData;
+ }
+ return 0;
+ }
+ else if (gce->pDest->iType == GC_EVENT_SETSBTEXT)
+ {
+ SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule);
+ if (si) {
+ replaceStr(&si->ptszStatusbarText, gce->ptszText);
+ if (si->ptszStatusbarText)
+ M->WriteTString(si->hContact, si->pszModule, "StatusBar", si->ptszStatusbarText);
+ else
+ DBWriteContactSettingString(si->hContact, si->pszModule, "StatusBar", "");
+ if (si->hWnd) {
+ SendMessage(si->hWnd, GC_UPDATESTATUSBAR, 0, 0);
+ }
+ }
+ }
+ else if (gce->pDest->iType == GC_EVENT_ACK)
+ {
+ SM_SendMessage(gce->pDest->ptszID, gce->pDest->pszModule, GC_ACKMESSAGE, 0, 0);
+ }
+ else if (gce->pDest->iType == GC_EVENT_SENDMESSAGE && gce->pszText)
+ {
+ SM_SendUserMessage(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszText);
+ }
+ else if (gce->pDest->iType == GC_EVENT_SETSTATUSEX)
+ {
+ SM_SetStatusEx(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszText, gce->dwItemData);
+ }
+ else return 1;
+
+ return 0;
+}
+
+static void AddUser(GCEVENT * gce)
+{
+ SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule);
+ if (si) {
+ WORD status = TM_StringToWord(si->pStatuses, gce->ptszStatus);
+ USERINFO * ui = SM_AddUser(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID, gce->ptszNick, status);
+ if (ui) {
+ ui->pszNick = mir_tstrdup(gce->ptszNick);
+
+ if (gce->bIsMe)
+ si->pMe = ui;
+
+ ui->Status = status;
+ ui->Status |= si->pStatuses->Status;
+
+ if (si->hWnd) {
+ SendMessage(si->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0);
+ if(si->dat)
+ GetMyNick(si->dat);
+ }
+ }
+ }
+}
+
+HWND CreateNewRoom(TContainerData *pContainer, SESSION_INFO *si, BOOL bActivateTab, BOOL bPopupContainer, BOOL bWantPopup)
+{
+ TCHAR *contactName = NULL, newcontactname[128];
+ char *szProto, *szStatus;
+ WORD wStatus;
+ int newItem;
+ HWND hwndNew = 0;
+ struct TNewWindowData newData = {
+ 0
+ };
+ HANDLE hContact = si->hContact;
+ HWND hwndTab;
+
+ if (M->FindWindow(hContact) != 0)
+ return 0;
+ if (hContact != 0 && M->GetByte("limittabs", 0) && !_tcsncmp(pContainer->szName, _T("default"), 6)) {
+ if ((pContainer = FindMatchingContainer(_T("default"), hContact)) == NULL) {
+ TCHAR szName[CONTAINER_NAMELEN + 1];
+
+ _sntprintf(szName, CONTAINER_NAMELEN, _T("default"));
+ pContainer = CreateContainer(szName, CNT_CREATEFLAG_CLONED, hContact);
+ }
+ }
+ newData.hContact = hContact;
+ newData.isWchar = 0;
+ newData.szInitialText = NULL;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) newData.hContact, 0);
+
+ ZeroMemory((void *)&newData.item, sizeof(newData.item));
+
+ contactName = (TCHAR *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) newData.hContact, GCDNF_TCHAR);
+
+ /*
+ * cut nickname if larger than x chars...
+ */
+
+ if (contactName && lstrlen(contactName) > 0) {
+ if (M->GetByte("cuttitle", 0))
+ CutContactName(contactName, newcontactname, safe_sizeof(newcontactname));
+ else {
+ lstrcpyn(newcontactname, contactName, safe_sizeof(newcontactname));
+ newcontactname[127] = 0;
+ }
+ } else
+ lstrcpyn(newcontactname, _T("_U_"), sizeof(newcontactname) / sizeof(TCHAR));
+
+ wStatus = szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord((HANDLE) newData.hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ szStatus = (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord((HANDLE)newData.hContact, szProto, "Status", ID_STATUS_OFFLINE), 0);
+
+ newData.item.pszText = newcontactname;
+
+ newData.item.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
+ newData.item.iImage = 0;
+
+ hwndTab = GetDlgItem(pContainer->hwnd, 1159);
+
+ // hide the active tab
+ if (pContainer->hwndActive && bActivateTab)
+ ShowWindow(pContainer->hwndActive, SW_HIDE);
+
+ {
+ int iTabIndex_wanted = M->GetDword(hContact, "tabindex", pContainer->iChilds * 100);
+ int iCount = TabCtrl_GetItemCount(hwndTab);
+ TCITEM item = {0};
+ HWND hwnd;
+ struct TWindowData *dat;
+ int relPos;
+ int i;
+
+ pContainer->iTabIndex = iCount;
+ if (iCount > 0) {
+ for (i = iCount - 1; i >= 0; i--) {
+ item.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, i, &item);
+ hwnd = (HWND)item.lParam;
+ dat = (struct TWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (dat) {
+ relPos = M->GetDword(dat->hContact, "tabindex", i * 100);
+ if (iTabIndex_wanted <= relPos)
+ pContainer->iTabIndex = i;
+ }
+ }
+ }
+ }
+
+ newItem = TabCtrl_InsertItem(hwndTab, pContainer->iTabIndex, &newData.item);
+ SendMessage(hwndTab, EM_REFRESHWITHOUTCLIP, 0, 0);
+ if (bActivateTab)
+ TabCtrl_SetCurSel(hwndTab, newItem);
+ newData.iTabID = newItem;
+ newData.iTabImage = newData.item.iImage;
+ newData.pContainer = pContainer;
+ newData.iActivate = (int) bActivateTab;
+ pContainer->iChilds++;
+ newData.bWantPopup = bWantPopup;
+ newData.hdbEvent = (HANDLE)si;
+ hwndNew = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CHANNEL), GetDlgItem(pContainer->hwnd, 1159), RoomWndProc, (LPARAM) & newData);
+ if(pContainer->dwFlags & CNT_SIDEBAR) {
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(hwndNew, GWLP_USERDATA);
+ if(dat)
+ pContainer->SideBar->addSession(dat, pContainer->iTabIndex);
+ }
+ SendMessage(pContainer->hwnd, WM_SIZE, 0, 0);
+ // if the container is minimized, then pop it up...
+ if (IsIconic(pContainer->hwnd)) {
+ if (bPopupContainer) {
+ SendMessage(pContainer->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+ SetFocus(pContainer->hwndActive);
+ } else {
+ if (pContainer->dwFlags & CNT_NOFLASH)
+ SendMessage(pContainer->hwnd, DM_SETICON, 0, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE));
+ else
+ FlashContainer(pContainer, 1, 0);
+ }
+ }
+ if (bActivateTab) {
+ if (PluginConfig.m_HideOnClose && !IsWindowVisible(pContainer->hwnd)){
+ WINDOWPLACEMENT wp={0};
+ wp.length = sizeof(wp);
+ GetWindowPlacement(pContainer->hwnd, &wp);
+
+ BroadCastContainer(pContainer, DM_CHECKSIZE, 0, 0); // make sure all tabs will re-check layout on activation
+ if(wp.showCmd == SW_SHOWMAXIMIZED)
+ ShowWindow(pContainer->hwnd, SW_SHOWMAXIMIZED);
+ else {
+ if(bPopupContainer)
+ ShowWindow(pContainer->hwnd, SW_SHOWNORMAL);
+ else
+ ShowWindow(pContainer->hwnd, SW_SHOWMINNOACTIVE);
+ }
+ SendMessage(pContainer->hwndActive, WM_SIZE, 0, 0);
+ SetFocus(hwndNew);
+ }
+ else {
+ SetFocus(hwndNew);
+ RedrawWindow(pContainer->hwnd, NULL, NULL, RDW_INVALIDATE);
+ UpdateWindow(pContainer->hwnd);
+ if (GetForegroundWindow() != pContainer->hwnd && bPopupContainer == TRUE)
+ SetForegroundWindow(pContainer->hwnd);
+ }
+ }
+ if(PluginConfig.m_bIsWin7 && PluginConfig.m_useAeroPeek && CSkin::m_skinEnabled && !M->GetByte("forceAeroPeek", 0))
+ CWarning::show(CWarning::WARN_AEROPEEK_SKIN, CWarning::CWF_UNTRANSLATED|MB_ICONWARNING|MB_OK);
+ return hwndNew; // return handle of the new dialog
+}
+
+void ShowRoom(SESSION_INFO* si, WPARAM wp, BOOL bSetForeground)
+{
+ if (!si)
+ return;
+
+ if (si->hWnd == NULL) {
+ TCHAR szName[CONTAINER_NAMELEN + 2];
+ struct TContainerData *pContainer = si->pContainer;
+
+ szName[0] = 0;
+ if (pContainer == NULL) {
+ GetContainerNameForContact(si->hContact, szName, CONTAINER_NAMELEN);
+ if (!g_Settings.OpenInDefault && !_tcscmp(szName, _T("default")))
+ _tcsncpy(szName, _T("Chat Rooms"), CONTAINER_NAMELEN);
+ szName[CONTAINER_NAMELEN] = 0;
+ pContainer = FindContainerByName(szName);
+ }
+ if (pContainer == NULL)
+ pContainer = CreateContainer(szName, FALSE, si->hContact);
+ si->hWnd = CreateNewRoom(pContainer, si, TRUE, TRUE, FALSE);
+ } else
+ ActivateExistingTab(si->pContainer, si->hWnd);
+}
+
+INT_PTR Service_AddEvent(WPARAM wParam, LPARAM lParam)
+{
+ GCEVENT *gce = (GCEVENT*)lParam;
+ GCDEST *gcd = NULL;
+ GCEVENT save_gce;
+ GCDEST save_gcd;
+ TCHAR* pWnd = NULL;
+ char* pMod = NULL;
+ BOOL bIsHighlighted = FALSE;
+ BOOL bRemoveFlag = FALSE;
+ int iRetVal = GC_EVENT_ERROR;
+ SESSION_INFO *si = NULL;
+ BOOL fFreeText = FALSE;
+
+ if (CMimAPI::m_shutDown)
+ return 0;
+
+ if (gce == NULL)
+ return GC_EVENT_ERROR;
+
+ gcd = gce->pDest;
+ if (gcd == NULL)
+ return GC_EVENT_ERROR;
+
+ if (gce->cbSize != SIZEOF_STRUCT_GCEVENT_V1 && gce->cbSize != SIZEOF_STRUCT_GCEVENT_V2)
+ return GC_EVENT_WRONGVER;
+
+ if (!IsEventSupported(gcd->iType))
+ return GC_EVENT_ERROR;
+
+ if (!(gce->dwFlags & GC_UNICODE)) {
+ save_gce = *gce;
+ save_gcd = *gce->pDest;
+ gce->pDest->ptszID = a2tf(gce->pDest->ptszID, gce->dwFlags, 0);
+ gce->ptszUID = a2tf(gce->ptszUID, gce->dwFlags, 0);
+ gce->ptszNick = a2tf(gce->ptszNick, gce->dwFlags, 0);
+ gce->ptszStatus = a2tf(gce->ptszStatus, gce->dwFlags, 0);
+ if (gcd->iType != GC_EVENT_MESSAGE && gcd->iType != GC_EVENT_ACTION) {
+ gce->ptszText = a2tf(gce->ptszText, gce->dwFlags, 0);
+ fFreeText = TRUE;
+ }
+ gce->ptszUserInfo = a2tf(gce->ptszUserInfo, gce->dwFlags, 0);
+ }
+
+ EnterCriticalSection(&cs);
+
+ // Do different things according to type of event
+ switch (gcd->iType) {
+ case GC_EVENT_ADDGROUP:
+ {
+ STATUSINFO* si = SM_AddStatus(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszStatus);
+ if (si && gce->dwItemData)
+ si->hIcon = CopyIcon((HICON)gce->dwItemData);
+ }
+ iRetVal = 0;
+ goto LBL_Exit;
+
+ case GC_EVENT_CHUID:
+ case GC_EVENT_CHANGESESSIONAME:
+ case GC_EVENT_SETITEMDATA:
+ case GC_EVENT_GETITEMDATA:
+ case GC_EVENT_CONTROL:
+ case GC_EVENT_SETSBTEXT:
+ case GC_EVENT_ACK:
+ case GC_EVENT_SENDMESSAGE :
+ case GC_EVENT_SETSTATUSEX :
+ iRetVal = DoControl(gce, wParam);
+ goto LBL_Exit;
+
+ case GC_EVENT_SETCONTACTSTATUS:
+ iRetVal = SM_SetContactStatus(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID, (WORD)gce->dwItemData);
+ goto LBL_Exit;
+
+ case GC_EVENT_TOPIC: {
+ si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule);
+ if (si) {
+ if (gce->pszText) {
+ replaceStr(&si->ptszTopic, RemoveFormatting(gce->ptszText));
+ M->WriteTString(si->hContact, si->pszModule , "Topic", /*RemoveFormatting*/(si->ptszTopic));
+ if (M->GetByte("Chat", "TopicOnClist", 1))
+ M->WriteTString(si->hContact, "CList" , "StatusMsg", /*RemoveFormatting*/(si->ptszTopic));
+ if(si->hWnd)
+ SendMessage(si->hWnd, DM_INVALIDATEPANEL, 0, 0);
+ }
+ }
+ break;
+ }
+ case GC_EVENT_ADDSTATUS:
+ SM_GiveStatus(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID, gce->ptszStatus);
+ if (!gce->bIsMe) {
+ bIsHighlighted = g_Settings.Highlight->match(gce, 0, CMUCHighlight::MATCH_NICKNAME);
+ }
+ break;
+
+ case GC_EVENT_REMOVESTATUS:
+ SM_TakeStatus(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID, gce->ptszStatus);
+ if (!gce->bIsMe) {
+ bIsHighlighted = g_Settings.Highlight->match(gce, 0, CMUCHighlight::MATCH_NICKNAME);
+ }
+ break;
+
+ case GC_EVENT_MESSAGE:
+ case GC_EVENT_ACTION: {
+ si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule);
+ if (!(gce->dwFlags & GC_UNICODE)) {
+ fFreeText = TRUE;
+ if (si)
+ gce->ptszText = a2tf(gce->ptszText, gce->dwFlags, M->GetDword(si->hContact, "ANSIcodepage", 0));
+ else
+ gce->ptszText = a2tf(gce->ptszText, gce->dwFlags, 0);
+ }
+ if (!gce->bIsMe && gce->pDest->pszID && gce->pszText) {
+ if (si)
+ bIsHighlighted = si->Highlight->match(gce, si, CMUCHighlight::MATCH_TEXT | CMUCHighlight::MATCH_NICKNAME);
+ }
+ }
+ break;
+
+ case GC_EVENT_NICK:
+ SM_ChangeNick(gce->pDest->ptszID, gce->pDest->pszModule, gce);
+ if (!gce->bIsMe) {
+ bIsHighlighted = g_Settings.Highlight->match(gce, 0, CMUCHighlight::MATCH_NICKNAME);
+ }
+
+ break;
+
+ case GC_EVENT_JOIN:
+ AddUser(gce);
+ if (!gce->bIsMe) {
+ bIsHighlighted = g_Settings.Highlight->match(gce, 0, CMUCHighlight::MATCH_NICKNAME);
+ }
+ break;
+
+ case GC_EVENT_PART:
+ case GC_EVENT_QUIT:
+ case GC_EVENT_KICK:
+ bRemoveFlag = TRUE;
+ if (!gce->bIsMe) {
+ bIsHighlighted = g_Settings.Highlight->match(gce, 0, CMUCHighlight::MATCH_NICKNAME);
+ }
+ break;
+ }
+
+ // Decide which window (log) should have the event
+ if (gcd->pszID) {
+ pWnd = gcd->ptszID;
+ pMod = gcd->pszModule;
+ }
+ else if ( gcd->iType == GC_EVENT_NOTICE || gcd->iType == GC_EVENT_INFORMATION ) {
+ SESSION_INFO* si = GetActiveSession();
+ if (si && !lstrcmpA(si->pszModule, gcd->pszModule)) {
+ pWnd = si->ptszID;
+ pMod = si->pszModule;
+ }
+ else {
+ iRetVal = 0;
+ goto LBL_Exit;
+ }
+ }
+ else {
+ // Send the event to all windows with a user pszUID. Used for broadcasting QUIT etc
+ SM_AddEventToAllMatchingUID(gce, bIsHighlighted);
+ if (!bRemoveFlag) {
+ iRetVal = 0;
+ goto LBL_Exit;
+ } }
+
+ // add to log
+ if (pWnd) {
+ if (si == NULL)
+ si = SM_FindSession(pWnd, pMod);
+
+ // fix for IRC's old stuyle mode notifications. Should not affect any other protocol
+ if ((gce->pDest->iType == GC_EVENT_ADDSTATUS || gce->pDest->iType == GC_EVENT_REMOVESTATUS) && !(gce->dwFlags & GCEF_ADDTOLOG)) {
+ iRetVal = 0;
+ goto LBL_Exit;
+ }
+
+ if (gce && gce->pDest->iType == GC_EVENT_JOIN && gce->time == 0) {
+ iRetVal = 0;
+ goto LBL_Exit;
+ }
+
+ if (si && (si->bInitDone || gce->pDest->iType == GC_EVENT_TOPIC || (gce->pDest->iType == GC_EVENT_JOIN && gce->bIsMe))) {
+ if (SM_AddEvent(pWnd, pMod, gce, bIsHighlighted) && si->hWnd) {
+ SendMessage(si->hWnd, GC_ADDLOG, 0, 0);
+ }
+ else if (si->hWnd) {
+ SendMessage(si->hWnd, GC_REDRAWLOG2, 0, 0);
+ }
+ DoSoundsFlashPopupTrayStuff(si, gce, bIsHighlighted, 0);
+ if ((gce->dwFlags & GCEF_ADDTOLOG) && g_Settings.LoggingEnabled)
+ LogToFile(si, gce);
+ }
+
+ if (!bRemoveFlag) {
+ iRetVal = 0;
+ goto LBL_Exit;
+ } }
+
+ if (bRemoveFlag)
+ iRetVal = (SM_RemoveUser(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID) == 0) ? 1 : 0;
+
+LBL_Exit:
+ LeaveCriticalSection(&cs);
+
+ if (!(gce->dwFlags & GC_UNICODE)) {
+ if (fFreeText)
+ mir_free((void*)gce->ptszText);
+ mir_free((void*)gce->ptszNick);
+ mir_free((void*)gce->ptszUID);
+ mir_free((void*)gce->ptszStatus);
+ mir_free((void*)gce->ptszUserInfo);
+ mir_free((void*)gce->pDest->ptszID);
+ *gce = save_gce;
+ *gce->pDest = save_gcd;
+ }
+ return iRetVal;
+}
+
+static INT_PTR Service_GetAddEventPtr(WPARAM wParam, LPARAM lParam)
+{
+ GCPTRS * gp = (GCPTRS *) lParam;
+
+ EnterCriticalSection(&cs);
+
+ gp->pfnAddEvent = Service_AddEvent;
+ LeaveCriticalSection(&cs);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Service creation
+
+void HookEvents(void)
+{
+ InitializeCriticalSection(&cs);
+ g_hHookPrebuildMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, CList_PrebuildContactMenu); // MIRANDAHOOK should return INT_PTR too
+}
+
+void UnhookEvents(void)
+{
+ UnhookEvent(g_hHookPrebuildMenu);
+ DeleteCriticalSection(&cs);
+}
+
+int CreateServiceFunctions(void)
+{
+ PluginConfig.m_chat_enabled = false;
+
+ if(ServiceExists(MS_GC_REGISTER)) {
+ LRESULT result = CWarning::show(CWarning::WARN_CHAT_ENABLED, CWarning::CWF_NOALLOWHIDE | CWarning::CWF_UNTRANSLATED | MB_YESNOCANCEL | MB_ICONQUESTION);
+ if(result == IDYES)
+ M->WriteByte("PluginDisable", "chat.dll", 1);
+ return(0);
+ }
+ PluginConfig.m_chat_enabled = true;
+
+ hServiceRegister = CreateServiceFunction(MS_GC_REGISTER, Service_Register);
+ hServiceNewChat = CreateServiceFunction(MS_GC_NEWSESSION, Service_NewChat);
+ hServiceAddEvent = CreateServiceFunction(MS_GC_EVENT, Service_AddEvent);
+ hServiceGetAddEventPtr = CreateServiceFunction(MS_GC_GETEVENTPTR, Service_GetAddEventPtr);
+ hServiceGetInfo = CreateServiceFunction(MS_GC_GETINFO, Service_GetInfo);
+ hServiceGetCount = CreateServiceFunction(MS_GC_GETSESSIONCOUNT, Service_GetCount);
+
+ hEventDoubleclicked = CreateServiceFunction("GChat/DblClickEvent", CList_EventDoubleclicked);
+ hEventPrebuildMenu = CreateServiceFunction("GChat/PrebuildMenuEvent", CList_PrebuildContactMenuSvc);
+ hEventJoinChat = CreateServiceFunction("GChat/JoinChat", CList_JoinChat);
+ hEventLeaveChat = CreateServiceFunction("GChat/LeaveChat", CList_LeaveChat);
+ return(1);
+}
+
+void DestroyServiceFunctions(void)
+{
+ DestroyServiceFunction(hServiceRegister);
+ DestroyServiceFunction(hServiceNewChat);
+ DestroyServiceFunction(hServiceAddEvent);
+ DestroyServiceFunction(hServiceGetAddEventPtr);
+ DestroyServiceFunction(hServiceGetInfo);
+ DestroyServiceFunction(hServiceGetCount);
+ DestroyServiceFunction(hEventDoubleclicked);
+ DestroyServiceFunction(hEventPrebuildMenu);
+ DestroyServiceFunction(hEventJoinChat);
+ DestroyServiceFunction(hEventLeaveChat);
+}
+
+void CreateHookableEvents(void)
+{
+ hSendEvent = CreateHookableEvent(ME_GC_EVENT);
+ hBuildMenuEvent = CreateHookableEvent(ME_GC_BUILDMENU);
+}
+
+void DestroyHookableEvents(void)
+{
+ DestroyHookableEvent(hSendEvent);
+ DestroyHookableEvent(hBuildMenuEvent);
+}
+
diff --git a/plugins/TabSRMM/chat/tools.cpp b/plugins/TabSRMM/chat/tools.cpp
new file mode 100644
index 0000000000..0726a01869
--- /dev/null
+++ b/plugins/TabSRMM/chat/tools.cpp
@@ -0,0 +1,1351 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * This code is based on and still contains large parts of the the
+ * original chat module for Miranda IM, written and copyrighted
+ * by Joergen Persson in 2005.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: tools.cpp 13650 2011-05-30 11:53:13Z silvercircle@gmail.com $
+ *
+ * Helper functions for the group chat module.
+ *
+ */
+
+#include "../src/commonheaders.h"
+
+// externs
+extern HICON hIcons[30];
+extern FONTINFO aFonts[OPTIONS_FONTCOUNT];
+extern HMENU g_hMenu;
+extern HANDLE hBuildMenuEvent ;
+extern HANDLE hSendEvent;
+
+int GetRichTextLength(HWND hwnd)
+{
+ GETTEXTLENGTHEX gtl;
+
+ gtl.flags = GTL_PRECISE;
+ gtl.codepage = CP_ACP ;
+ return (int) SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
+}
+
+/**
+ * @param pszWord string to strip of any IRC-style
+ * formatting
+ * @param fToLower convert to lowercase
+ * @param fStripCR strip cr/lf sequences (only for highlighter, defaults to false)
+ * @param buf caller-provided buffer, use a static one
+ * when the caller does not provide a
+ * buffer
+ * caller provided buffer is NEEDED to make
+ * this thread-safe.
+ *
+ * @return TCHAR* the stripped string
+ */
+TCHAR* RemoveFormatting(const TCHAR* pszWord, bool fToLower, bool fStripCR, TCHAR* buf, const size_t len)
+{
+ static TCHAR _szTemp[20000];
+ TCHAR* szTemp = 0;
+ size_t _buflen = 0;
+
+ if(0 == buf) {
+ szTemp = _szTemp;
+ _buflen = 20000;
+ } else {
+ szTemp = buf;
+ _buflen = len;
+ szTemp[len - 1] = 0;
+ }
+
+ size_t i = 0;
+ size_t j = 0;
+
+ if (pszWord == 0)
+ return NULL;
+
+ size_t wordlen = lstrlen(pszWord);
+
+ while (j < _buflen && i <= wordlen) {
+ if (pszWord[i] == '%') {
+ switch (pszWord[i+1]) {
+ case '%':
+ szTemp[j] = '%';
+ j++;
+ i++;
+ i++;
+ break;
+ case 'b':
+ case 'u':
+ case 'i':
+ case 'B':
+ case 'U':
+ case 'I':
+ case 'r':
+ case 'C':
+ case 'F':
+ i++;
+ i++;
+ break;
+
+ case 'c':
+ case 'f':
+ i += 4;
+ break;
+
+ default:
+ szTemp[j] = pszWord[i];
+ j++;
+ i++;
+ break;
+ }
+ } else {
+ if(fStripCR) {
+ if(0x0a == pszWord[i] || 0x0c == pszWord[i]) {
+ szTemp[j++] = ' ';
+ i++;
+ continue;
+ }
+ }
+ szTemp[j] = pszWord[i];
+ j++;
+ i++;
+ }
+ }
+ if(fToLower) {
+ _wsetlocale(LC_ALL, L"");
+ wcslwr(szTemp);
+ }
+ return(szTemp);
+}
+
+static void __stdcall ShowRoomFromPopup(void * pi)
+{
+ SESSION_INFO* si = (SESSION_INFO*) pi;
+ ShowRoom(si, WINDOW_VISIBLE, TRUE);
+}
+
+static void TSAPI Chat_OpenPopup(SESSION_INFO* si, HWND hwndPopup)
+{
+ CallFunctionAsync(ShowRoomFromPopup, si);
+ PUDeletePopUp(hwndPopup);
+}
+
+static void TSAPI Chat_DismissPopup(const SESSION_INFO* si, HWND hwndPopup)
+{
+ if (si->hContact)
+ if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->hContact, (LPARAM)0))
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->hContact, (LPARAM)szChatIconString);
+
+ if (si->hWnd && KillTimer(si->hWnd, TIMERID_FLASHWND))
+ FlashWindow(si->hWnd, FALSE);
+
+ PUDeletePopUp(hwndPopup);
+}
+
+static INT_PTR CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_COMMAND:
+ if (HIWORD(wParam) == STN_CLICKED) {
+ SESSION_INFO* si = (SESSION_INFO*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, (LPARAM)0);;
+
+ if(si) {
+ if(nen_options.maskActL & MASK_OPEN)
+ Chat_OpenPopup(si, hWnd);
+ else
+ Chat_DismissPopup(si, hWnd);
+ }
+ return TRUE;
+ }
+ break;
+ case WM_CONTEXTMENU: {
+ SESSION_INFO* si = (SESSION_INFO*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, (LPARAM)0);
+
+ if(si && si->hContact) {
+ if(nen_options.maskActR & MASK_OPEN)
+ Chat_OpenPopup(si, hWnd);
+ else
+ Chat_DismissPopup(si, hWnd);
+ }
+ }
+ break;
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+static int ShowPopup(HANDLE hContact, SESSION_INFO* si, HICON hIcon, char* pszProtoName, TCHAR* pszRoomName, COLORREF crBkg, const TCHAR* fmt, ...)
+{
+ POPUPDATAT_V2 pd = {0};
+ va_list marker;
+ static TCHAR szBuf[4*1024];
+
+ if (!fmt || lstrlen(fmt) == 0 || lstrlen(fmt) > 2000)
+ return 0;
+
+ va_start(marker, fmt);
+ _vstprintf(szBuf, fmt, marker);
+ va_end(marker);
+
+ pd.lchContact = hContact;
+
+ if (hIcon)
+ pd.lchIcon = hIcon ;
+ else
+ pd.lchIcon = LoadIconEx(IDI_CHANMGR, "window", 0, 0);
+
+ mir_sntprintf(pd.lptzContactName, MAX_CONTACTNAME - 1, _T(TCHAR_STR_PARAM) _T(" - %s"),
+ pszProtoName, CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR));
+ lstrcpyn(pd.lptzText, TranslateTS(szBuf), MAX_SECONDLINE - 1);
+ pd.iSeconds = g_Settings.iPopupTimeout;
+
+ if (g_Settings.iPopupStyle == 2) {
+ pd.colorBack = 0;
+ pd.colorText = 0;
+ } else if (g_Settings.iPopupStyle == 3) {
+ pd.colorBack = g_Settings.crPUBkgColour;
+ pd.colorText = g_Settings.crPUTextColour;
+ } else {
+ pd.colorBack = M->GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR_MUC, SRMSGDEFSET_BKGCOLOUR);
+ pd.colorText = crBkg;
+ }
+
+ pd.PluginWindowProc = (WNDPROC)PopupDlgProc;
+ pd.PluginData = si;
+ return PUAddPopUpT(&pd);
+}
+
+static BOOL DoTrayIcon(SESSION_INFO* si, GCEVENT * gce)
+{
+ int iEvent = gce->pDest->iType;
+
+ if (si && (iEvent & si->iLogTrayFlags)) {
+ switch (iEvent) {
+ case GC_EVENT_MESSAGE | GC_EVENT_HIGHLIGHT :
+ case GC_EVENT_ACTION | GC_EVENT_HIGHLIGHT :
+ CList_AddEvent(si->hContact, PluginConfig.g_IconMsgEvent, szChatIconString, 0,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_HILIGHT), gce->ptszNick, si->ptszName);
+ break;
+ case GC_EVENT_MESSAGE :
+ CList_AddEvent(si->hContact, hIcons[ICON_MESSAGE], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_MSG), gce->ptszNick, si->ptszName);
+ break;
+ case GC_EVENT_ACTION:
+ CList_AddEvent(si->hContact, hIcons[ICON_ACTION], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_MSG), gce->ptszNick, si->ptszName);
+ break;
+ case GC_EVENT_JOIN:
+ CList_AddEvent(si->hContact, hIcons[ICON_JOIN], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_JOINED), gce->ptszNick, si->ptszName);
+ break;
+ case GC_EVENT_PART:
+ CList_AddEvent(si->hContact, hIcons[ICON_PART], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_LEFT), gce->ptszNick, si->ptszName);
+ break;
+ case GC_EVENT_QUIT:
+ CList_AddEvent(si->hContact, hIcons[ICON_QUIT], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_QUIT), gce->ptszNick);
+ break;
+ case GC_EVENT_NICK:
+ CList_AddEvent(si->hContact, hIcons[ICON_NICK], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_NICK), gce->ptszNick, gce->pszText);
+ break;
+ case GC_EVENT_KICK:
+ CList_AddEvent(si->hContact, hIcons[ICON_KICK], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_KICK), gce->pszStatus, gce->ptszNick, si->ptszName);
+ break;
+ case GC_EVENT_NOTICE:
+ CList_AddEvent(si->hContact, hIcons[ICON_NOTICE], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_NOTICE), gce->ptszNick);
+ break;
+ case GC_EVENT_TOPIC:
+ CList_AddEvent(si->hContact, hIcons[ICON_TOPIC], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_TOPIC), si->ptszName);
+ break;
+ case GC_EVENT_INFORMATION:
+ CList_AddEvent(si->hContact, hIcons[ICON_INFO], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_INFO), si->ptszName);
+ break;
+ case GC_EVENT_ADDSTATUS:
+ CList_AddEvent(si->hContact, hIcons[ICON_ADDSTATUS], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_STATUS_ON), gce->pszText, gce->pszStatus, gce->ptszNick, si->ptszName);
+ break;
+ case GC_EVENT_REMOVESTATUS:
+ CList_AddEvent(si->hContact, hIcons[ICON_REMSTATUS], szChatIconString, CLEF_ONLYAFEW,
+ CTranslator::get(CTranslator::GEN_MUC_TRAY_STATUS_OFF), gce->pszText, gce->pszStatus, gce->ptszNick, si->ptszName);
+ break;
+ }
+ }
+ return TRUE;
+}
+
+static BOOL DoPopup(SESSION_INFO* si, GCEVENT* gce, struct TWindowData* dat)
+{
+ int iEvent = gce->pDest->iType;
+ struct TContainerData *pContainer = dat ? dat->pContainer : NULL;
+ char *szProto = dat ? dat->szProto : si->pszModule;
+
+ TCHAR *bbStart, *bbEnd;
+ if (g_Settings.BBCodeInPopups)
+ {
+ bbStart = _T("[b]");
+ bbEnd = _T("[/b]");
+ } else
+ {
+ bbStart = bbEnd = _T("");
+ }
+
+ if (si && (iEvent & si->iLogPopupFlags)) {
+
+ if (nen_options.iMUCDisable) // no popups at all. Period
+ return 0;
+ /*
+ * check the status mode against the status mask
+ */
+
+ if (nen_options.dwStatusMask != -1) {
+ DWORD dwStatus = 0;
+ if (szProto != NULL) {
+ dwStatus = (DWORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ if (!(dwStatus == 0 || dwStatus <= ID_STATUS_OFFLINE || ((1 << (dwStatus - ID_STATUS_ONLINE)) & nen_options.dwStatusMask))) // should never happen, but...
+ return 0;
+ }
+ }
+ if (dat && pContainer != 0) { // message window is open, need to check the container config if we want to see a popup nonetheless
+ if (nen_options.bWindowCheck) { // no popups at all for open windows... no exceptions
+ if(!PluginConfig.m_HideOnClose)
+ return(0);
+ if(pContainer->fHidden)
+ goto passed;
+ return(0);
+ }
+ if (pContainer->dwFlags & CNT_DONTREPORT && IsIconic(pContainer->hwnd)) // in tray counts as "minimised"
+ goto passed;
+ if (pContainer->dwFlags & CNT_DONTREPORTUNFOCUSED) {
+ if (!IsIconic(pContainer->hwnd) && GetForegroundWindow() != pContainer->hwnd && GetActiveWindow() != pContainer->hwnd)
+ goto passed;
+ }
+ if (pContainer->dwFlags & CNT_ALWAYSREPORTINACTIVE) {
+ if (pContainer->dwFlags & CNT_DONTREPORTFOCUSED)
+ goto passed;
+
+ if (pContainer->hwndActive == si->hWnd)
+ return 0;
+
+ goto passed;
+ }
+ return 0;
+ }
+passed:
+ int iNewEvent = iEvent;
+ COLORREF clr = 0;
+
+ if((iNewEvent & GC_EVENT_HIGHLIGHT)) {
+ clr = aFonts[16].color;
+ iNewEvent &= ~GC_EVENT_HIGHLIGHT;
+ }
+ switch (iNewEvent) {
+ case GC_EVENT_MESSAGE :
+ ShowPopup(si->hContact, si, hIcons[ICON_MESSAGE], si->pszModule, si->ptszName, clr ? clr : aFonts[9].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_MSG), bbStart, gce->ptszNick, bbEnd, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_ACTION:
+ ShowPopup(si->hContact, si, hIcons[ICON_ACTION], si->pszModule, si->ptszName, clr ? clr : aFonts[15].color, _T("%s %s"), gce->ptszNick, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_JOIN:
+ ShowPopup(si->hContact, si, hIcons[ICON_JOIN], si->pszModule, si->ptszName, clr ? clr : aFonts[3].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_JOINED), gce->ptszNick);
+ break;
+ case GC_EVENT_PART:
+ if (!gce->pszText)
+ ShowPopup(si->hContact, si, hIcons[ICON_PART], si->pszModule, si->ptszName, clr ? clr : aFonts[4].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_LEFT), gce->ptszNick);
+ else
+ ShowPopup(si->hContact, si, hIcons[ICON_PART], si->pszModule, si->ptszName, clr ? clr : aFonts[4].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_LEFT1), gce->ptszNick, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_QUIT:
+ if (!gce->pszText)
+ ShowPopup(si->hContact, si, hIcons[ICON_QUIT], si->pszModule, si->ptszName, clr ? clr : aFonts[5].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_QUIT), gce->ptszNick);
+ else
+ ShowPopup(si->hContact, si, hIcons[ICON_QUIT], si->pszModule, si->ptszName, clr ? clr : aFonts[5].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_QUIT1), gce->ptszNick, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_NICK:
+ ShowPopup(si->hContact, si, hIcons[ICON_NICK], si->pszModule, si->ptszName, clr ? clr : aFonts[7].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_NICK), gce->ptszNick, gce->ptszText);
+ break;
+ case GC_EVENT_KICK:
+ if (!gce->pszText)
+ ShowPopup(si->hContact, si, hIcons[ICON_KICK], si->pszModule, si->ptszName, clr ? clr : aFonts[6].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_KICK), (char *)gce->pszStatus, gce->ptszNick);
+ else
+ ShowPopup(si->hContact, si, hIcons[ICON_KICK], si->pszModule, si->ptszName, clr ? clr : aFonts[6].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_KICK1), (char *)gce->pszStatus, gce->ptszNick, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_NOTICE:
+ ShowPopup(si->hContact, si, hIcons[ICON_NOTICE], si->pszModule, si->ptszName, clr ? clr : aFonts[8].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_NOTICE), gce->ptszNick, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_TOPIC:
+ if (!gce->ptszNick)
+ ShowPopup(si->hContact, si, hIcons[ICON_TOPIC], si->pszModule, si->ptszName, clr ? clr : aFonts[11].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_TOPIC), RemoveFormatting(gce->ptszText));
+ else
+ ShowPopup(si->hContact, si, hIcons[ICON_TOPIC], si->pszModule, si->ptszName, clr ? clr : aFonts[11].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_TOPIC1), RemoveFormatting(gce->ptszText), gce->ptszNick);
+ break;
+ case GC_EVENT_INFORMATION:
+ ShowPopup(si->hContact, si, hIcons[ICON_INFO], si->pszModule, si->ptszName, clr ? clr : aFonts[12].color, _T("%s"), RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_ADDSTATUS:
+ ShowPopup(si->hContact, si, hIcons[ICON_ADDSTATUS], si->pszModule, si->ptszName, clr ? clr : aFonts[13].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_STATUS_ON), gce->ptszText, (char *)gce->pszStatus, gce->ptszNick);
+ break;
+ case GC_EVENT_REMOVESTATUS:
+ ShowPopup(si->hContact, si, hIcons[ICON_REMSTATUS], si->pszModule, si->ptszName, clr ? clr : aFonts[14].color,
+ CTranslator::get(CTranslator::GEN_MUC_POPUP_STATUS_OFF), gce->ptszText, (char *)gce->pszStatus, gce->ptszNick);
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+void TSAPI DoFlashAndSoundWorker(FLASH_PARAMS* p)
+{
+ SESSION_INFO* si = SM_FindSessionByHCONTACT(p->hContact);
+ TWindowData* dat = 0;
+
+ if(si == 0)
+ return;
+
+ if (si->hWnd) {
+ dat = si->dat;
+ if (dat) {
+ p->bInactive = dat->pContainer->hwnd != GetForegroundWindow();
+ p->bActiveTab = (dat->pContainer->hwndActive == si->hWnd);
+ }
+ if (p->sound && Utils::mustPlaySound(si->dat))
+ SkinPlaySound(p->sound);
+ }
+ else if(p->sound)
+ SkinPlaySound(p->sound);
+
+ if (dat) {
+ HWND hwndTab = GetParent(si->hWnd);
+ BOOL bForcedIcon = (p->hNotifyIcon == hIcons[ICON_HIGHLIGHT] || p->hNotifyIcon == hIcons[ICON_MESSAGE]);
+
+ if ((p->iEvent & si->iLogTrayFlags) || bForcedIcon) {
+ if (!p->bActiveTab) {
+ if (p->hNotifyIcon == hIcons[ICON_HIGHLIGHT])
+ dat->iFlashIcon = p->hNotifyIcon;
+ else {
+ if (dat->iFlashIcon != hIcons[ICON_HIGHLIGHT] && dat->iFlashIcon != hIcons[ICON_MESSAGE])
+ dat->iFlashIcon = p->hNotifyIcon;
+ }
+ dat->mayFlashTab = TRUE;
+ SetTimer(si->hWnd, TIMERID_FLASHWND, TIMEOUT_FLASHWND, NULL);
+ }
+ }
+ if(dat->pWnd) {
+ dat->pWnd->updateIcon(p->hNotifyIcon);
+ dat->pWnd->setOverlayIcon(p->hNotifyIcon, true);
+ }
+
+ // autoswitch tab..
+ if (p->bMustAutoswitch) {
+ if ((IsIconic(dat->pContainer->hwnd)) && !IsZoomed(dat->pContainer->hwnd) && PluginConfig.haveAutoSwitch() && dat->pContainer->hwndActive != si->hWnd) {
+ int iItem = GetTabIndexFromHWND(hwndTab, si->hWnd);
+ if (iItem >= 0) {
+ TabCtrl_SetCurSel(hwndTab, iItem);
+ ShowWindow(dat->pContainer->hwndActive, SW_HIDE);
+ dat->pContainer->hwndActive = si->hWnd;
+ SendMessage(dat->pContainer->hwnd, DM_UPDATETITLE, (WPARAM)dat->hContact, 0);
+ dat->pContainer->dwFlags |= CNT_DEFERREDTABSELECT;
+ }
+ }
+ }
+
+ /*
+ * flash window if it is not focused
+ */
+ if (p->bMustFlash && p->bInactive)
+ if (!(dat->pContainer->dwFlags & CNT_NOFLASH))
+ FlashContainer(dat->pContainer, 1, 0);
+
+ if (p->hNotifyIcon && p->bInactive && ((p->iEvent & si->iLogTrayFlags) || bForcedIcon)) {
+ HICON hIcon;
+
+ if (p->bMustFlash)
+ dat->hTabIcon = p->hNotifyIcon;
+ else if (dat->iFlashIcon) {
+ TCITEM item = {0};
+
+ dat->hTabIcon = dat->iFlashIcon;
+ item.mask = TCIF_IMAGE;
+ item.iImage = 0;
+ TabCtrl_SetItem(GetParent(si->hWnd), dat->iTabID, &item);
+ }
+ hIcon = (HICON)SendMessage(dat->pContainer->hwnd, WM_GETICON, ICON_BIG, 0);
+ if (p->hNotifyIcon == hIcons[ICON_HIGHLIGHT] || (hIcon != hIcons[ICON_MESSAGE] && hIcon != hIcons[ICON_HIGHLIGHT])) {
+ SendMessage(dat->pContainer->hwnd, DM_SETICON, (WPARAM)dat, (LPARAM)p->hNotifyIcon);
+ dat->pContainer->dwFlags |= CNT_NEED_UPDATETITLE;
+ }
+ }
+
+ if (p->bMustFlash && p->bInactive)
+ UpdateTrayMenu(dat, si->wStatus, si->pszModule, dat ? dat->szStatus : NULL, si->hContact, p->bHighlight ? 1 : 1);
+ }
+
+ free(p);
+}
+
+BOOL DoSoundsFlashPopupTrayStuff(SESSION_INFO* si, GCEVENT * gce, BOOL bHighlight, int bManyFix)
+{
+ FLASH_PARAMS* params;
+ struct TWindowData *dat = 0;
+ bool fFlagUnread = false;
+ WPARAM wParamForHighLight = 0;
+
+ if (gce == 0 || si == 0 || gce->bIsMe || si->iType == GCW_SERVER)
+ return FALSE;
+
+ params = (FLASH_PARAMS*)calloc(1, sizeof(FLASH_PARAMS));
+ params->hContact = si->hContact;
+ params->bInactive = TRUE;
+ if(si->hWnd && si->dat) {
+ dat = si->dat;
+ if((si->hWnd == si->dat->pContainer->hwndActive) && GetForegroundWindow() == si->dat->pContainer->hwnd)
+ params->bInactive = FALSE;
+ }
+ params->bActiveTab = params->bMustFlash = params->bMustAutoswitch = FALSE;
+
+ params->iEvent = gce->pDest->iType;
+
+ if (bHighlight) {
+ gce->pDest->iType |= GC_EVENT_HIGHLIGHT;
+ params->sound = "ChatHighlight";
+ if (M->GetByte(si->hContact, "CList", "Hidden", 0) != 0)
+ DBDeleteContactSetting(si->hContact, "CList", "Hidden");
+ if (params->bInactive) {
+ fFlagUnread = true;
+ DoTrayIcon(si, gce);
+ }
+
+ /* TODO fix for 3.0 final !!! */
+#if !defined(__DELAYED_FOR_3_1)
+ if(g_Settings.CreateWindowOnHighlight && 0 == dat)
+ wParamForHighLight = 1;
+
+ if(dat && g_Settings.AnnoyingHighlight && params->bInactive && dat->pContainer->hwnd != GetForegroundWindow()) {
+ wParamForHighLight = 2;
+ params->hWnd = dat->hwnd;
+ }
+#endif
+ if (dat || !nen_options.iMUCDisable)
+ DoPopup(si, gce, dat);
+ if (params->bInactive && si && si->hWnd)
+ SendMessage(si->hWnd, GC_SETMESSAGEHIGHLIGHT, 0, (LPARAM) si);
+ if (g_Settings.FlashWindowHightlight && params->bInactive)
+ params->bMustFlash = TRUE;
+ params->bMustAutoswitch = TRUE;
+ params->hNotifyIcon = hIcons[ICON_HIGHLIGHT];
+ } else {
+ // do blinking icons in tray
+ if (params->bInactive || !g_Settings.TrayIconInactiveOnly) {
+ DoTrayIcon(si, gce);
+ if(params->iEvent == GC_EVENT_MESSAGE)
+ fFlagUnread = true;
+ }
+ // stupid thing to not create multiple popups for a QUIT event for instance
+ if (bManyFix == 0) {
+ // do popups
+ if (dat || !nen_options.iMUCDisable)
+ DoPopup(si, gce, dat);
+
+ // do sounds and flashing
+ switch (params->iEvent) {
+ case GC_EVENT_JOIN:
+ params->sound = "ChatJoin";
+ if (params->bInactive)
+ params->hNotifyIcon = hIcons[ICON_JOIN];
+ break;
+ case GC_EVENT_PART:
+ params->sound = "ChatPart";
+ if (params->bInactive)
+ params->hNotifyIcon = hIcons[ICON_PART];
+ break;
+ case GC_EVENT_QUIT:
+ params->sound = "ChatQuit";
+ if (params->bInactive)
+ params->hNotifyIcon = hIcons[ICON_QUIT];
+ break;
+ case GC_EVENT_ADDSTATUS:
+ case GC_EVENT_REMOVESTATUS:
+ params->sound = "ChatMode";
+ if (params->bInactive)
+ params->hNotifyIcon = hIcons[params->iEvent == GC_EVENT_ADDSTATUS ? ICON_ADDSTATUS : ICON_REMSTATUS];
+ break;
+ case GC_EVENT_KICK:
+ params->sound = "ChatKick";
+ if (params->bInactive)
+ params->hNotifyIcon = hIcons[ICON_KICK];
+ break;
+ case GC_EVENT_MESSAGE:
+ params->sound = "ChatMessage";
+ if (params->bInactive && !(si->wState&STATE_TALK)) {
+ si->wState |= STATE_TALK;
+ DBWriteContactSettingWord(si->hContact, si->pszModule, "ApparentMode", (LPARAM)(WORD) 40071);
+ }
+ break;
+ case GC_EVENT_ACTION:
+ params->sound = "ChatAction";
+ if (params->bInactive)
+ params->hNotifyIcon = hIcons[ICON_ACTION];
+ break;
+ case GC_EVENT_NICK:
+ params->sound = "ChatNick";
+ if (params->bInactive)
+ params->hNotifyIcon = hIcons[ICON_NICK];
+ break;
+ case GC_EVENT_NOTICE:
+ params->sound = "ChatNotice";
+ if (params->bInactive)
+ params->hNotifyIcon = hIcons[ICON_NOTICE];
+ break;
+ case GC_EVENT_TOPIC:
+ params->sound = "ChatTopic";
+ if (params->bInactive)
+ params->hNotifyIcon = hIcons[ICON_TOPIC];
+ break;
+ }
+ } else {
+ switch (params->iEvent) {
+ case GC_EVENT_JOIN:
+ params->hNotifyIcon = hIcons[ICON_JOIN];
+ break;
+ case GC_EVENT_PART:
+ params->hNotifyIcon = hIcons[ICON_PART];
+ break;
+ case GC_EVENT_QUIT:
+ params->hNotifyIcon = hIcons[ICON_QUIT];
+ break;
+ case GC_EVENT_KICK:
+ params->hNotifyIcon = hIcons[ICON_KICK];
+ break;
+ case GC_EVENT_ACTION:
+ params->hNotifyIcon = hIcons[ICON_ACTION];
+ break;
+ case GC_EVENT_NICK:
+ params->hNotifyIcon = hIcons[ICON_NICK];
+ break;
+ case GC_EVENT_NOTICE:
+ params->hNotifyIcon = hIcons[ICON_NOTICE];
+ break;
+ case GC_EVENT_TOPIC:
+ params->hNotifyIcon = hIcons[ICON_TOPIC];
+ break;
+ case GC_EVENT_ADDSTATUS:
+ params->hNotifyIcon = hIcons[ICON_ADDSTATUS];
+ break;
+ case GC_EVENT_REMOVESTATUS:
+ params->hNotifyIcon = hIcons[ICON_REMSTATUS];
+ break;
+ }
+ }
+
+ if (params->iEvent == GC_EVENT_MESSAGE) {
+ params->bMustAutoswitch = TRUE;
+ if (g_Settings.FlashWindow)
+ params->bMustFlash = TRUE;
+ params->hNotifyIcon = hIcons[ICON_MESSAGE];
+ }
+ }
+ if(dat && fFlagUnread) {
+ dat->dwUnread++;
+ if(dat->pWnd)
+ dat->pWnd->Invalidate();
+ }
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_MUCFLASHWORKER, wParamForHighLight, (LPARAM)params);
+ return TRUE;
+}
+
+int Chat_GetColorIndex(const char* pszModule, COLORREF cr)
+{
+ MODULEINFO * pMod = MM_FindModule(pszModule);
+ int i = 0;
+
+ if (!pMod || pMod->nColorCount == 0)
+ return -1;
+
+ for (i = 0; i < pMod->nColorCount; i++)
+ if (pMod->crColors[i] == cr)
+ return i;
+
+ return -1;
+}
+
+// obscure function that is used to make sure that any of the colors
+// passed by the protocol is used as fore- or background color
+// in the messagebox. THis is to vvercome limitations in the richedit
+// that I do not know currently how to fix
+
+void CheckColorsInModule(const char* pszModule)
+{
+ MODULEINFO * pMod = MM_FindModule(pszModule);
+ int i = 0;
+ COLORREF crFG;
+ COLORREF crBG = (COLORREF)M->GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR);
+
+ LoadLogfont(MSGFONTID_MESSAGEAREA, NULL, &crFG, FONTMODULE);
+
+ if (!pMod)
+ return;
+
+ for (i = 0; i < pMod->nColorCount; i++) {
+ if (pMod->crColors[i] == crFG || pMod->crColors[i] == crBG) {
+ if (pMod->crColors[i] == RGB(255, 255, 255))
+ pMod->crColors[i]--;
+ else
+ pMod->crColors[i]++;
+ }
+ }
+}
+
+TCHAR* my_strstri(const TCHAR* s1, const TCHAR* s2)
+{
+ int i, j, k;
+
+ _tsetlocale(LC_ALL, _T(""));
+ for (i = 0;s1[i];i++)
+ for (j = i, k = 0; _totlower(s1[j]) == _totlower(s2[k]);j++, k++)
+ if (!s2[k+1])
+ return (TCHAR*)(s1 + i);
+
+ return NULL;
+}
+
+/*
+ * log the event to the log file
+ * allows selective logging of wanted events
+ */
+BOOL LogToFile(SESSION_INFO* si, GCEVENT * gce)
+{
+ MODULEINFO * mi = NULL;
+ TCHAR szBuffer[4096];
+ TCHAR szLine[4096];
+ TCHAR szTime[100];
+ FILE *hFile = NULL;
+ TCHAR tszFolder[MAX_PATH];
+ TCHAR p = '\0';
+ BOOL bFileJustCreated = TRUE;
+
+ if (!si || !gce)
+ return FALSE;
+
+ mi = MM_FindModule(si->pszModule);
+ if (!mi)
+ return FALSE;
+
+ /*
+ * check whether we have to log this event
+ */
+ if(!(gce->pDest->iType & si->iDiskLogFlags))
+ return FALSE;
+
+ szBuffer[0] = '\0';
+
+ GetChatLogsFilename(si, gce->time);
+ bFileJustCreated = !PathFileExists(si->pszLogFileName);
+ _tcscpy(tszFolder, si->pszLogFileName);
+ PathRemoveFileSpec(tszFolder);
+ if (!PathIsDirectory(tszFolder))
+ CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)tszFolder);
+
+ lstrcpyn(szTime, MakeTimeStamp(g_Settings.pszTimeStampLog, gce->time), 99);
+
+ hFile = _tfopen(si->pszLogFileName, _T("ab+"));
+ if (hFile) {
+ TCHAR szTemp[512], szTemp2[512];
+ TCHAR* pszNick = NULL;
+ if (bFileJustCreated)
+ fputws((const wchar_t*)"\377\376", hFile); //UTF-16 LE BOM == FF FE
+ if (gce->ptszNick) {
+ if (g_Settings.LogLimitNames && lstrlen(gce->ptszNick) > 20) {
+ lstrcpyn(szTemp2, gce->ptszNick, 20);
+ lstrcpyn(szTemp2 + 20, _T("..."), 4);
+ } else lstrcpyn(szTemp2, gce->ptszNick, 511);
+
+ if (gce->pszUserInfo)
+ mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s (%s)"), szTemp2, gce->pszUserInfo);
+ else
+ mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s"), szTemp2);
+ pszNick = szTemp;
+ }
+ switch (gce->pDest->iType) {
+ case GC_EVENT_MESSAGE:
+ case GC_EVENT_MESSAGE | GC_EVENT_HIGHLIGHT:
+ p = '*';
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), _T("%s: %s"), gce->ptszNick, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_ACTION:
+ case GC_EVENT_ACTION | GC_EVENT_HIGHLIGHT:
+ p = '*';
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), _T("%s %s"), gce->ptszNick, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_JOIN:
+ p = '>';
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_JOINED), (char *)pszNick);
+ break;
+ case GC_EVENT_PART:
+ p = '<';
+ if (!gce->pszText)
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_LEFT), (char *)pszNick);
+ else
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_LEFT1), (char *)pszNick, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_QUIT:
+ p = '<';
+ if (!gce->pszText)
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_QUIT), (char *)pszNick);
+ else
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_QUIT1), (char *)pszNick, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_NICK:
+ p = '^';
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_NICK), gce->ptszNick, gce->ptszText);
+ break;
+ case GC_EVENT_KICK:
+ p = '~';
+ if (!gce->pszText)
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_KICK), (char *)gce->pszStatus, gce->ptszNick);
+ else
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_KICK1), (char *)gce->pszStatus, gce->ptszNick, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_NOTICE:
+ p = 'o';
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_NOTICE), gce->ptszNick, RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_TOPIC:
+ p = '#';
+ if (!gce->pszNick)
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_TOPIC), RemoveFormatting(gce->ptszText));
+ else
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_TOPIC1), RemoveFormatting(gce->ptszText), gce->ptszNick);
+ break;
+ case GC_EVENT_INFORMATION:
+ p = '!';
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), _T("%s"), RemoveFormatting(gce->ptszText));
+ break;
+ case GC_EVENT_ADDSTATUS:
+ p = '+';
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_STATUS_ON), gce->ptszText, (char *)gce->pszStatus, gce->ptszNick);
+ break;
+ case GC_EVENT_REMOVESTATUS:
+ p = '-';
+ mir_sntprintf(szBuffer, SIZEOF(szBuffer), CTranslator::get(CTranslator::GEN_MUC_POPUP_STATUS_OFF), gce->ptszText, (char *)gce->pszStatus, gce->ptszNick);
+ break;
+ }
+ /*
+ * formatting strings don't need to be translatable - changing them via language pack would
+ * only screw up the log format.
+ */
+ if (p)
+ mir_sntprintf(szLine, SIZEOF(szLine), _T("%s %c %s\r\n"), szTime, p, szBuffer);
+ else
+ mir_sntprintf(szLine, SIZEOF(szLine), _T("%s %s\r\n"), szTime, szBuffer);
+
+ if (szLine[0]) {
+ _fputts(szLine, hFile);
+
+ if (g_Settings.LoggingLimit > 0) {
+ long dwSize;
+ long trimlimit;
+
+ fseek(hFile, 0, SEEK_END);
+ dwSize = ftell(hFile);
+ rewind(hFile);
+
+ trimlimit = g_Settings.LoggingLimit * 1024;
+ if (dwSize > trimlimit) {
+ TCHAR tszDrive[_MAX_DRIVE];
+ TCHAR tszDir[_MAX_DIR];
+ TCHAR tszName[_MAX_FNAME];
+ TCHAR tszExt[_MAX_EXT];
+ TCHAR tszNewName[_MAX_DRIVE + _MAX_DIR + _MAX_FNAME + _MAX_EXT + 20];
+ TCHAR tszNewPath[_MAX_DRIVE + _MAX_DIR + _MAX_FNAME + _MAX_EXT + 20];
+ TCHAR tszTimestamp[20];
+ time_t now = time(0);
+
+ _tcsftime(tszTimestamp, 20, _T("%Y%m%d-%H%M%S"), _localtime32((__time32_t *)&now));
+ tszTimestamp[19] = 0;
+ /*
+ * max size reached, rotate the log
+ * move old logs to /archived sub folder just inside the log root folder.
+ * add a time stamp to the file name.
+ */
+ _tsplitpath(si->pszLogFileName, tszDrive, tszDir, tszName, tszExt);
+
+ mir_sntprintf(tszNewPath, _MAX_DRIVE + _MAX_DIR + _MAX_FNAME + _MAX_EXT + 20, _T("%s%sarchived\\"),
+ tszDrive, tszDir);
+
+ CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)tszNewPath);
+ mir_sntprintf(tszNewName, _MAX_DRIVE + _MAX_DIR + _MAX_FNAME + _MAX_EXT + 20, _T("%s%s-%s%s"), tszNewPath, tszName, tszTimestamp, tszExt);
+ fclose(hFile);
+ hFile = 0;
+ if(!PathFileExists(tszNewName))
+ CopyFile(si->pszLogFileName, tszNewName, TRUE);
+ DeleteFile(si->pszLogFileName);
+ }
+ }
+ }
+
+ if (hFile)
+ fclose(hFile);
+ hFile = NULL;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UINT CreateGCMenu(HWND hwndDlg, HMENU *hMenu, int iIndex, POINT pt, SESSION_INFO* si, TCHAR* pszUID, TCHAR* pszWordText)
+{
+ GCMENUITEMS gcmi = {0};
+ int i;
+ HMENU hSubMenu = 0;
+ DWORD codepage = M->GetDword(si->hContact, "ANSIcodepage", 0);
+ int pos;
+
+ *hMenu = GetSubMenu(g_hMenu, iIndex);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) *hMenu, 0);
+ gcmi.pszID = si->ptszID;
+ gcmi.pszModule = si->pszModule;
+ gcmi.pszUID = pszUID;
+
+ if (iIndex == 1) {
+ int i = GetRichTextLength(GetDlgItem(hwndDlg, IDC_CHAT_LOG));
+
+ EnableMenuItem(*hMenu, ID_CLEARLOG, MF_ENABLED);
+ EnableMenuItem(*hMenu, ID_COPYALL, MF_ENABLED);
+ ModifyMenu(*hMenu, 4, MF_GRAYED | MF_BYPOSITION, 4, NULL);
+ if (!i) {
+ EnableMenuItem(*hMenu, ID_COPYALL, MF_BYCOMMAND | MF_GRAYED);
+ EnableMenuItem(*hMenu, ID_CLEARLOG, MF_BYCOMMAND | MF_GRAYED);
+ if (pszWordText && pszWordText[0])
+ ModifyMenu(*hMenu, 4, MF_ENABLED | MF_BYPOSITION, 4, NULL);
+ }
+
+ if (pszWordText && pszWordText[0]) {
+ TCHAR szMenuText[4096];
+ mir_sntprintf(szMenuText, 4096, CTranslator::get(CTranslator::GEN_MUC_LOOKUP), pszWordText);
+ ModifyMenu(*hMenu, 4, MF_STRING | MF_BYPOSITION, 4, szMenuText);
+ } else ModifyMenu(*hMenu, 4, MF_STRING | MF_GRAYED | MF_BYPOSITION, 4, CTranslator::get(CTranslator::GEN_MUC_LOOKUP_NOWORD));
+ gcmi.Type = MENU_ON_LOG;
+ } else if (iIndex == 0) {
+ TCHAR szTemp[30], szTemp2[30];
+ lstrcpyn(szTemp, CTranslator::get(CTranslator::GEN_MUC_MESSAGEAMP), 24);
+ if (pszUID)
+ mir_sntprintf(szTemp2, SIZEOF(szTemp2), _T("%s %s"), szTemp, pszUID);
+ else
+ lstrcpyn(szTemp2, szTemp, 24);
+
+ if (lstrlen(szTemp2) > 22)
+ lstrcpyn(szTemp2 + 22, _T("..."), 4);
+ ModifyMenu(*hMenu, ID_MESS, MF_STRING | MF_BYCOMMAND, ID_MESS, szTemp2);
+ gcmi.Type = MENU_ON_NICKLIST;
+ }
+
+ NotifyEventHooks(hBuildMenuEvent, 0, (WPARAM)&gcmi);
+
+ if (gcmi.nItems > 0)
+ AppendMenu(*hMenu, MF_SEPARATOR, 0, 0);
+
+ for (i = 0; i < gcmi.nItems; i++) {
+ TCHAR* ptszDescr = a2tf(gcmi.Item[i].pszDesc, si->dwFlags, 0);
+ DWORD dwState = gcmi.Item[i].bDisabled ? MF_GRAYED : 0;
+
+ if (gcmi.Item[i].uType == MENU_NEWPOPUP) {
+ hSubMenu = CreateMenu();
+ AppendMenu(*hMenu, dwState | MF_POPUP, (UINT_PTR)hSubMenu, ptszDescr);
+ } else if (gcmi.Item[i].uType == MENU_POPUPHMENU)
+ AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_POPUP, gcmi.Item[i].dwID, ptszDescr);
+ else if (gcmi.Item[i].uType == MENU_POPUPITEM)
+ AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_STRING, gcmi.Item[i].dwID, ptszDescr);
+ else if (gcmi.Item[i].uType == MENU_POPUPCHECK)
+ AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_CHECKED | MF_STRING, gcmi.Item[i].dwID, ptszDescr);
+ else if (gcmi.Item[i].uType == MENU_POPUPSEPARATOR)
+ AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, MF_SEPARATOR, 0, ptszDescr);
+ else if (gcmi.Item[i].uType == MENU_SEPARATOR)
+ AppendMenu(*hMenu, MF_SEPARATOR, 0, ptszDescr);
+ else if (gcmi.Item[i].uType == MENU_HMENU)
+ AppendMenu(*hMenu, dwState | MF_POPUP, gcmi.Item[i].dwID, ptszDescr);
+ else if (gcmi.Item[i].uType == MENU_ITEM)
+ AppendMenu(*hMenu, dwState | MF_STRING, gcmi.Item[i].dwID, ptszDescr);
+ else if (gcmi.Item[i].uType == MENU_CHECK)
+ AppendMenu(*hMenu, dwState | MF_CHECKED | MF_STRING, gcmi.Item[i].dwID, ptszDescr);
+
+ mir_free(ptszDescr);
+ }
+
+#if !defined(__DELAYED_FOR_3_1)
+ if (iIndex == 0) {
+ AppendMenu(*hMenu, MF_SEPARATOR, 0, 0);
+ pos = GetMenuItemCount(*hMenu);
+ InsertMenu(*hMenu, pos, MF_BYPOSITION, (UINT_PTR)20020, CTranslator::get(CTranslator::GEN_MUC_MENU_ADDTOHIGHLIGHT));
+ InsertMenu(*hMenu, pos, MF_BYPOSITION, (UINT_PTR)20021, CTranslator::get(CTranslator::GEN_MUC_MENU_EDITHIGHLIGHTLIST));
+ }
+#endif
+ if (iIndex == 1 && si->iType != GCW_SERVER && !(si->dwFlags & GC_UNICODE)) {
+ AppendMenu(*hMenu, MF_SEPARATOR, 0, 0);
+ InsertMenu(PluginConfig.g_hMenuEncoding, 1, MF_BYPOSITION | MF_STRING, (UINT_PTR)CP_UTF8, CTranslator::get(CTranslator::GEN_STRING_UTF8));
+ pos = GetMenuItemCount(*hMenu);
+ InsertMenu(*hMenu, pos, MF_BYPOSITION | MF_POPUP, (UINT_PTR) PluginConfig.g_hMenuEncoding, CTranslator::get(CTranslator::GEN_MSG_ENCODING));
+ for (i = 0; i < GetMenuItemCount(PluginConfig.g_hMenuEncoding); i++)
+ CheckMenuItem(PluginConfig.g_hMenuEncoding, i, MF_BYPOSITION | MF_UNCHECKED);
+ if (codepage == CP_ACP)
+ CheckMenuItem(PluginConfig.g_hMenuEncoding, 0, MF_BYPOSITION | MF_CHECKED);
+ else
+ CheckMenuItem(PluginConfig.g_hMenuEncoding, codepage, MF_BYCOMMAND | MF_CHECKED);
+
+ }
+
+ return TrackPopupMenu(*hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL);
+}
+
+void DestroyGCMenu(HMENU *hMenu, int iIndex)
+{
+ MENUITEMINFO mi;
+ mi.cbSize = sizeof(mi);
+ mi.fMask = MIIM_SUBMENU;
+ while (GetMenuItemInfo(*hMenu, iIndex, TRUE, &mi)) {
+ if (mi.hSubMenu != NULL)
+ DestroyMenu(mi.hSubMenu);
+ RemoveMenu(*hMenu, iIndex, MF_BYPOSITION);
+ }
+}
+
+BOOL DoEventHookAsync(HWND hwnd, const TCHAR* pszID, const char* pszModule, int iType, TCHAR* pszUID, TCHAR* pszText, DWORD dwItem)
+{
+ SESSION_INFO* si;
+ GCHOOK* gch = (GCHOOK*)mir_alloc(sizeof(GCHOOK));
+ GCDEST* gcd = (GCDEST*)mir_alloc(sizeof(GCDEST));
+
+ memset(gch, 0, sizeof(GCHOOK));
+ memset(gcd, 0, sizeof(GCDEST));
+
+ replaceStrA(&gcd->pszModule, pszModule);
+ if ((si = SM_FindSession(pszID, pszModule)) == NULL)
+ return FALSE;
+
+ if (!(si->dwFlags & GC_UNICODE)) {
+ DWORD dwCP = M->GetDword(si->hContact, "ANSIcodepage", 0);
+ gcd->pszID = t2a(pszID, 0);
+ gch->pszUID = t2a(pszUID, 0);
+ gch->pszText = t2a(pszText, dwCP);
+ } else {
+ replaceStr(&gcd->ptszID, pszID);
+ replaceStr(&gch->ptszUID, pszUID);
+ replaceStr(&gch->ptszText, pszText);
+ }
+ gcd->iType = iType;
+ gch->dwData = dwItem;
+ gch->pDest = gcd;
+ PostMessage(hwnd, GC_FIREHOOK, 0, (LPARAM) gch);
+ return TRUE;
+}
+
+BOOL DoEventHook(const TCHAR* pszID, const char* pszModule, int iType, const TCHAR* pszUID, const TCHAR* pszText, DWORD dwItem)
+{
+ SESSION_INFO* si;
+ GCHOOK gch = {0};
+ GCDEST gcd = {0};
+
+ gcd.pszModule = (char*)pszModule;
+ if ((si = SM_FindSession(pszID, pszModule)) == NULL)
+ return FALSE;
+
+ if (!(si->dwFlags & GC_UNICODE)) {
+ DWORD dwCP = M->GetDword(si->hContact, "ANSIcodepage", 0);
+ gcd.pszID = t2a(pszID, 0);
+ gch.pszUID = t2a(pszUID, 0);
+ gch.pszText = t2a(pszText, dwCP);
+ } else {
+ gcd.ptszID = mir_tstrdup(pszID);
+ gch.ptszUID = mir_tstrdup(pszUID);
+ gch.ptszText = mir_tstrdup(pszText);
+ }
+ gcd.iType = iType;
+ gch.dwData = dwItem;
+ gch.pDest = &gcd;
+ NotifyEventHooks(hSendEvent, 0, (WPARAM)&gch);
+
+ mir_free(gcd.pszID);
+ mir_free(gch.ptszUID);
+ mir_free(gch.ptszText);
+ return TRUE;
+}
+
+BOOL IsEventSupported(int eventType)
+{
+ switch (eventType) {
+ // Supported events
+ case GC_EVENT_JOIN:
+ case GC_EVENT_PART:
+ case GC_EVENT_QUIT:
+ case GC_EVENT_KICK:
+ case GC_EVENT_NICK:
+ case GC_EVENT_NOTICE:
+ case GC_EVENT_MESSAGE:
+ case GC_EVENT_TOPIC:
+ case GC_EVENT_INFORMATION:
+ case GC_EVENT_ACTION:
+ case GC_EVENT_ADDSTATUS:
+ case GC_EVENT_REMOVESTATUS:
+ case GC_EVENT_CHUID:
+ case GC_EVENT_CHANGESESSIONAME:
+ case GC_EVENT_ADDGROUP:
+ case GC_EVENT_SETITEMDATA:
+ case GC_EVENT_GETITEMDATA:
+ case GC_EVENT_SETSBTEXT:
+ case GC_EVENT_ACK:
+ case GC_EVENT_SENDMESSAGE:
+ case GC_EVENT_SETSTATUSEX:
+ case GC_EVENT_CONTROL:
+ case GC_EVENT_SETCONTACTSTATUS:
+ return TRUE;
+ }
+
+ // Other events
+ return FALSE;
+}
+
+TCHAR* a2tf(const TCHAR* str, int flags, DWORD cp)
+{
+ if (str == NULL)
+ return NULL;
+
+ if (flags & GC_UNICODE)
+ return mir_tstrdup(str);
+ else {
+ int cbLen;
+ TCHAR *result;
+
+ if (cp == CP_UTF8)
+ return(M->utf8_decodeW((char *)str));
+
+ if (cp == 0)
+ cp = PluginConfig.m_LangPackCP; // CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 );
+ cbLen = MultiByteToWideChar(cp, 0, (char*)str, -1, 0, 0);
+ result = (TCHAR*)mir_alloc(sizeof(TCHAR) * (cbLen + 1));
+ if (result == NULL)
+ return NULL;
+
+ MultiByteToWideChar(cp, 0, (char*)str, -1, result, cbLen);
+ result[ cbLen ] = 0;
+ return result;
+ }
+}
+
+static char* u2a(const wchar_t* src, DWORD cp)
+{
+ int cbLen;
+ char *result;
+
+ if (cp == 0)
+ cp = PluginConfig.m_LangPackCP;
+ else if (cp == CP_UTF8)
+ return(M->utf8_encodeW(src));
+
+ cbLen = WideCharToMultiByte(cp, 0, src, -1, NULL, 0, NULL, NULL);
+ result = (char*)mir_alloc(cbLen + 1);
+ if (result == NULL)
+ return NULL;
+
+ WideCharToMultiByte(cp, 0, src, -1, result, cbLen, NULL, NULL);
+ result[ cbLen ] = 0;
+ return result;
+}
+
+char* t2a(const TCHAR* src, DWORD cp)
+{
+ return u2a(src, cp);
+}
+
+TCHAR* replaceStr(TCHAR** dest, const TCHAR* src)
+{
+ mir_free(*dest);
+ *dest = mir_tstrdup(src);
+ return *dest;
+}
+
+char* replaceStrA(char** dest, const char* src)
+{
+ mir_free(*dest);
+ *dest = mir_strdup(src);
+ return *dest;
+}
+
+/*
+ * set all filters and notification config for a session
+ * uses per channel mask + filterbits, default config as backup
+ */
+
+void Chat_SetFilters(SESSION_INFO *si)
+{
+ DWORD dwFlags_default = 0, dwMask = 0, dwFlags_local = 0;
+ int i;
+
+ if (si == NULL)
+ return;
+
+ dwFlags_default = M->GetDword("Chat", "FilterFlags", 0x03E0);
+ dwFlags_local = M->GetDword(si->hContact, "Chat", "FilterFlags", 0x03E0);
+ dwMask = M->GetDword(si->hContact, "Chat", "FilterMask", 0);
+
+ si->iLogFilterFlags = dwFlags_default;
+ for (i = 0; i < 32; i++) {
+ if (dwMask & (1 << i))
+ si->iLogFilterFlags = (dwFlags_local & (1 << i) ? si->iLogFilterFlags | (1 << i) : si->iLogFilterFlags & ~(1 << i));
+ }
+
+ dwFlags_default = M->GetDword("Chat", "PopupFlags", 0x03E0);
+ dwFlags_local = M->GetDword(si->hContact, "Chat", "PopupFlags", 0x03E0);
+ dwMask = M->GetDword(si->hContact, "Chat", "PopupMask", 0);
+
+ si->iLogPopupFlags = dwFlags_default;
+ for (i = 0; i < 32; i++) {
+ if (dwMask & (1 << i))
+ si->iLogPopupFlags = (dwFlags_local & (1 << i) ? si->iLogPopupFlags | (1 << i) : si->iLogPopupFlags & ~(1 << i));
+ }
+
+ dwFlags_default = M->GetDword("Chat", "TrayIconFlags", 0x03E0);
+ dwFlags_local = M->GetDword(si->hContact, "Chat", "TrayIconFlags", 0x03E0);
+ dwMask = M->GetDword(si->hContact, "Chat", "TrayIconMask", 0);
+
+ si->iLogTrayFlags = dwFlags_default;
+ for (i = 0; i < 32; i++) {
+ if (dwMask & (1 << i))
+ si->iLogTrayFlags = (dwFlags_local & (1 << i) ? si->iLogTrayFlags | (1 << i) : si->iLogTrayFlags & ~(1 << i));
+ }
+
+ dwFlags_default = M->GetDword("Chat", "DiskLogFlags", 0xFFFF);
+ si->iDiskLogFlags = dwFlags_default;
+
+
+ if (si->iLogFilterFlags == 0)
+ si->bFilterEnabled = 0;
+}
+
+static TCHAR tszOldTimeStamp[30] = _T("\0");
+
+TCHAR* GetChatLogsFilename(SESSION_INFO *si, time_t tTime)
+{
+ REPLACEVARSARRAY rva[11];
+ REPLACEVARSDATA dat = {0};
+ TCHAR *p = 0, *tszParsedName = 0;
+ int i;
+ bool fReparse = false;
+
+ if(!tTime)
+ time(&tTime);
+
+ /*
+ * check whether relevant parts of the timestamp have changed and
+ * we have to reparse the filename
+ */
+
+ TCHAR *tszNow = MakeTimeStamp(_T("%a%d%m%Y"), tTime);
+
+ if(_tcscmp(tszOldTimeStamp, tszNow)) {
+ _tcsncpy(tszOldTimeStamp, tszNow, 30);
+ tszOldTimeStamp[29] = 0;
+ fReparse = true;
+ }
+
+ if(fReparse || 0 == si->pszLogFileName[0]) {
+ rva[0].lptzKey = _T("d");
+ rva[0].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%#d"), tTime));
+ // day 01-31
+ rva[1].lptzKey = _T("dd");
+ rva[1].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%d"), tTime));
+ // month 1-12
+ rva[2].lptzKey = _T("m");
+ rva[2].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%#m"), tTime));
+ // month 01-12
+ rva[3].lptzKey = _T("mm");
+ rva[3].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%m"), tTime));
+ // month text short
+ rva[4].lptzKey = _T("mon");
+ rva[4].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%b"), tTime));
+ // month text
+ rva[5].lptzKey = _T("month");
+ rva[5].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%B"), tTime));
+ // year 01-99
+ rva[6].lptzKey = _T("yy");
+ rva[6].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%y"), tTime));
+ // year 1901-9999
+ rva[7].lptzKey = _T("yyyy");
+ rva[7].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%Y"), tTime));
+ // weekday short
+ rva[8].lptzKey = _T("wday");
+ rva[8].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%a"), tTime));
+ // weekday
+ rva[9].lptzKey = _T("weekday");
+ rva[9].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%A"), tTime));
+ // end of array
+ rva[10].lptzKey = NULL;
+ rva[10].lptzValue = NULL;
+
+ if (g_Settings.pszLogDir[lstrlen(g_Settings.pszLogDir)-1] == '\\')
+ _tcscat(g_Settings.pszLogDir, _T("%userid%.log"));
+
+ dat.cbSize = sizeof(dat);
+ dat.dwFlags = RVF_TCHAR;
+ dat.hContact = si->hContact;
+ dat.variables = rva;
+ tszParsedName = (TCHAR*) CallService(MS_UTILS_REPLACEVARS, (WPARAM)g_Settings.pszLogDir, (LPARAM)&dat);
+
+ if(!M->pathIsAbsolute(tszParsedName))
+ mir_sntprintf(si->pszLogFileName, MAX_PATH, _T("%s%s"), M->getChatLogPath(), tszParsedName);
+ else
+ mir_sntprintf(si->pszLogFileName, MAX_PATH, _T("%s"), tszParsedName);
+
+ mir_free(tszParsedName);
+
+ for (i=0; i < SIZEOF(rva);i++)
+ mir_free(rva[i].lptzValue);
+
+ for (p = si->pszLogFileName + 2; *p; ++p) {
+ if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || *p == '<' || *p == '>' || *p == '|' )
+ *p = _T('_');
+ }
+ }
+
+ return si->pszLogFileName;
+}
diff --git a/plugins/TabSRMM/chat/window.cpp b/plugins/TabSRMM/chat/window.cpp
new file mode 100644
index 0000000000..0c7d3c8f99
--- /dev/null
+++ b/plugins/TabSRMM/chat/window.cpp
@@ -0,0 +1,3840 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * This code is based on and still contains large parts of the the
+ * original chat module for Miranda IM, written and copyrighted
+ * by Joergen Persson in 2005.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: window.cpp 13631 2011-04-24 08:44:57Z silvercircle $
+ *
+ * This implements the group chat dialog window
+ *
+ */
+
+#include "../src/commonheaders.h"
+
+#include <tom.h>
+
+//#include "../m_MathModule.h"
+
+// externs...
+extern LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+extern HRESULT(WINAPI *MyCloseThemeData)(HANDLE);
+extern REOLECallback *mREOLECallback;
+
+int g_cLinesPerPage=0;
+int g_iWheelCarryover=0;
+//
+
+extern HBRUSH hListBkgBrush;
+extern HANDLE hSendEvent;
+extern HICON hIcons[30];
+extern HMENU g_hMenu;
+extern WNDPROC OldSplitterProc;
+
+static WNDPROC OldMessageProc;
+static WNDPROC OldNicklistProc;
+static WNDPROC OldFilterButtonProc;
+static WNDPROC OldLogProc;
+static HKL hkl = NULL;
+static HCURSOR hCurHyperlinkHand;
+
+typedef struct
+{
+ time_t lastEnterTime;
+ TCHAR* szSearchQuery;
+ TCHAR* szSearchResult;
+ SESSION_INFO *lastSession;
+ TCHAR szTabSave[20];
+ BOOL iSavedSpaces;
+} MESSAGESUBDATA;
+
+static const CLSID IID_ITextDocument= { 0x8CC497C0,0xA1DF,0x11CE, { 0x80,0x98, 0x00,0xAA, 0x00,0x47,0xBE,0x5D} };
+extern WNDPROC OldIEViewProc;
+
+static void Chat_SetMessageLog(TWindowData *dat)
+{
+ unsigned int iLogMode = M->GetByte("Chat", "useIEView", 0);
+
+ if (iLogMode == WANT_IEVIEW_LOG && dat->hwndIEView == 0) {
+ IEVIEWWINDOW ieWindow;
+ IEVIEWEVENT iee;
+
+ //CheckAndDestroyHPP(dat);
+ ZeroMemory(&ieWindow, sizeof(ieWindow));
+ ZeroMemory(&iee, sizeof(iee));
+ ieWindow.cbSize = sizeof(ieWindow);
+ ieWindow.iType = IEW_CREATE;
+ ieWindow.dwFlags = 0;
+ ieWindow.dwMode = IEWM_TABSRMM;
+ ieWindow.parent = dat->hwnd;
+ ieWindow.x = 0;
+ ieWindow.y = 0;
+ ieWindow.cx = 200;
+ ieWindow.cy = 300;
+ CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
+ dat->hwndIEView = ieWindow.hwnd;
+ ZeroMemory(&iee, sizeof(iee));
+ iee.cbSize = sizeof(iee);
+ iee.iType = IEE_CLEAR_LOG;
+ iee.hwnd = dat->hwndIEView;
+ iee.hContact = dat->hContact;
+ iee.codepage = dat->codePage;
+
+ SESSION_INFO *si = (SESSION_INFO *)dat->si;
+
+ iee.pszProto = si->pszModule;
+ CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&iee);
+
+ Utils::showDlgControl(dat->hwnd, IDC_CHAT_LOG, SW_HIDE);
+ Utils::enableDlgControl(dat->hwnd, IDC_CHAT_LOG, FALSE);
+ } else if (iLogMode == WANT_HPP_LOG && dat->hwndHPP == 0) {
+ IEVIEWWINDOW ieWindow;
+
+ ZeroMemory(&ieWindow, sizeof(ieWindow));
+ //CheckAndDestroyIEView(dat);
+ ieWindow.cbSize = sizeof(IEVIEWWINDOW);
+ ieWindow.iType = IEW_CREATE;
+ ieWindow.dwFlags = 0;
+ ieWindow.dwMode = IEWM_MUCC;
+ ieWindow.parent = dat->hwnd;
+ ieWindow.x = 0;
+ ieWindow.y = 0;
+ ieWindow.cx = 10;
+ ieWindow.cy = 10;
+ CallService(MS_HPP_EG_WINDOW, 0, (LPARAM)&ieWindow);
+ dat->hwndHPP = ieWindow.hwnd;
+ Utils::showDlgControl(dat->hwnd, IDC_CHAT_LOG, SW_HIDE);
+ Utils::enableDlgControl(dat->hwnd, IDC_CHAT_LOG, FALSE);
+ } else {
+ if (iLogMode != WANT_IEVIEW_LOG)
+ CheckAndDestroyIEView(dat);
+ Utils::showDlgControl(dat->hwnd, IDC_CHAT_LOG, SW_SHOW);
+ Utils::enableDlgControl(dat->hwnd, IDC_CHAT_LOG, TRUE);
+ dat->hwndIEView = 0;
+ dat->hwndIWebBrowserControl = 0;
+ dat->hwndHPP = 0;
+ }
+}
+
+
+/*
+ * checking if theres's protected text at the point
+ * emulates EN_LINK WM_NOTIFY to parent to process links
+ */
+static BOOL CheckCustomLink(HWND hwndDlg, POINT* ptClient, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL bUrlNeeded)
+{
+ long res = 0, cnt = 0;
+ long cpMin = 0, cpMax = 0;
+ POINT ptEnd = {0};
+ IRichEditOle* RichEditOle = NULL;
+ ITextDocument* TextDocument = NULL;
+ ITextRange* TextRange = NULL;
+ ITextFont* TextFont = NULL;
+ BOOL bIsCustomLink = FALSE;
+
+ POINT pt = *ptClient;
+ ClientToScreen(hwndDlg, &pt);
+
+ do {
+ if (!SendMessage(hwndDlg, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle)) break;
+ if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) break;
+ if (TextDocument->RangeFromPoint(pt.x, pt.y, &TextRange) != S_OK) break;
+
+ TextRange->GetStart(&cpMin);
+ cpMax = cpMin+1;
+ TextRange->SetEnd(cpMax);
+
+ if (TextRange->GetFont(&TextFont) != S_OK)
+ break;
+
+ TextFont->GetProtected(&res);
+ if (res != tomTrue)
+ break;
+
+ TextRange->GetPoint(tomEnd+TA_BOTTOM+TA_RIGHT, &ptEnd.x, &ptEnd.y);
+ if (pt.x > ptEnd.x || pt.y > ptEnd.y)
+ break;
+
+ if (bUrlNeeded) {
+ TextRange->GetStoryLength(&cnt);
+ for (; cpMin > 0; cpMin--) {
+ res = tomTrue;
+ TextRange->SetIndex(tomCharacter, cpMin+1, tomTrue);
+ TextFont->GetProtected(&res);
+ if (res != tomTrue) { cpMin++; break; }
+ }
+ for (cpMax--; cpMax < cnt; cpMax++) {
+ res = tomTrue;
+ TextRange->SetIndex(tomCharacter, cpMax+1, tomTrue);
+ TextFont->GetProtected(&res);
+ if (res != tomTrue)
+ break;
+ }
+ }
+
+ bIsCustomLink = (cpMin < cpMax);
+ } while(FALSE);
+
+ if (TextFont) TextFont->Release();
+ if (TextRange) TextRange->Release();
+ if (TextDocument) TextDocument->Release();
+ if (RichEditOle) RichEditOle->Release();
+
+ if (bIsCustomLink) {
+ ENLINK enlink = {0};
+ enlink.nmhdr.hwndFrom = hwndDlg;
+ enlink.nmhdr.idFrom = IDC_CHAT_LOG;
+ enlink.nmhdr.code = EN_LINK;
+ enlink.msg = uMsg;
+ enlink.wParam = wParam;
+ enlink.lParam = lParam;
+ enlink.chrg.cpMin = cpMin;
+ enlink.chrg.cpMax = cpMax;
+ SendMessage(GetParent(hwndDlg), WM_NOTIFY, (WPARAM)IDC_CHAT_LOG, (LPARAM)&enlink);
+ }
+ return bIsCustomLink;
+}
+
+static BOOL IsStringValidLink(TCHAR* pszText)
+{
+ TCHAR *p = pszText;
+
+ if (pszText == NULL)
+ return FALSE;
+ if (lstrlen(pszText) < 5)
+ return FALSE;
+
+ while (*p) {
+ if (*p == (TCHAR)'"')
+ return FALSE;
+ p++;
+ }
+ if (_totlower(pszText[0]) == 'w' && _totlower(pszText[1]) == 'w' && _totlower(pszText[2]) == 'w' && pszText[3] == '.' && _istalnum(pszText[4]))
+ return TRUE;
+
+ return(_tcsstr(pszText, _T("://")) == NULL ? FALSE : TRUE);
+}
+
+/*
+ * called whenever a group chat tab becomes active (either by switching tabs or activating a
+ * container window
+ */
+
+static void Chat_UpdateWindowState(TWindowData *dat, UINT msg)
+{
+ if (dat == NULL)
+ return;
+
+ HWND hwndDlg = dat->hwnd;
+ HWND hwndTab = GetParent(hwndDlg);
+ SESSION_INFO *si = (SESSION_INFO *)dat->si;
+
+ if (msg == WM_ACTIVATE) {
+ if (dat->pContainer->dwFlags & CNT_TRANSPARENCY && CMimAPI::m_pSetLayeredWindowAttributes != NULL) {
+ DWORD trans = LOWORD(dat->pContainer->settings->dwTransparency);
+ CMimAPI::m_pSetLayeredWindowAttributes(dat->pContainer->hwnd, CSkin::m_ContainerColorKey, (BYTE)trans, (dat->pContainer->dwFlags & CNT_TRANSPARENCY ? LWA_ALPHA : 0));
+ }
+ }
+
+ if(si->hwndFilter) {
+ POINT pt;
+ RECT rcFilter;
+
+ GetCursorPos(&pt);
+ GetWindowRect(si->hwndFilter, &rcFilter);
+ if(!PtInRect(&rcFilter, pt)) {
+ SendMessage(si->hwndFilter, WM_CLOSE, 1, 1);
+ si->hwndFilter = 0;
+ }
+ }
+
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ if(dat->fIsAutosizingInput && dat->iInputAreaHeight == -1) {
+ dat->iInputAreaHeight = 0;
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_REQUESTRESIZE, 0, 0);
+ }
+#endif
+ dat->Panel->dismissConfig();
+ dat->dwUnread = 0;
+ if(dat->pWnd) {
+ dat->pWnd->activateTab();
+ dat->pWnd->setOverlayIcon(0, true);
+ }
+
+ if (dat->pContainer->hwndSaved == hwndDlg || dat->bWasDeleted)
+ return;
+
+ dat->pContainer->hwndSaved = hwndDlg;
+
+ SetActiveSession(si->ptszID, si->pszModule);
+ dat->hTabIcon = dat->hTabStatusIcon;
+
+ if (dat->iTabID >= 0) {
+ if (DBGetContactSettingWord(si->hContact, si->pszModule , "ApparentMode", 0) != 0)
+ DBWriteContactSettingWord(si->hContact, si->pszModule , "ApparentMode", (LPARAM) 0);
+ if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->hContact, (LPARAM)0))
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->hContact, (LPARAM)szChatIconString);
+
+ SendMessage(hwndDlg, GC_UPDATETITLE, 0, 1);
+ dat->dwTickLastEvent = 0;
+ dat->dwFlags &= ~MWF_DIVIDERSET;
+ if (KillTimer(hwndDlg, TIMERID_FLASHWND) || dat->iFlashIcon) {
+ FlashTab(dat, hwndTab, dat->iTabID, &dat->bTabFlash, FALSE, dat->hTabIcon);
+ dat->mayFlashTab = FALSE;
+ dat->iFlashIcon = 0;
+ }
+ if (dat->pContainer->dwFlashingStarted != 0) {
+ FlashContainer(dat->pContainer, 0, 0);
+ dat->pContainer->dwFlashingStarted = 0;
+ }
+ dat->pContainer->dwFlags &= ~CNT_NEED_UPDATETITLE;
+
+ if (dat->dwFlags & MWF_NEEDCHECKSIZE)
+ PostMessage(hwndDlg, DM_SAVESIZE, 0, 0);
+
+ if (PluginConfig.m_AutoLocaleSupport) {
+ if (dat->hkl == 0)
+ DM_LoadLocale(dat);
+ else
+ SendMessage(hwndDlg, DM_SETLOCALE, 0, 0);
+ }
+ SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE));
+ dat->dwLastActivity = GetTickCount();
+ dat->pContainer->dwLastActivity = dat->dwLastActivity;
+ dat->pContainer->MenuBar->configureMenu();
+ UpdateTrayMenuState(dat, FALSE);
+ DM_SetDBButtonStates(hwndDlg, dat);
+
+ if (g_Settings.MathMod) {
+ CallService(MTH_Set_ToolboxEditHwnd, 0, (LPARAM)GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE));
+ MTH_updateMathWindow(dat);
+ }
+
+ if (dat->dwFlagsEx & MWF_EX_DELAYEDSPLITTER) {
+ dat->dwFlagsEx &= ~MWF_EX_DELAYEDSPLITTER;
+ ShowWindow(dat->pContainer->hwnd, SW_RESTORE);
+ PostMessage(hwndDlg, DM_SPLITTERGLOBALEVENT, dat->wParam, dat->lParam);
+ PostMessage(hwndDlg, WM_SIZE, 0, 0);
+ dat->wParam = dat->lParam = 0;
+ }
+ /*
+ if (dat->hwndIEView) {
+ RECT rcRTF;
+ POINT pt;
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_LOG), &rcRTF);
+ rcRTF.left += 20;
+ rcRTF.top += 20;
+ pt.x = rcRTF.left;
+ pt.y = rcRTF.top;
+ if (dat->hwndIEView) {
+ if (M->GetByte("subclassIEView", 0) && dat->oldIEViewProc == 0) {
+ WNDPROC wndProc = (WNDPROC)SetWindowLongPtr(dat->hwndIEView, GWLP_WNDPROC, (LONG_PTR)IEViewSubclassProc);
+ if (OldIEViewProc == 0)
+ OldIEViewProc = wndProc;
+ dat->oldIEViewProc = wndProc;
+ }
+ }
+ dat->hwndIWebBrowserControl = WindowFromPoint(pt);
+ }
+ */
+ }
+ if(M->isAero())
+ InvalidateRect(hwndTab, NULL, FALSE);
+ if(dat->pContainer->dwFlags & CNT_SIDEBAR)
+ dat->pContainer->SideBar->setActiveItem(dat);
+ BB_SetButtonsPos(dat);
+
+ if(dat->pWnd)
+ dat->pWnd->Invalidate();
+}
+
+/*
+ * initialize button bar, set all the icons and ensure proper button state
+ */
+
+static void InitButtons(HWND hwndDlg, SESSION_INFO* si)
+{
+ BOOL isFlat = M->GetByte("tbflat", 1);
+ BOOL isThemed = PluginConfig.m_bIsXP;
+ MODULEINFO *pInfo = si ? MM_FindModule(si->pszModule) : NULL;
+ BOOL bFilterEnabled = si ? si->bFilterEnabled : FALSE;
+
+ int i = 0;
+
+ if (pInfo) {
+ Utils::enableDlgControl(hwndDlg, IDC_CHAT_BOLD, pInfo->bBold);
+ Utils::enableDlgControl(hwndDlg, IDC_ITALICS, pInfo->bItalics);
+ Utils::enableDlgControl(hwndDlg, IDC_CHAT_UNDERLINE, pInfo->bUnderline);
+ Utils::enableDlgControl(hwndDlg, IDC_COLOR, pInfo->bColor);
+ Utils::enableDlgControl(hwndDlg, IDC_BKGCOLOR, pInfo->bBkgColor);
+ if (si->iType == GCW_CHATROOM)
+ Utils::enableDlgControl(hwndDlg, IDC_CHANMGR, pInfo->bChanMgr);
+ }
+}
+
+static void Chat_ResizeIeView(const TWindowData *dat)
+{
+ RECT rcRichEdit;
+ POINT pt;
+ IEVIEWWINDOW ieWindow;
+ int iMode = dat->hwndIEView ? 1 : 2;
+ HWND hwndDlg = dat->hwnd;
+
+ ZeroMemory(&ieWindow, sizeof(ieWindow));
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_LOG), &rcRichEdit);
+ pt.x = rcRichEdit.left;
+ pt.y = rcRichEdit.top;
+ ScreenToClient(hwndDlg, &pt);
+ ieWindow.cbSize = sizeof(IEVIEWWINDOW);
+ ieWindow.iType = IEW_SETPOS;
+ ieWindow.parent = hwndDlg;
+ ieWindow.hwnd = iMode == 1 ? dat->hwndIEView : dat->hwndHPP;
+ ieWindow.x = pt.x;
+ ieWindow.y = pt.y;
+ ieWindow.cx = rcRichEdit.right - rcRichEdit.left;
+ ieWindow.cy = rcRichEdit.bottom - rcRichEdit.top;
+ if (ieWindow.cx != 0 && ieWindow.cy != 0) {
+ CallService(iMode == 1 ? MS_IEVIEW_WINDOW : MS_HPP_EG_WINDOW, 0, (LPARAM)&ieWindow);
+ }
+}
+
+/*
+ * resizer callback for the group chat session window. Called from Mirandas dialog
+ * resizing service
+ */
+
+static int RoomWndResize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL *urc)
+{
+ RECT rc, rcTabs;
+ SESSION_INFO* si = (SESSION_INFO*)lParam;
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ int TabHeight;
+ BOOL bToolbar = !(dat->pContainer->dwFlags & CNT_HIDETOOLBAR);
+ BOOL bBottomToolbar = dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR ? 1 : 0;
+ int panelHeight = dat->Panel->getHeight() + 1;
+
+ BOOL bNick = si->iType != GCW_SERVER && si->bNicklistEnabled;
+ int i = 0;
+ static int msgBottom = 0, msgTop = 0;
+ bool fInfoPanel = dat->Panel->isActive();
+
+ rc.bottom = rc.top = rc.left = rc.right = 0;
+
+ GetClientRect(hwndDlg, &rcTabs);
+ TabHeight = rcTabs.bottom - rcTabs.top;
+
+ if(dat->fIsAutosizingInput)
+ Utils::showDlgControl(hwndDlg, IDC_SPLITTERY, SW_HIDE);
+
+ if (si->iType != GCW_SERVER) {
+ Utils::showDlgControl(hwndDlg, IDC_LIST, si->bNicklistEnabled ? SW_SHOW : SW_HIDE);
+ Utils::showDlgControl(hwndDlg, IDC_SPLITTERX, si->bNicklistEnabled ? SW_SHOW : SW_HIDE);
+
+ Utils::enableDlgControl(hwndDlg, IDC_SHOWNICKLIST, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_FILTER, TRUE);
+ if (si->iType == GCW_CHATROOM) {
+ MODULEINFO* tmp = MM_FindModule(si->pszModule);
+ if (tmp)
+ Utils::enableDlgControl(hwndDlg, IDC_CHANMGR, tmp->bChanMgr);
+ }
+ } else {
+ Utils::showDlgControl(hwndDlg, IDC_LIST, SW_HIDE);
+ Utils::showDlgControl(hwndDlg, IDC_SPLITTERX, SW_HIDE);
+ }
+
+ if (si->iType == GCW_SERVER) {
+ Utils::enableDlgControl(hwndDlg, IDC_SHOWNICKLIST, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_FILTER, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_CHANMGR, FALSE);
+ }
+ //ShowWindow(GetDlgItem(hwndDlg, IDC_CHAT_TOGGLESIDEBAR), dat->pContainer->dwFlags & CNT_SIDEBAR ? SW_SHOW : SW_HIDE);
+
+ switch (urc->wId) {
+ case IDC_PANELSPLITTER:
+ urc->rcItem.bottom = panelHeight;
+ urc->rcItem.top = panelHeight - 2;
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP;
+ case IDC_CHAT_LOG:
+ urc->rcItem.top = 0;
+ urc->rcItem.left = 0;
+ urc->rcItem.right = bNick ? urc->dlgNewSize.cx - si->iSplitterX : urc->dlgNewSize.cx;
+ urc->rcItem.bottom = (bToolbar&&!bBottomToolbar) ? (urc->dlgNewSize.cy - si->iSplitterY - (PluginConfig.g_DPIscaleY > 1.0 ? DPISCALEY_S(24) : DPISCALEY_S(23))) : (urc->dlgNewSize.cy - si->iSplitterY - DPISCALEY_S(2));
+ if (fInfoPanel)
+ urc->rcItem.top += panelHeight;
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item = &SkinItems[ID_EXTBKHISTORY];
+ if (!item->IGNORED) {
+ urc->rcItem.left += item->MARGIN_LEFT;
+ urc->rcItem.right -= item->MARGIN_RIGHT;
+ urc->rcItem.top += item->MARGIN_TOP;
+ urc->rcItem.bottom -= item->MARGIN_BOTTOM;
+ }
+ }
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM;
+
+ case IDC_LIST:
+ urc->rcItem.top = 0;
+ urc->rcItem.right = urc->dlgNewSize.cx ;
+ urc->rcItem.left = urc->dlgNewSize.cx - si->iSplitterX + 2;
+ urc->rcItem.bottom = (bToolbar&&!bBottomToolbar) ? (urc->dlgNewSize.cy - si->iSplitterY - DPISCALEY_S(23)) : (urc->dlgNewSize.cy - si->iSplitterY - DPISCALEY_S(2));
+ if (fInfoPanel)
+ urc->rcItem.top += panelHeight;
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item = &SkinItems[ID_EXTBKUSERLIST];
+ if (!item->IGNORED) {
+ urc->rcItem.left += item->MARGIN_LEFT;
+ urc->rcItem.right -= item->MARGIN_RIGHT;
+ urc->rcItem.top += item->MARGIN_TOP;
+ urc->rcItem.bottom -= item->MARGIN_BOTTOM;
+ }
+ }
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM;
+
+ case IDC_SPLITTERX:
+ urc->rcItem.right = urc->dlgNewSize.cx - si->iSplitterX + 2;
+ urc->rcItem.left = urc->dlgNewSize.cx - si->iSplitterX;
+ urc->rcItem.bottom = (bToolbar&&!bBottomToolbar) ? (urc->dlgNewSize.cy - si->iSplitterY - DPISCALEY_S(23)) : (urc->dlgNewSize.cy - si->iSplitterY - DPISCALEY_S(2));
+ urc->rcItem.top = 0;
+ if (fInfoPanel)
+ urc->rcItem.top += panelHeight;
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM;
+
+ case IDC_SPLITTERY:
+ urc->rcItem.right = urc->dlgNewSize.cx;
+ urc->rcItem.top = (bToolbar&&!bBottomToolbar) ? urc->dlgNewSize.cy - si->iSplitterY : urc->dlgNewSize.cy - si->iSplitterY;
+ urc->rcItem.bottom = (bToolbar&&!bBottomToolbar) ? (urc->dlgNewSize.cy - si->iSplitterY + DPISCALEY_S(2)) : (urc->dlgNewSize.cy - si->iSplitterY + DPISCALEY_S(2));
+ urc->rcItem.left = 0;
+ urc->rcItem.bottom++;
+ urc->rcItem.top++;
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM;
+
+ case IDC_CHAT_MESSAGE:
+ urc->rcItem.right = urc->dlgNewSize.cx ;
+ urc->rcItem.top = urc->dlgNewSize.cy - si->iSplitterY + 3;
+ urc->rcItem.bottom = urc->dlgNewSize.cy; // - 1 ;
+ msgBottom = urc->rcItem.bottom;
+
+ if(dat->fIsAutosizingInput)
+ urc->rcItem.top -= DPISCALEY_S(1);
+
+ msgTop = urc->rcItem.top;
+ if (bBottomToolbar&&bToolbar)
+ urc->rcItem.bottom -= DPISCALEY_S(22);
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item = &SkinItems[ID_EXTBKINPUTAREA];
+ if (!item->IGNORED) {
+ urc->rcItem.left += item->MARGIN_LEFT;
+ urc->rcItem.right -= item->MARGIN_RIGHT;
+ urc->rcItem.top += item->MARGIN_TOP;
+ urc->rcItem.bottom -= item->MARGIN_BOTTOM;
+ }
+ }
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM;
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
+}
+
+
+/*
+ * subclassing for the message input control (a richedit text control)
+ */
+
+static LRESULT CALLBACK MessageSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MESSAGESUBDATA *dat;
+ SESSION_INFO* Parentsi;
+ struct TWindowData *mwdat;
+ HWND hwndParent = GetParent(hwnd);
+
+ mwdat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA);
+ Parentsi = (SESSION_INFO *)mwdat->si;
+
+ dat = (MESSAGESUBDATA *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ if(mwdat->fkeyProcessed && (msg == WM_KEYUP)) {
+ GetKeyboardState(mwdat->kstate);
+ if(mwdat->kstate[VK_CONTROL] & 0x80 || mwdat->kstate[VK_SHIFT] & 0x80)
+ return(0);
+ else {
+ mwdat->fkeyProcessed = false;
+ return(0);
+ }
+ }
+ switch (msg) {
+ case WM_NCCALCSIZE:
+ return(CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKINPUTAREA, msg, wParam, lParam, OldMessageProc));
+
+ case WM_NCPAINT:
+ return(CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKINPUTAREA, msg, wParam, lParam, OldMessageProc));
+
+ case EM_SUBCLASSED:
+ dat = (MESSAGESUBDATA *) mir_calloc(sizeof(MESSAGESUBDATA));
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) dat);
+ return 0;
+
+ case WM_CONTEXTMENU: {
+ MODULEINFO* mi = MM_FindModule(Parentsi->pszModule);
+ HMENU hMenu, hSubMenu;
+ CHARRANGE sel, all = { 0, -1};
+ int iSelection;
+ int iPrivateBG = M->GetByte(mwdat->hContact, "private_bg", 0);
+ MessageWindowPopupData mwpd;
+ POINT pt;
+ int idFrom = IDC_CHAT_MESSAGE;
+
+ GetCursorPos(&pt);
+ hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT));
+ hSubMenu = GetSubMenu(hMenu, 2);
+ RemoveMenu(hSubMenu, 9, MF_BYPOSITION);
+ RemoveMenu(hSubMenu, 8, MF_BYPOSITION);
+ RemoveMenu(hSubMenu, 4, MF_BYPOSITION);
+ EnableMenuItem(hSubMenu, IDM_PASTEFORMATTED, MF_BYCOMMAND | ((mi && mi->bBold) ? MF_ENABLED : MF_GRAYED));
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hSubMenu, 0);
+
+ SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) & sel);
+ if (sel.cpMin == sel.cpMax) {
+ EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED);
+ if (idFrom == IDC_CHAT_MESSAGE)
+ EnableMenuItem(hSubMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED);
+ }
+ mwpd.cbSize = sizeof(mwpd);
+ mwpd.uType = MSG_WINDOWPOPUP_SHOWING;
+ mwpd.uFlags = (idFrom == IDC_LOG ? MSG_WINDOWPOPUP_LOG : MSG_WINDOWPOPUP_INPUT);
+ mwpd.hContact = mwdat->hContact;
+ mwpd.hwnd = hwnd;
+ mwpd.hMenu = hSubMenu;
+ mwpd.selection = 0;
+ mwpd.pt = pt;
+ NotifyEventHooks(PluginConfig.m_event_MsgPopup, 0, (LPARAM)&mwpd);
+
+ iSelection = TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, GetParent(hwnd), NULL);
+
+ mwpd.selection = iSelection;
+ mwpd.uType = MSG_WINDOWPOPUP_SELECTED;
+ NotifyEventHooks(PluginConfig.m_event_MsgPopup, 0, (LPARAM)&mwpd);
+
+ switch (iSelection) {
+ case IDM_COPY:
+ SendMessage(hwnd, WM_COPY, 0, 0);
+ break;
+ case IDM_CUT:
+ SendMessage(hwnd, WM_CUT, 0, 0);
+ break;
+ case IDM_PASTE:
+ case IDM_PASTEFORMATTED:
+ if (idFrom == IDC_CHAT_MESSAGE)
+ SendMessage(hwnd, EM_PASTESPECIAL, (iSelection == IDM_PASTE) ? CF_TEXTT : 0, 0);
+ break;
+ case IDM_COPYALL:
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & all);
+ SendMessage(hwnd, WM_COPY, 0, 0);
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & sel);
+ break;
+ case IDM_SELECTALL:
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & all);
+ break;
+ }
+ DestroyMenu(hMenu);
+ return TRUE;
+ }
+
+ case WM_MOUSEWHEEL: {
+ LRESULT result = DM_MouseWheelHandler(hwnd, hwndParent, mwdat, wParam, lParam);
+ if (result == 0)
+ return 0;
+
+ dat->lastEnterTime = 0;
+ break;
+ }
+
+ case WM_SYSKEYUP:
+ if(wParam == VK_MENU) {
+ ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_CHAT_MESSAGE);
+ return(0);
+ }
+ break;
+
+ case WM_SYSKEYDOWN:
+ mwdat->fkeyProcessed = false;
+ if(ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_CHAT_MESSAGE)) {
+ mwdat->fkeyProcessed = true;
+ return(0);
+ }
+ break;
+
+ case WM_SYSCHAR: {
+ if(mwdat->fkeyProcessed) {
+ mwdat->fkeyProcessed = false; // preceeding key event has been processed by miranda hotkey service
+ return(0);
+ }
+ BOOL isMenu = GetKeyState(VK_MENU) & 0x8000;
+
+ if ((wParam >= '0' && wParam <= '9') && isMenu) { // ALT-1 -> ALT-0 direct tab selection
+ BYTE bChar = (BYTE)wParam;
+ int iIndex;
+
+ if (bChar == '0')
+ iIndex = 10;
+ else
+ iIndex = bChar - (BYTE)'0';
+ SendMessage(mwdat->pContainer->hwnd, DM_SELECTTAB, DM_SELECT_BY_INDEX, (LPARAM)iIndex);
+ return 0;
+ }
+ break;
+ }
+
+ case WM_CHAR: {
+ BOOL isShift, isAlt, isCtrl;
+ KbdState(mwdat, isShift, isCtrl, isAlt);
+
+ //MAD: sound on typing..
+ if(PluginConfig.g_bSoundOnTyping && !isAlt &&!isCtrl&&!(mwdat->pContainer->dwFlags&CNT_NOSOUND)&&wParam!=VK_ESCAPE&&!(wParam==VK_TAB&&PluginConfig.m_AllowTab))
+ SkinPlaySound("SoundOnTyping");
+ //MAD
+
+ if (wParam == 0x0d && isCtrl && PluginConfig.m_MathModAvail) {
+ TCHAR toInsert[100];
+ BYTE keyState[256];
+ size_t i;
+ size_t iLen = lstrlen(PluginConfig.m_MathModStartDelimiter);
+ ZeroMemory(keyState, 256);
+ _tcsncpy(toInsert, PluginConfig.m_MathModStartDelimiter, 30);
+ _tcsncat(toInsert, PluginConfig.m_MathModStartDelimiter, 30);
+ SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM)toInsert);
+ SetKeyboardState(keyState);
+ for (i = 0; i < iLen; i++)
+ SendMessage(hwnd, WM_KEYDOWN, mwdat->dwFlags & MWF_LOG_RTL ? VK_RIGHT : VK_LEFT, 0);
+ return 0;
+ }
+ if(isCtrl && !isAlt && !isShift) {
+ MODULEINFO* mi = MM_FindModule(Parentsi->pszModule);
+
+ switch(wParam) {
+ case 0x09: // ctrl-i (italics)
+ if(mi && mi->bItalics) {
+ CheckDlgButton(hwndParent, IDC_ITALICS, IsDlgButtonChecked(hwndParent, IDC_ITALICS) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED);
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_ITALICS, 0), 0);
+ }
+ return(0);
+ case 0x02: // ctrl-b (bold)
+ if(mi && mi->bBold) {
+ CheckDlgButton(hwndParent, IDC_CHAT_BOLD, IsDlgButtonChecked(hwndParent, IDC_CHAT_BOLD) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED);
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_CHAT_BOLD, 0), 0);
+ }
+ return 0;
+ case 0x20: // ctrl-space clear formatting
+ if(mi && mi->bBold && mi->bItalics && mi->bUnderline) {
+ CheckDlgButton(hwndParent, IDC_BKGCOLOR, BST_UNCHECKED);
+ CheckDlgButton(hwndParent, IDC_COLOR, BST_UNCHECKED);
+ CheckDlgButton(hwndParent, IDC_CHAT_BOLD, BST_UNCHECKED);
+ CheckDlgButton(hwndParent, IDC_CHAT_UNDERLINE, BST_UNCHECKED);
+ CheckDlgButton(hwndParent, IDC_ITALICS, BST_UNCHECKED);
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_BKGCOLOR, 0), 0);
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_COLOR, 0), 0);
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_CHAT_BOLD, 0), 0);
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_CHAT_UNDERLINE, 0), 0);
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_ITALICS, 0), 0);
+ }
+ return 0;
+ case 0x0c: // ctrl-l background color
+ if(mi && mi->bBkgColor) {
+ CheckDlgButton(hwndParent, IDC_BKGCOLOR, IsDlgButtonChecked(hwndParent, IDC_BKGCOLOR) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED);
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_BKGCOLOR, 0), 0);
+ }
+ return 0;
+ case 0x15: // ctrl-u underlined
+ if(mi && mi->bUnderline) {
+ CheckDlgButton(hwndParent, IDC_CHAT_UNDERLINE, IsDlgButtonChecked(hwndParent, IDC_CHAT_UNDERLINE) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED);
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_CHAT_UNDERLINE, 0), 0);
+ }
+ return 0; // ctrl-k color
+ case 0x0b:
+ if(mi && mi->bColor) {
+ CheckDlgButton(hwndParent, IDC_COLOR, IsDlgButtonChecked(hwndParent, IDC_COLOR) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED);
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_COLOR, 0), 0);
+ }
+ return 0;
+ case 0x17:
+ PostMessage(hwndParent, WM_CLOSE, 0, 1);
+ return 0;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ case WM_KEYDOWN: {
+ static size_t start, end;
+ BOOL isShift, isCtrl, isAlt;
+ KbdState(mwdat, isShift, isCtrl, isAlt);
+
+ //MAD: sound on typing..
+ if(PluginConfig.g_bSoundOnTyping&&!isAlt&&wParam == VK_DELETE)
+ SkinPlaySound("SoundOnTyping");
+ //
+ if (wParam == VK_INSERT && !isShift && !isCtrl && !isAlt) {
+ mwdat->fInsertMode = !mwdat->fInsertMode;
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd);
+ }
+ if (wParam == VK_CAPITAL || wParam == VK_NUMLOCK)
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd);
+
+ if (isCtrl && isAlt && !isShift) {
+ switch (wParam) {
+ case VK_UP:
+ case VK_DOWN:
+ case VK_PRIOR:
+ case VK_NEXT:
+ case VK_HOME:
+ case VK_END: {
+ WPARAM wp = 0;
+
+ if (wParam == VK_UP)
+ wp = MAKEWPARAM(SB_LINEUP, 0);
+ else if (wParam == VK_PRIOR)
+ wp = MAKEWPARAM(SB_PAGEUP, 0);
+ else if (wParam == VK_NEXT)
+ wp = MAKEWPARAM(SB_PAGEDOWN, 0);
+ else if (wParam == VK_HOME)
+ wp = MAKEWPARAM(SB_TOP, 0);
+ else if (wParam == VK_END) {
+ DM_ScrollToBottom(mwdat, 0, 0);
+ return 0;
+ } else if (wParam == VK_DOWN)
+ wp = MAKEWPARAM(SB_LINEDOWN, 0);
+
+ SendMessage(GetDlgItem(hwndParent, IDC_CHAT_LOG), WM_VSCROLL, wp, 0);
+ return 0;
+ }
+ }
+ }
+
+ if (wParam == VK_RETURN) {
+ if (isShift) {
+ if (PluginConfig.m_SendOnShiftEnter) {
+ PostMessage(hwndParent, WM_COMMAND, IDOK, 0);
+ return 0;
+ } else
+ break;
+ }
+ if ((isCtrl && !isShift) ^(0 != PluginConfig.m_SendOnEnter)) {
+ PostMessage(hwndParent, WM_COMMAND, IDOK, 0);
+ return 0;
+ }
+ if (PluginConfig.m_SendOnEnter || PluginConfig.m_SendOnDblEnter) {
+ if (isCtrl)
+ break;
+ else {
+ if (PluginConfig.m_SendOnDblEnter) {
+ if (dat->lastEnterTime + 2 < time(NULL)) {
+ dat->lastEnterTime = time(NULL);
+ break;
+ } else {
+ SendMessage(hwnd, WM_KEYDOWN, VK_BACK, 0);
+ SendMessage(hwnd, WM_KEYUP, VK_BACK, 0);
+ PostMessage(hwndParent, WM_COMMAND, IDOK, 0);
+ return 0;
+ }
+ }
+ PostMessage(hwndParent, WM_COMMAND, IDOK, 0);
+ return 0;
+ }
+ } else
+ break;
+ } else
+ dat->lastEnterTime = 0;
+
+ if ((wParam == VK_NEXT && isCtrl && !isShift) || (wParam == VK_TAB && isCtrl && !isShift)) { // CTRL-TAB (switch tab/window)
+ SendMessage(mwdat->pContainer->hwnd, DM_SELECTTAB, DM_SELECT_NEXT, 0);
+ return TRUE;
+ }
+
+ if ((wParam == VK_PRIOR && isCtrl && !isShift) || (wParam == VK_TAB && isCtrl && isShift)) { // CTRL_SHIFT-TAB (switch tab/window)
+ SendMessage(mwdat->pContainer->hwnd, DM_SELECTTAB, DM_SELECT_PREV, 0);
+ return TRUE;
+ }
+ if (wParam == VK_TAB && !isCtrl && !isShift) { //tab-autocomplete
+ int iLen, end, topicStart;
+ BOOL isTopic = FALSE;
+ BOOL isRoom = FALSE;
+ wchar_t* pszText = NULL;
+ GETTEXTEX gt = {0};
+ LRESULT lResult = (LRESULT)SendMessage(hwnd, EM_GETSEL, (WPARAM)NULL, (LPARAM)NULL);
+ bool fCompleted = false;
+
+ SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+ start = LOWORD(lResult);
+ end = HIWORD(lResult);
+ SendMessage(hwnd, EM_SETSEL, end, end);
+
+ gt.codepage = 1200;
+ gt.flags = GTL_DEFAULT | GTL_PRECISE;
+
+ iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gt, (LPARAM)0);
+ if (iLen > 0) {
+ wchar_t* pszName = NULL;
+ pszText = reinterpret_cast<wchar_t*>(Utils::safeMirCalloc((iLen + 10) * sizeof(wchar_t)));
+ gt.flags = GT_DEFAULT;
+ gt.cb = (iLen + 9) * sizeof(wchar_t);
+
+ SendMessage(hwnd, EM_GETTEXTEX, (WPARAM)&gt, (LPARAM)pszText);
+
+ if(start > 1 && pszText[start-1] == ' ' && pszText[start-2] == ':')
+ start--;
+
+ while( start > 0 && pszText[start-1] != ' ' && pszText[start-1] != 13 && pszText[start-1] != VK_TAB)
+ start--;
+
+ while (end < iLen && pszText[end] != ' ' && pszText[end] != 13 && pszText[end-1] != VK_TAB)
+ end ++;
+
+ if(pszText[start] == '#')
+ isRoom = TRUE;
+ else {
+ topicStart = (int)start;
+ while ( topicStart >0 && (pszText[topicStart-1] == ' ' || pszText[topicStart-1] == 13 || pszText[topicStart-1] == VK_TAB))
+ topicStart--;
+ if (topicStart > 5 && _tcsstr(&pszText[topicStart-6], _T("/topic")) == &pszText[topicStart-6])
+ isTopic = TRUE;
+ }
+ if (dat->szSearchQuery == NULL) {
+ size_t len = (end - start) + 1;
+ dat->szSearchQuery = reinterpret_cast<wchar_t*>(Utils::safeMirAlloc(sizeof(wchar_t) * len));
+ wcsncpy( dat->szSearchQuery, pszText + start, len);
+ dat->szSearchQuery[len - 1] = 0;
+ dat->szSearchResult = mir_tstrdup(dat->szSearchQuery);
+ dat->lastSession = NULL;
+ }
+ if (isTopic) {
+ pszName = Parentsi->ptszTopic;
+ } else if (isRoom) {
+ dat->lastSession = SM_FindSessionAutoComplete(Parentsi->pszModule, Parentsi, dat->lastSession, dat->szSearchQuery, dat->szSearchResult);
+ if (dat->lastSession != NULL)
+ pszName = dat->lastSession->ptszName;
+ } else
+ pszName = UM_FindUserAutoComplete(Parentsi->pUsers, dat->szSearchQuery, dat->szSearchResult);
+
+ mir_free(pszText);
+ pszText = NULL;
+ mir_free(dat->szSearchResult);
+ dat->szSearchResult = 0;
+ if (pszName == 0) {
+ if ((int)end != (int)start) {
+ SendMessage(hwnd, EM_SETSEL, start, end);
+ SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) dat->szSearchQuery);
+ }
+ mir_free(dat->szSearchQuery);
+ dat->szSearchQuery = NULL;
+ } else {
+ pszText = 0;
+ dat->szSearchResult = mir_tstrdup(pszName);
+ if ((int)end != (int)start) {
+ if (!isRoom && !isTopic && g_Settings.AddColonToAutoComplete && start == 0) {
+ pszText = reinterpret_cast<wchar_t*>(Utils::safeMirAlloc((wcslen(pszName) + 4) * sizeof(wchar_t)));
+ wcscpy(pszText, pszName);
+ wcscat(pszText, L": ");
+ pszName = pszText;
+ }
+ SendMessage(hwnd, EM_SETSEL, start, end);
+ SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM)pszName);
+ }
+ if(pszText)
+ mir_free(pszText);
+ fCompleted = true;
+ }
+ }
+ SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+ if(!fCompleted && !PluginConfig.m_AllowTab) {
+ if((GetSendButtonState(mwdat->hwnd) != PBS_DISABLED))
+ SetFocus(GetDlgItem(mwdat->hwnd, IDOK));
+ else
+ SetFocus(GetDlgItem(mwdat->hwnd, IDC_CHAT_LOG));
+ }
+ return 0;
+ } else if (wParam != VK_RIGHT && wParam != VK_LEFT) {
+ mir_free(dat->szSearchQuery);
+ dat->szSearchQuery = NULL;
+ mir_free(dat->szSearchResult);
+ dat->szSearchResult = NULL;
+ }
+
+ if (wParam == VK_F4 && isCtrl && !isAlt) { // ctrl-F4 (close tab)
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_CHAT_CLOSE, BN_CLICKED), 0);
+ return 0;
+ }
+
+ if (wParam == VK_NEXT || wParam == VK_PRIOR) {
+ HWND htemp = hwndParent;
+ SendDlgItemMessage(htemp, IDC_CHAT_LOG, msg, wParam, lParam);
+ dat->lastEnterTime = 0;
+ return 0;
+ }
+
+ if (wParam == VK_UP && isCtrl && !isAlt) {
+ int iLen;
+ GETTEXTLENGTHEX gtl = {0};
+ SETTEXTEX ste;
+ LOGFONTA lf;
+ char* lpPrevCmd = SM_GetPrevCommand(Parentsi->ptszID, Parentsi->pszModule);
+
+ SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+
+ LoadLogfont(MSGFONTID_MESSAGEAREA, &lf, NULL, FONTMODULE);
+ ste.flags = ST_DEFAULT;
+ ste.codepage = CP_ACP;
+ if (lpPrevCmd)
+ SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpPrevCmd);
+ else
+ SetWindowText(hwnd, _T(""));
+
+ gtl.flags = GTL_PRECISE;
+ gtl.codepage = CP_ACP;
+ iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM) & gtl, (LPARAM)NULL);
+ SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
+ SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+ SendMessage(hwnd, EM_SETSEL, iLen, iLen);
+ dat->lastEnterTime = 0;
+ return 0;
+ }
+
+ if (wParam == VK_DOWN && isCtrl && !isAlt) {
+ int iLen;
+ GETTEXTLENGTHEX gtl = {0};
+ SETTEXTEX ste;
+
+ char* lpPrevCmd = SM_GetNextCommand(Parentsi->ptszID, Parentsi->pszModule);
+ SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+
+ ste.flags = ST_DEFAULT;
+ ste.codepage = CP_ACP;
+ if (lpPrevCmd)
+ SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM) lpPrevCmd);
+ else
+ SetWindowText(hwnd, _T(""));
+
+ gtl.flags = GTL_PRECISE;
+ gtl.codepage = CP_ACP;
+ iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM) & gtl, (LPARAM)NULL);
+ SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
+ SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+ SendMessage(hwnd, EM_SETSEL, iLen, iLen);
+ dat->lastEnterTime = 0;
+ return 0;
+ }
+ if (wParam == VK_RETURN)
+ break;
+ //fall through
+ }
+
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_KILLFOCUS:
+ dat->lastEnterTime = 0;
+ break;
+
+ case WM_KEYUP:
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP: {
+ CHARFORMAT2 cf;
+ UINT u = 0;
+ UINT u2 = 0;
+ COLORREF cr;
+ MODULEINFO* mi = MM_FindModule(Parentsi->pszModule);
+
+ LoadLogfont(MSGFONTID_MESSAGEAREA, NULL, &cr, FONTMODULE);
+
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_BACKCOLOR | CFM_COLOR | CFM_UNDERLINETYPE;
+ cf.dwEffects = 0;
+ SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+
+ if (mi && mi->bColor) {
+ int index = Chat_GetColorIndex(Parentsi->pszModule, cf.crTextColor);
+ u = IsDlgButtonChecked(GetParent(hwnd), IDC_COLOR);
+
+ if (index >= 0) {
+ Parentsi->bFGSet = TRUE;
+ Parentsi->iFG = index;
+ }
+
+ if (u == BST_UNCHECKED && cf.crTextColor != cr)
+ CheckDlgButton(hwndParent, IDC_COLOR, BST_CHECKED);
+ else if (u == BST_CHECKED && cf.crTextColor == cr)
+ CheckDlgButton(hwndParent, IDC_COLOR, BST_UNCHECKED);
+ }
+
+ if (mi && mi->bBkgColor) {
+ int index = Chat_GetColorIndex(Parentsi->pszModule, cf.crBackColor);
+ COLORREF crB = (COLORREF)M->GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR);
+ u = IsDlgButtonChecked(hwndParent, IDC_BKGCOLOR);
+
+ if (index >= 0) {
+ Parentsi->bBGSet = TRUE;
+ Parentsi->iBG = index;
+ }
+
+ if (u == BST_UNCHECKED && cf.crBackColor != crB)
+ CheckDlgButton(hwndParent, IDC_BKGCOLOR, BST_CHECKED);
+ else if (u == BST_CHECKED && cf.crBackColor == crB)
+ CheckDlgButton(hwndParent, IDC_BKGCOLOR, BST_UNCHECKED);
+ }
+
+ if (mi && mi->bBold) {
+ u = IsDlgButtonChecked(hwndParent, IDC_CHAT_BOLD);
+ u2 = cf.dwEffects;
+ u2 &= CFE_BOLD;
+ if (u == BST_UNCHECKED && u2)
+ CheckDlgButton(hwndParent, IDC_CHAT_BOLD, BST_CHECKED);
+ else if (u == BST_CHECKED && u2 == 0)
+ CheckDlgButton(hwndParent, IDC_CHAT_BOLD, BST_UNCHECKED);
+ }
+
+ if (mi && mi->bItalics) {
+ u = IsDlgButtonChecked(hwndParent, IDC_ITALICS);
+ u2 = cf.dwEffects;
+ u2 &= CFE_ITALIC;
+ if (u == BST_UNCHECKED && u2)
+ CheckDlgButton(hwndParent, IDC_ITALICS, BST_CHECKED);
+ else if (u == BST_CHECKED && u2 == 0)
+ CheckDlgButton(hwndParent, IDC_ITALICS, BST_UNCHECKED);
+ }
+
+ if (mi && mi->bUnderline) {
+ u = IsDlgButtonChecked(hwndParent, IDC_CHAT_UNDERLINE);
+ if(cf.dwEffects & CFE_UNDERLINE && (cf.bUnderlineType & CFU_UNDERLINE || cf.bUnderlineType & CFU_UNDERLINEWORD)) {
+ if (u == BST_UNCHECKED )
+ CheckDlgButton(hwndParent, IDC_CHAT_UNDERLINE, BST_CHECKED);
+ }
+ else {
+ if (u == BST_CHECKED)
+ CheckDlgButton(hwndParent, IDC_CHAT_UNDERLINE, BST_UNCHECKED);
+ }
+ }
+ }
+ break;
+
+ case WM_INPUTLANGCHANGEREQUEST:
+ return DefWindowProc(hwnd, WM_INPUTLANGCHANGEREQUEST, wParam, lParam);
+
+ case WM_INPUTLANGCHANGE:
+ if (PluginConfig.m_AutoLocaleSupport && GetFocus() == hwnd && mwdat->pContainer->hwndActive == hwndParent && GetForegroundWindow() == mwdat->pContainer->hwnd && GetActiveWindow() == mwdat->pContainer->hwnd) {
+ DM_SaveLocale(mwdat, wParam, lParam);
+ SendMessage(hwnd, EM_SETLANGOPTIONS, 0, (LPARAM) SendMessage(hwnd, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
+ return 1;
+ }
+ break;
+
+ case WM_ERASEBKGND: {
+ return(CSkin::m_skinEnabled ? 0 : 1);
+ }
+
+ case EM_UNSUBCLASSED:
+ mir_free(dat);
+ return 0;
+ }
+
+ return CallWindowProc(OldMessageProc, hwnd, msg, wParam, lParam);
+}
+
+
+/*
+ * subclassing for the message filter dialog (set and configure event filters for the current
+ * session
+ */
+
+static UINT _eventorder[] = { GC_EVENT_ACTION,
+ GC_EVENT_MESSAGE,
+ GC_EVENT_NICK,
+ GC_EVENT_JOIN,
+ GC_EVENT_PART,
+ GC_EVENT_TOPIC,
+ GC_EVENT_ADDSTATUS,
+ GC_EVENT_INFORMATION,
+ GC_EVENT_QUIT,
+ GC_EVENT_KICK,
+ GC_EVENT_NOTICE,
+ 0
+};
+
+static INT_PTR CALLBACK FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ SESSION_INFO * si = (SESSION_INFO *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ switch (uMsg) {
+ case WM_INITDIALOG: {
+
+ si = (SESSION_INFO *)lParam;
+ DWORD dwMask = M->GetDword(si->hContact, "Chat", "FilterMask", 0);
+ DWORD dwFlags = M->GetDword(si->hContact, "Chat", "FilterFlags", 0);
+
+ DWORD dwPopupMask = M->GetDword(si->hContact, "Chat", "PopupMask", 0);
+ DWORD dwPopupFlags = M->GetDword(si->hContact, "Chat", "PopupFlags", 0);
+
+ DWORD dwTrayMask = M->GetDword(si->hContact, "Chat", "TrayIconMask", 0);
+ DWORD dwTrayFlags = M->GetDword(si->hContact, "Chat", "TrayIconFlags", 0);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)si);
+
+ for(int i = 0; _eventorder[i]; i++) {
+ CheckDlgButton(hwndDlg, IDC_1 + i, dwMask & _eventorder[i] ? (dwFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE);
+ CheckDlgButton(hwndDlg, IDC_P1 + i, dwPopupMask & _eventorder[i] ? (dwPopupFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE);
+ CheckDlgButton(hwndDlg, IDC_T1 + i, dwTrayMask & _eventorder[i] ? (dwTrayFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE);
+ }
+ return(FALSE);
+ }
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ SetTextColor((HDC)wParam, RGB(60, 60, 150));
+ SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
+ return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
+
+ case WM_CLOSE:
+ if (wParam == 1 && lParam == 1) {
+ int iFlags = 0, i;
+ UINT result;
+ DWORD dwMask = 0, dwFlags = 0;
+
+ for(i = 0; _eventorder[i]; i++) {
+ result = IsDlgButtonChecked(hwndDlg, IDC_1 + i);
+ dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0);
+ iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0);
+ }
+
+ if (iFlags&GC_EVENT_ADDSTATUS)
+ iFlags |= GC_EVENT_REMOVESTATUS;
+
+ if (si) {
+ if (dwMask == 0) {
+ DBDeleteContactSetting(si->hContact, "Chat", "FilterFlags");
+ DBDeleteContactSetting(si->hContact, "Chat", "FilterMask");
+ } else {
+ M->WriteDword(si->hContact, "Chat", "FilterFlags", iFlags);
+ M->WriteDword(si->hContact, "Chat", "FilterMask", dwMask);
+ }
+ }
+
+ dwMask = iFlags = 0;
+
+ for(i = 0; _eventorder[i]; i++) {
+ result = IsDlgButtonChecked(hwndDlg, IDC_P1 + i);
+ dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0);
+ iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0);
+ }
+
+ if (iFlags&GC_EVENT_ADDSTATUS)
+ iFlags |= GC_EVENT_REMOVESTATUS;
+
+ if (si) {
+ if (dwMask == 0) {
+ DBDeleteContactSetting(si->hContact, "Chat", "PopupFlags");
+ DBDeleteContactSetting(si->hContact, "Chat", "PopupMask");
+ } else {
+ M->WriteDword(si->hContact, "Chat", "PopupFlags", iFlags);
+ M->WriteDword(si->hContact, "Chat", "PopupMask", dwMask);
+ }
+ }
+
+ dwMask = iFlags = 0;
+
+ for(i = 0; _eventorder[i]; i++) {
+ result = IsDlgButtonChecked(hwndDlg, IDC_T1 + i);
+ dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0);
+ iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0);
+ }
+ if (iFlags&GC_EVENT_ADDSTATUS)
+ iFlags |= GC_EVENT_REMOVESTATUS;
+
+ if (si) {
+ if (dwMask == 0) {
+ DBDeleteContactSetting(si->hContact, "Chat", "TrayIconFlags");
+ DBDeleteContactSetting(si->hContact, "Chat", "TrayIconMask");
+ } else {
+ M->WriteDword(si->hContact, "Chat", "TrayIconFlags", iFlags);
+ M->WriteDword(si->hContact, "Chat", "TrayIconMask", dwMask);
+ }
+ Chat_SetFilters(si);
+ SendMessage(si->hWnd, GC_CHANGEFILTERFLAG, 0, (LPARAM)iFlags);
+ if (si->bFilterEnabled)
+ SendMessage(si->hWnd, GC_REDRAWLOG, 0, 0);
+ }
+ }
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+ break;
+ }
+ return(FALSE);
+}
+
+/**
+ * subclass for some tool bar buttons which must perform special actions
+ * on right click.
+ */
+static LRESULT CALLBACK ButtonSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndParent = GetParent(hwnd);
+
+ switch (msg) {
+ case WM_RBUTTONUP: {
+ HWND hFilter = GetDlgItem(hwndParent, IDC_FILTER);
+ HWND hColor = GetDlgItem(hwndParent, IDC_COLOR);
+ HWND hBGColor = GetDlgItem(hwndParent, IDC_BKGCOLOR);
+
+ if (M->GetByte("Chat", "RightClickFilter", 0) != 0) {
+ if (hFilter == hwnd)
+ SendMessage(hwndParent, GC_SHOWFILTERMENU, 0, 0);
+ if (hColor == hwnd)
+ SendMessage(hwndParent, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_COLOR);
+ if (hBGColor == hwnd)
+ SendMessage(hwndParent, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_BKGCOLOR);
+ }
+ }
+ break;
+ }
+
+ return CallWindowProc(OldFilterButtonProc, hwnd, msg, wParam, lParam);
+}
+
+
+/*
+ * subclassing for the message history display (rich edit control in which the chat history appears)
+ */
+
+static LRESULT CALLBACK LogSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndParent = GetParent(hwnd);
+ struct TWindowData *mwdat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA);
+
+ switch (msg) {
+ case WM_NCCALCSIZE:
+ return(CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, OldLogProc));
+
+ case WM_NCPAINT:
+ return(CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, OldLogProc));
+
+ case WM_COPY:
+ return(DM_WMCopyHandler(hwnd, OldLogProc, wParam, lParam));
+
+ case WM_SETCURSOR:
+ if (g_Settings.ClickableNicks && (LOWORD(lParam) == HTCLIENT)) {
+ POINT pt;
+ GetCursorPos(&pt);
+ ScreenToClient(hwnd,&pt);
+ if (CheckCustomLink(hwnd, &pt, msg, wParam, lParam, FALSE)) return TRUE;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONUP:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONDBLCLK:
+ if (g_Settings.ClickableNicks) {
+ POINT pt={LOWORD(lParam), HIWORD(lParam)};
+ CheckCustomLink(hwnd, &pt, msg, wParam, lParam, TRUE);
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ {
+ CHARRANGE sel;
+ if (g_Settings.ClickableNicks) {
+ POINT pt={LOWORD(lParam), HIWORD(lParam)};
+ CheckCustomLink(hwnd, &pt, msg, wParam, lParam, TRUE);
+ }
+ if(true || M->GetByte("autocopy", 0)) {
+ SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) &sel);
+ if (sel.cpMin != sel.cpMax) {
+ SendMessage(hwnd, WM_COPY, 0, 0);
+ sel.cpMin = sel.cpMax ;
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & sel);
+ SetFocus(GetDlgItem(hwndParent, IDC_CHAT_MESSAGE));
+ }
+ }
+ }
+ break;
+
+ case WM_KEYDOWN:
+ if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window)
+ PostMessage(hwndParent, WM_CLOSE, 0, 1);
+ return TRUE;
+ }
+ break;
+
+ case WM_SYSKEYUP:
+ if(wParam == VK_MENU) {
+ ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_CHAT_LOG);
+ return(0);
+ }
+ break;
+
+ case WM_SYSKEYDOWN:
+ mwdat->fkeyProcessed = false;
+ if(ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_CHAT_LOG)) {
+ mwdat->fkeyProcessed = true;
+ return(0);
+ }
+ break;
+
+ case WM_SYSCHAR: {
+ if(mwdat->fkeyProcessed) {
+ mwdat->fkeyProcessed = false;
+ return(0);
+ }
+ break;
+ }
+
+ case WM_ACTIVATE: {
+ if (LOWORD(wParam) == WA_INACTIVE) {
+ CHARRANGE sel;
+ SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) &sel);
+ if (sel.cpMin != sel.cpMax) {
+ sel.cpMin = sel.cpMax ;
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & sel);
+ }
+ }
+ }
+ break;
+
+ case WM_CHAR:
+ SetFocus(GetDlgItem(hwndParent, IDC_CHAT_MESSAGE));
+ SendMessage(GetDlgItem(hwndParent, IDC_CHAT_MESSAGE), WM_CHAR, wParam, lParam);
+ break;
+ }
+
+ return CallWindowProc(OldLogProc, hwnd, msg, wParam, lParam);
+}
+
+
+/*
+ * process mouse - hovering for the nickname list. fires events so the protocol can
+ * show the userinfo - tooltip.
+ */
+
+static void ProcessNickListHovering(HWND hwnd, int hoveredItem, POINT * pt, SESSION_INFO * parentdat)
+{
+ static int currentHovered = -1;
+ static HWND hwndToolTip = NULL;
+ static HWND oldParent = NULL;
+ TOOLINFO ti = {0};
+ RECT clientRect;
+ BOOL bNewTip = FALSE;
+ USERINFO *ui1 = NULL;
+
+ if (hoveredItem == currentHovered) return;
+ currentHovered = hoveredItem;
+
+ if (oldParent != hwnd && hwndToolTip) {
+ SendMessage(hwndToolTip, TTM_DELTOOL, 0, 0);
+ DestroyWindow(hwndToolTip);
+ hwndToolTip = NULL;
+ }
+ if (hoveredItem == -1) {
+
+ SendMessage(hwndToolTip, TTM_ACTIVATE, 0, 0);
+
+ } else {
+
+ if (!hwndToolTip) {
+ hwndToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL,
+ WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ hwnd, NULL, g_hInst, NULL);
+ bNewTip = TRUE;
+ }
+
+ GetClientRect(hwnd, &clientRect);
+ ti.cbSize = sizeof(TOOLINFO);
+ ti.uFlags = TTF_SUBCLASS;
+ ti.hinst = g_hInst;
+ ti.hwnd = hwnd;
+ ti.uId = 1;
+ ti.rect = clientRect;
+
+ ti.lpszText = NULL;
+
+ ui1 = SM_GetUserFromIndex(parentdat->ptszID, parentdat->pszModule, currentHovered);
+ if (ui1) {
+ char serviceName[256];
+ _snprintf(serviceName, SIZEOF(serviceName), "%s"MS_GC_PROTO_GETTOOLTIPTEXT, parentdat->pszModule);
+ if (ServiceExists(serviceName))
+ ti.lpszText = (TCHAR*)CallService(serviceName, (WPARAM)parentdat->ptszID, (LPARAM)ui1->pszUID);
+ else {
+ TCHAR ptszBuf[ 1024 ];
+ mir_sntprintf( ptszBuf, SIZEOF(ptszBuf), _T("%s: %s\r\n%s: %s\r\n%s: %s"),
+ CTranslator::get(CTranslator::GEN_MUC_NICKNAME), ui1->pszNick,
+ CTranslator::get(CTranslator::GEN_MUC_UID), ui1->pszUID,
+ CTranslator::get(CTranslator::GEN_MUC_STATUS), TM_WordToString( parentdat->pStatuses, ui1->Status ));
+ ti.lpszText = mir_tstrdup( ptszBuf );
+ }
+ }
+
+ SendMessage(hwndToolTip, bNewTip ? TTM_ADDTOOL : TTM_UPDATETIPTEXT, 0, (LPARAM) &ti);
+ SendMessage(hwndToolTip, TTM_ACTIVATE, (ti.lpszText != NULL) , 0);
+ SendMessage(hwndToolTip, TTM_SETMAXTIPWIDTH, 0 , 400);
+ if (ti.lpszText)
+ mir_free(ti.lpszText);
+ }
+}
+
+/*
+ * subclassing for the nickname list control. It is an ownerdrawn listbox
+ */
+
+static LRESULT CALLBACK NicklistSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndParent = GetParent(hwnd);
+ struct TWindowData *mwdat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA);
+
+ static BOOL isToolTip = NULL;
+ static int currentHovered = -1;
+
+ switch (msg) {
+ //MAD: attemp to fix weird bug, when combobox with hidden vscroll
+ //can't be scrolled with mouse-wheel.
+ case WM_NCCALCSIZE: {
+ if (CSkin::m_DisableScrollbars) {
+ RECT lpRect;
+ LONG itemHeight;
+
+ GetClientRect (hwnd, &lpRect);
+ itemHeight = SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0);
+ g_cLinesPerPage = (lpRect.bottom - lpRect.top) /itemHeight ;
+ }
+ return(CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKUSERLIST, msg, wParam, lParam, OldNicklistProc));
+ }
+ //
+ case WM_NCPAINT:
+ return(CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKUSERLIST, msg, wParam, lParam, OldNicklistProc));
+
+ case WM_ERASEBKGND: {
+ HDC dc = (HDC)wParam;
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA);
+ SESSION_INFO *parentdat = (SESSION_INFO *)dat->si;
+ if (dc) {
+ int height, index, items = 0;
+
+ index = SendMessage(hwnd, LB_GETTOPINDEX, 0, 0);
+ if (index == LB_ERR || parentdat->nUsersInNicklist <= 0)
+ return 0;
+
+ items = parentdat->nUsersInNicklist - index;
+ height = SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0);
+
+ if (height != LB_ERR) {
+ RECT rc = {0};
+ GetClientRect(hwnd, &rc);
+
+ if (rc.bottom - rc.top > items * height) {
+ rc.top = items * height;
+ FillRect(dc, &rc, hListBkgBrush);
+ }
+ }
+ }
+ }
+ return 1;
+
+ //MAD
+ case WM_MOUSEWHEEL: {
+ if (CSkin::m_DisableScrollbars) {
+ UINT uScroll;
+ int dLines;
+ short zDelta=(short)HIWORD(wParam);
+ if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uScroll, 0))
+ uScroll = 3; /* default value */
+
+ if (uScroll == WHEEL_PAGESCROLL)
+ uScroll = g_cLinesPerPage;
+ if (uScroll == 0)
+ return 0;
+
+ zDelta += g_iWheelCarryover; /* Accumulate wheel motion */
+
+ dLines = zDelta * (int)uScroll / WHEEL_DELTA;
+
+
+ //Record the unused portion as the next carryover.
+ g_iWheelCarryover = zDelta - dLines * WHEEL_DELTA / (int)uScroll;
+
+
+ // scrolling.
+ while (abs(dLines)) {
+ if (dLines > 0) {
+ SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
+ dLines--;
+ } else {
+ SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
+ dLines++;
+ }
+ }
+ return 0;
+ }
+ break;
+ }
+//MAD_
+ case WM_KEYDOWN:
+ if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window)
+ PostMessage(hwndParent, WM_CLOSE, 0, 1);
+ return TRUE;
+ }
+ if (wParam == VK_ESCAPE || wParam == VK_UP || wParam == VK_DOWN || wParam == VK_NEXT ||
+ wParam == VK_PRIOR || wParam == VK_TAB || wParam == VK_HOME || wParam == VK_END) {
+ if (mwdat && mwdat->si) {
+ SESSION_INFO *si = (SESSION_INFO *)mwdat->si;
+ si->szSearch[0] = 0;
+ si->iSearchItem = -1;
+ }
+ }
+ break;
+
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ if (mwdat && mwdat->si) { // set/kill focus invalidates incremental search status
+ SESSION_INFO *si = (SESSION_INFO *)mwdat->si;
+ si->szSearch[0] = 0;
+ si->iSearchItem = -1;
+ }
+ break;
+
+ case WM_CHAR:
+ case WM_UNICHAR: {
+ /*
+ * simple incremental search for the user (nick) - list control
+ * typing esc or movement keys will clear the current search string
+ */
+
+ if (mwdat && mwdat->si) {
+ SESSION_INFO *si = (SESSION_INFO *)mwdat->si;
+ if (wParam == 27 && si->szSearch[0]) { // escape - reset everything
+ si->szSearch[0] = 0;
+ si->iSearchItem = -1;
+ break;
+ } else if (wParam == '\b' && si->szSearch[0]) // backspace
+ si->szSearch[lstrlen(si->szSearch) - 1] = '\0';
+ else if (wParam < ' ')
+ break;
+ else {
+ TCHAR szNew[2];
+ szNew[0] = (TCHAR) wParam;
+ szNew[1] = '\0';
+ if (lstrlen(si->szSearch) >= SIZEOF(si->szSearch) - 2) {
+ MessageBeep(MB_OK);
+ break;
+ }
+ _tcscat(si->szSearch, szNew);
+ }
+ if (si->szSearch[0]) {
+ int iItems = SendMessage(hwnd, LB_GETCOUNT, 0, 0);
+ int i;
+ USERINFO *ui;
+
+ /*
+ * iterate over the (sorted) list of nicknames and search for the
+ * string we have
+ */
+
+ for (i = 0; i < iItems; i++) {
+ ui = UM_FindUserFromIndex(si->pUsers, i);
+ if (ui) {
+ if (!_tcsnicmp(ui->pszNick, si->szSearch, lstrlen(si->szSearch))) {
+ SendMessage(hwnd, LB_SETSEL, FALSE, -1);
+ SendMessage(hwnd, LB_SETSEL, TRUE, i);
+ si->iSearchItem = i;
+ InvalidateRect(hwnd, NULL, FALSE);
+ return 0;
+ }
+ }
+ }
+ if (i == iItems) {
+ MessageBeep(MB_OK);
+ si->szSearch[lstrlen(si->szSearch) - 1] = '\0';
+ return 0;
+ }
+ }
+ }
+ break;
+ }
+
+ case WM_RBUTTONDOWN: {
+ int iCounts = SendMessage(hwnd, LB_GETSELCOUNT, 0, 0);
+
+ if (iCounts != LB_ERR && iCounts > 1)
+ return 0;
+ SendMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
+ break;
+ }
+
+ case WM_RBUTTONUP:
+ SendMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
+ break;
+
+ case WM_MEASUREITEM: {
+ MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *) lParam;
+ if (mis->CtlType == ODT_MENU)
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+ return FALSE;
+ }
+
+ case WM_DRAWITEM: {
+ DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *) lParam;
+ if (dis->CtlType == ODT_MENU)
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+ return FALSE;
+ }
+ case WM_CONTEXTMENU: {
+ TVHITTESTINFO hti;
+ int item;
+ int height;
+ USERINFO * ui;
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA);
+ SESSION_INFO *parentdat = (SESSION_INFO *)dat->si;
+
+
+ hti.pt.x = (short) LOWORD(lParam);
+ hti.pt.y = (short) HIWORD(lParam);
+ if (hti.pt.x == -1 && hti.pt.y == -1) {
+ int index = SendMessage(hwnd, LB_GETCURSEL, 0, 0);
+ int top = SendMessage(hwnd, LB_GETTOPINDEX, 0, 0);
+ height = SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0);
+ hti.pt.x = 4;
+ hti.pt.y = (index - top) * height + 1;
+ } else
+ ScreenToClient(hwnd, &hti.pt);
+
+ item = (DWORD)(SendMessage(hwnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(hti.pt.x, hti.pt.y)));
+ if ( HIWORD( item ) == 1 )
+ item = (DWORD)(-1);
+ else
+ item &= 0xFFFF;
+
+ ui = SM_GetUserFromIndex(parentdat->ptszID, parentdat->pszModule, item);
+ // ui = (USERINFO *)SendMessage(GetDlgItem(hwndParent, IDC_LIST), LB_GETITEMDATA, item, 0);
+ if (ui) {
+ HMENU hMenu = 0;
+ UINT uID;
+ USERINFO uinew;
+
+ memcpy(&uinew, ui, sizeof(USERINFO));
+ if (hti.pt.x == -1 && hti.pt.y == -1)
+ hti.pt.y += height - 4;
+ ClientToScreen(hwnd, &hti.pt);
+ uID = CreateGCMenu(hwnd, &hMenu, 0, hti.pt, parentdat, uinew.pszUID, NULL);
+
+ switch (uID) {
+ case 0:
+ break;
+
+ case 20020: { // add to highlight...
+ RECT rc, rcWnd;
+ THighLightEdit the = {THighLightEdit::CMD_ADD, parentdat, ui};
+
+ if(parentdat && ui) {
+ HWND hwnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_ADDHIGHLIGHT), parentdat->dat->pContainer->hwnd, CMUCHighlight::dlgProcAdd, (LPARAM)&the);
+ TranslateDialogDefault(hwnd);
+ GetClientRect(parentdat->pContainer->hwnd, &rcWnd);
+ GetWindowRect(hwnd, &rc);
+
+ SetWindowPos(hwnd, HWND_TOP, (rcWnd.right - (rc.right - rc.left)) / 2, (rcWnd.bottom - (rc.bottom - rc.top)) / 2 , 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
+ }
+ break;
+ }
+
+ case ID_MESS:
+ DoEventHookAsync(GetParent(hwnd), parentdat->ptszID, parentdat->pszModule, GC_USER_PRIVMESS, ui->pszUID, NULL, (LPARAM)NULL);
+ break;
+
+ default: {
+ int iCount = SendMessage(hwnd, LB_GETCOUNT, 0, 0);
+
+ if (iCount != LB_ERR) {
+ int iSelectedItems = SendMessage(hwnd, LB_GETSELCOUNT, 0, 0);
+
+ if (iSelectedItems != LB_ERR) {
+ int *pItems = (int *)malloc(sizeof(int) * (iSelectedItems + 1));
+
+ if (pItems) {
+ if (SendMessage(hwnd, LB_GETSELITEMS, (WPARAM)iSelectedItems, (LPARAM)pItems) != LB_ERR) {
+ USERINFO *ui1 = NULL;
+ int i;
+
+ for (i = 0; i < iSelectedItems; i++) {
+ ui1 = SM_GetUserFromIndex(parentdat->ptszID, parentdat->pszModule, pItems[i]);
+ if (ui1)
+ DoEventHookAsync(hwndParent, parentdat->ptszID, parentdat->pszModule, GC_USER_NICKLISTMENU, ui1->pszUID, NULL, (LPARAM)uID);
+ }
+ }
+ free(pItems);
+ }
+ }
+ }
+ //DoEventHookAsync(hwndParent, parentdat->ptszID, parentdat->pszModule, GC_USER_NICKLISTMENU, ui->pszUID, NULL, (LPARAM)uID);
+ break;
+ }
+ }
+ DestroyGCMenu(&hMenu, 1);
+ return TRUE;
+ }
+ }
+ break;
+
+ case WM_MOUSEMOVE: {
+ POINT pt;
+ RECT clientRect;
+ pt.x = LOWORD(lParam);
+ pt.y = HIWORD(lParam);
+ GetClientRect(hwnd, &clientRect);
+ if (PtInRect(&clientRect, pt)) {
+ //hit test item under mouse
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA);
+ SESSION_INFO *parentdat = (SESSION_INFO *)dat->si;
+
+ DWORD nItemUnderMouse = (DWORD)SendMessage(hwnd, LB_ITEMFROMPOINT, 0, lParam);
+ if (HIWORD(nItemUnderMouse) == 1)
+ nItemUnderMouse = (DWORD)(-1);
+ else
+ nItemUnderMouse &= 0xFFFF;
+
+ if (M->GetByte("adv_TipperTooltip", 1) && ServiceExists("mToolTip/HideTip")) {
+ if ((int)nItemUnderMouse == currentHovered) break;
+ currentHovered = (int)nItemUnderMouse;
+
+ KillTimer(hwnd, 1);
+
+ if (isToolTip) {
+ CallService("mToolTip/HideTip", 0, 0);
+ isToolTip = FALSE;
+ }
+
+ if (nItemUnderMouse != -1)
+ SetTimer(hwnd, 1, 450, 0);
+ }
+ else ProcessNickListHovering(hwnd, (int)nItemUnderMouse, &pt, parentdat);
+ }
+ else
+ {
+ if (M->GetByte("adv_TipperTooltip", 1) && ServiceExists("mToolTip/HideTip")) {
+ KillTimer(hwnd, 1);
+ if (isToolTip) {
+ CallService("mToolTip/HideTip", 0, 0);
+ isToolTip = FALSE;
+ }
+ }
+ else ProcessNickListHovering(hwnd, -1, &pt, NULL);
+ }
+ }
+ break;
+
+ case WM_TIMER:
+ {
+ CLCINFOTIP ti = {0};
+ USERINFO *ui1 = NULL;
+ TCHAR ptszBuf[1024];
+ char serviceName[256];
+ POINT pt;
+
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA);
+ SESSION_INFO * parentdat = dat->si;
+
+ GetCursorPos(&pt);
+ ScreenToClient(hwnd, &pt);
+
+ DWORD nItemUnderMouse = (DWORD)SendMessage(GetDlgItem(dat->hwnd, IDC_LIST), LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y));
+ if (HIWORD(nItemUnderMouse) == 1)
+ nItemUnderMouse = (DWORD)(-1);
+ else
+ nItemUnderMouse &= 0xFFFF;
+ if (((int)nItemUnderMouse != currentHovered) || (nItemUnderMouse == -1)) {
+ KillTimer(hwnd, 1);
+ break;
+ }
+
+ ui1 = SM_GetUserFromIndex(parentdat->ptszID, parentdat->pszModule, currentHovered);
+
+ if (ui1) {
+ ti.cbSize = sizeof(ti);
+ mir_snprintf(serviceName, SIZEOF(serviceName), "%s"MS_GC_PROTO_GETTOOLTIPTEXT, parentdat->pszModule);
+
+ if (ServiceExists(serviceName))
+ mir_sntprintf(ptszBuf, SIZEOF(ptszBuf), _T("%s"), (TCHAR*)CallService(serviceName, (WPARAM)parentdat->ptszID, (LPARAM)ui1->pszUID));
+ else
+ mir_sntprintf(ptszBuf, SIZEOF(ptszBuf), _T("<b>%s:</b>\t%s\n<b>%s:</b>\t%s\n<b>%s:</b>\t%s"),
+ TranslateT("Nick"), ui1->pszNick,
+ TranslateT("Unique id"), ui1->pszUID,
+ TranslateT("Status"), TM_WordToString(parentdat->pStatuses, ui1->Status));
+
+ if (ptszBuf != NULL)
+ if (CallService("mToolTip/ShowTipW", (WPARAM)mir_tstrdup(ptszBuf), (LPARAM)&ti))
+ isToolTip = TRUE;
+ }
+ KillTimer(hwnd, 1);
+ }
+ break;
+ }
+ return CallWindowProc(OldNicklistProc, hwnd, msg, wParam, lParam);
+}
+
+/*
+ * calculate the required rectangle for a string using the given font. This is more
+ * precise than using GetTextExtentPoint...()
+ */
+
+int GetTextPixelSize(TCHAR* pszText, HFONT hFont, BOOL bWidth)
+{
+ HDC hdc;
+ HFONT hOldFont;
+ RECT rc = {0};
+ int i;
+
+ if (!pszText || !hFont)
+ return 0;
+
+ hdc = GetDC(NULL);
+ hOldFont = (HFONT)SelectObject(hdc, hFont);
+ i = DrawText(hdc, pszText , -1, &rc, DT_CALCRECT);
+ SelectObject(hdc, hOldFont);
+ ReleaseDC(NULL, hdc);
+ return bWidth ? rc.right - rc.left : rc.bottom - rc.top;
+}
+
+static void __cdecl phase2(void * lParam)
+{
+ SESSION_INFO* si = (SESSION_INFO*) lParam;
+ Sleep(30);
+ if (si && si->hWnd)
+ PostMessage(si->hWnd, GC_REDRAWLOG3, 0, 0);
+}
+
+
+/*
+ * the actual group chat session window procedure. Handles the entire chat session window
+ * which is usually a (tabbed) child of a container class window.
+ */
+
+INT_PTR CALLBACK RoomWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ SESSION_INFO * si = NULL;
+ HWND hwndTab = GetParent(hwndDlg);
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ if (dat)
+ si = (SESSION_INFO *)dat->si;
+
+ if (dat == NULL && (uMsg == WM_ACTIVATE || uMsg == WM_SETFOCUS))
+ return 0;
+
+ switch (uMsg) {
+ case WM_INITDIALOG: {
+ int mask;
+ struct TNewWindowData *newData = (struct TNewWindowData *) lParam;
+ struct TWindowData *dat;
+ SESSION_INFO *psi = (SESSION_INFO*)newData->hdbEvent;
+ RECT rc;
+
+ dat = (struct TWindowData *)malloc(sizeof(struct TWindowData));
+ ZeroMemory(dat, sizeof(struct TWindowData));
+ si = psi;
+ dat->si = psi;
+ dat->hContact = psi->hContact;
+ dat->szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)psi->hContact, 0);
+ dat->bType = SESSIONTYPE_CHAT;
+ dat->Panel = new CInfoPanel(dat);
+
+ dat->cache = CContactCache::getContactCache(dat->hContact);
+ dat->cache->updateState();
+ dat->cache->updateUIN();
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+ newData->item.lParam = (LPARAM) hwndDlg;
+ TabCtrl_SetItem(hwndTab, newData->iTabID, &newData->item);
+ dat->iTabID = newData->iTabID;
+ dat->pContainer = newData->pContainer;
+ psi->pContainer = newData->pContainer;
+ dat->hwnd = hwndDlg;
+ psi->hWnd = hwndDlg;
+ psi->dat = dat;
+ dat->fIsAutosizingInput = IsAutoSplitEnabled(dat);
+ dat->fLimitedUpdate = false;
+ dat->iInputAreaHeight = -1;
+ if(!dat->pContainer->settings->fPrivate)
+ psi->iSplitterY = g_Settings.iSplitterY;
+ else {
+ if(M->GetByte("Chat", "SyncSplitter", 0))
+ psi->iSplitterY = dat->pContainer->settings->splitterPos - DPISCALEY_S(23);
+ else
+ psi->iSplitterY = g_Settings.iSplitterY;
+ }
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ if(dat->fIsAutosizingInput)
+ psi->iSplitterY = GetDefaultMinimumInputHeight(dat);
+#endif
+ dat->pWnd = 0;
+ CProxyWindow::add(dat);
+
+ dat->fInsertMode = FALSE;
+
+ dat->codePage = M->GetDword(dat->hContact, "ANSIcodepage", CP_ACP);
+ dat->Panel->getVisibility();
+ dat->Panel->Configure();
+ M->AddWindow(hwndDlg, dat->hContact);
+ BroadCastContainer(dat->pContainer, DM_REFRESHTABINDEX, 0, 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETOLECALLBACK, 0, (LPARAM) mREOLECallback);
+
+ BB_InitDlgButtons(dat);
+ DM_InitTip(dat);
+
+ SendMessage(GetDlgItem(hwndDlg,IDC_COLOR), BUTTONSETASPUSHBTN, 0, 0);
+
+ OldSplitterProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTERX), GWLP_WNDPROC, (LONG_PTR)SplitterSubclassProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTERY), GWLP_WNDPROC, (LONG_PTR)SplitterSubclassProc);
+ OldNicklistProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LIST), GWLP_WNDPROC, (LONG_PTR)NicklistSubclassProc);
+ OldLogProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHAT_LOG), GWLP_WNDPROC, (LONG_PTR)LogSubclassProc);
+ OldFilterButtonProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_WNDPROC, (LONG_PTR)ButtonSubclassProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_COLOR), GWLP_WNDPROC, (LONG_PTR)ButtonSubclassProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_BKGCOLOR), GWLP_WNDPROC, (LONG_PTR)ButtonSubclassProc);
+ OldMessageProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), GWLP_WNDPROC, (LONG_PTR)MessageSubclassProc);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SUBCLASSED, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_AUTOURLDETECT, 1, 0);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PANELSPLITTER), GWLP_WNDPROC, (LONG_PTR) SplitterSubclassProc);
+ TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPENING, 0);
+
+ mask = (int)SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_GETEVENTMASK, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETEVENTMASK, 0, mask | ENM_LINK | ENM_MOUSEEVENTS | ENM_KEYEVENTS);
+
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETEVENTMASK, 0, ENM_REQUESTRESIZE | ENM_MOUSEEVENTS | ENM_SCROLL | ENM_KEYEVENTS | ENM_CHANGE);
+#else
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_SCROLL | ENM_KEYEVENTS | ENM_CHANGE);
+#endif
+
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_LIMITTEXT, (WPARAM)0x7FFFFFFF, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3));
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3));
+ dat->Panel->loadHeight();
+ Utils::enableDlgControl(hwndDlg, IDC_SMILEYBTN, TRUE);
+
+ if (PluginConfig.g_hMenuTrayUnread != 0 && dat->hContact != 0 && dat->szProto != NULL)
+ UpdateTrayMenu(0, dat->wStatus, dat->szProto, dat->szStatus, dat->hContact, FALSE);
+
+ DM_ThemeChanged(dat);
+ SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_HIDESELECTION, TRUE, 0);
+
+ CreateWindowEx(0, _T("TSButtonClass"), _T(""), WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0, 0, 6, DPISCALEY_S(20),
+ hwndDlg, (HMENU)IDC_CHAT_TOGGLESIDEBAR, g_hInst, NULL);
+
+ GetMYUIN(dat);
+ GetMyNick(dat);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_TOGGLESIDEBAR, BUTTONSETASFLATBTN + 10, 0, PluginConfig.m_bIsXP);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_TOGGLESIDEBAR, BUTTONSETASFLATBTN + 12, 0, (LPARAM)dat->pContainer);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_TOGGLESIDEBAR, BUTTONSETASFLATBTN, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_TOGGLESIDEBAR, BUTTONSETASTOOLBARBUTTON, 0, 1);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_TOGGLESIDEBAR, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Expand or collapse the side bar"), 1);
+
+ dat->hwndIEView = dat->hwndHPP = 0;
+
+ //Chat_SetMessageLog(dat);
+
+ SendMessage(hwndDlg, GC_SETWNDPROPS, 0, 0);
+ SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
+ SendMessage(hwndDlg, GC_UPDATETITLE, 0, 1);
+ SendMessage(dat->pContainer->hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc);
+ SetWindowPos(hwndDlg, HWND_TOP, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), 0);
+ ShowWindow(hwndDlg, SW_SHOW);
+ PostMessage(hwndDlg, GC_UPDATENICKLIST, 0, 0);
+ dat->pContainer->hwndActive = hwndDlg;
+ BB_SetButtonsPos(dat);
+ TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPEN, 0);
+ }
+ break;
+
+ case WM_SETFOCUS:
+ if (CMimAPI::m_shutDown)
+ break;
+
+ Chat_UpdateWindowState(dat, WM_SETFOCUS);
+ SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE));
+ return 1;
+
+ case WM_TIMECHANGE:
+ PostMessage(hwndDlg, GC_REDRAWLOG, 0, 0);
+ break;
+
+ case DM_LOADBUTTONBARICONS: {
+ BB_UpdateIcons(hwndDlg, dat);
+ return 0;
+ }
+
+ case GC_SETWNDPROPS: {
+ //HICON hIcon;
+ COLORREF colour = M->GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR);
+ InitButtons(hwndDlg, si);
+ ConfigureSmileyButton(dat);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETBKGNDCOLOR, 0, colour);
+
+ DM_InitRichEdit(dat);
+ SendDlgItemMessage(hwndDlg, IDOK, BUTTONSETASFLATBTN + 14, 0, 0);
+ {
+ SendMessage(GetDlgItem(hwndDlg, IDC_LIST), LB_SETITEMHEIGHT, 0, (LPARAM)g_Settings.iNickListFontHeight);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_LIST), NULL, TRUE);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_FILTER, BUTTONSETOVERLAYICON, 0,
+ (LPARAM)(si->bFilterEnabled ? PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled));
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ SendMessage(hwndDlg, GC_REDRAWLOG2, 0, 0);
+ }
+ break;
+
+ case DM_UPDATETITLE:
+ return(SendMessage(hwndDlg, GC_UPDATETITLE, wParam, lParam));
+
+ case GC_UPDATETITLE: {
+ TCHAR szTemp [100];
+ HICON hIcon;
+ BOOL fNoCopy = TRUE;
+ const TCHAR* szNick = dat->cache->getNick();
+
+ if(dat->bWasDeleted)
+ return(0);
+
+ dat->wStatus = si->wStatus;
+
+ if (lstrlen(szNick) > 0) {
+ if (M->GetByte("cuttitle", 0))
+ CutContactName(szNick, dat->newtitle, safe_sizeof(dat->newtitle));
+ else {
+ lstrcpyn(dat->newtitle, szNick, safe_sizeof(dat->newtitle));
+ dat->newtitle[129] = 0;
+ }
+ }
+
+ switch (si->iType) {
+ case GCW_CHATROOM:
+ hIcon = dat->wStatus <= ID_STATUS_OFFLINE ? LoadSkinnedProtoIcon(si->pszModule, ID_STATUS_OFFLINE) : LoadSkinnedProtoIcon(si->pszModule, dat->wStatus);
+ fNoCopy = FALSE;
+ mir_sntprintf(szTemp, SIZEOF(szTemp),
+ (si->nUsersInNicklist == 1) ? CTranslator::get(CTranslator::GEN_MUC_ROOM_TITLE_USER) :
+ CTranslator::get(CTranslator::GEN_MUC_ROOM_TITLE_USERS),
+ si->ptszName, si->nUsersInNicklist, si->bFilterEnabled ? CTranslator::get(CTranslator::GEN_MUC_ROOM_TITLE_FILTER) : _T(""));
+ break;
+ case GCW_PRIVMESS:
+ mir_sntprintf(szTemp, SIZEOF(szTemp),
+ (si->nUsersInNicklist == 1) ? CTranslator::get(CTranslator::GEN_MUC_PRIVSESSION) :
+ CTranslator::get(CTranslator::GEN_MUC_PRIVSESSION_MULTI), si->ptszName, si->nUsersInNicklist);
+ break;
+ case GCW_SERVER:
+ mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s: Server"), si->ptszName);
+ hIcon = LoadIconEx(IDI_CHANMGR, "window", 16, 16);
+ break;
+ }
+
+ if(dat->pWnd) {
+ dat->pWnd->updateTitle(dat->newtitle);
+ dat->pWnd->updateIcon(hIcon);
+ }
+ dat->hTabStatusIcon = hIcon;
+
+ if (lParam)
+ dat->hTabIcon = dat->hTabStatusIcon;
+
+ if (dat->cache->getStatus() != dat->cache->getOldStatus()) {
+ TCITEM item;
+
+ ZeroMemory(&item, sizeof(item));
+ item.mask = TCIF_TEXT;
+
+ lstrcpyn(dat->szStatus, (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)dat->wStatus, GSMDF_TCHAR), 50);
+ dat->szStatus[49] = 0;
+ item.pszText = dat->newtitle;
+ item.cchTextMax = 120;
+ TabCtrl_SetItem(hwndTab, dat->iTabID, &item);
+ }
+ SetWindowText(hwndDlg, szTemp);
+ if (dat->pContainer->hwndActive == hwndDlg) {
+ SendMessage(dat->pContainer->hwnd, DM_UPDATETITLE, (WPARAM)hwndDlg, 1);
+ SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
+ }
+ }
+ break;
+
+ case GC_UPDATESTATUSBAR:
+ if(dat->bWasDeleted)
+ return(0);
+
+ if (dat->pContainer->hwndActive != hwndDlg || dat->pContainer->hwndStatus == 0 || CMimAPI::m_shutDown || dat->szStatusBar[0])
+ break;
+ if (si->pszModule != NULL) {
+ TCHAR szFinalStatusBarText[512];
+ MODULEINFO* mi=NULL;
+ int x = 12;
+
+ //Mad: strange rare crash here...
+ mi = MM_FindModule(si->pszModule);
+ if(!mi)
+ break;
+
+ if(!mi->ptszModDispName)
+ break;
+
+ x += GetTextPixelSize(mi->ptszModDispName, (HFONT)SendMessage(dat->pContainer->hwndStatus, WM_GETFONT, 0, 0), TRUE);
+ x += GetSystemMetrics(SM_CXSMICON);
+
+ if(dat->Panel->isActive()) {
+ time_t now = time(0);
+ DWORD diff = (now - mi->idleTimeStamp) / 60;
+
+ if((diff >= 1 && diff != mi->lastIdleCheck) || lParam) {
+ mi->lastIdleCheck = diff;
+ if(diff == 0)
+ mi->tszIdleMsg[0] = 0;
+ else if(diff > 59) {
+ DWORD hours = diff / 60;
+ DWORD minutes = diff % 60;
+ mir_sntprintf(mi->tszIdleMsg, 60, CTranslator::get(CTranslator::MUC_SBAR_IDLEFORMAT), hours, hours > 1 ?
+ CTranslator::get(CTranslator::GEN_STRING_HOURS) : CTranslator::get(CTranslator::GEN_STRING_HOUR),
+ minutes, minutes > 1 ? CTranslator::get(CTranslator::GEN_STRING_MINUTES) : CTranslator::get(CTranslator::GEN_STRING_MINUTE));
+ }
+ else
+ mir_sntprintf(mi->tszIdleMsg, 60, CTranslator::get(CTranslator::MUC_SBAR_IDLEFORMAT_SHORT),
+ diff, diff > 1 ? CTranslator::get(CTranslator::GEN_STRING_MINUTES) : CTranslator::get(CTranslator::GEN_STRING_MINUTE));
+ }
+ mir_sntprintf(szFinalStatusBarText, SIZEOF(szFinalStatusBarText), CTranslator::get(CTranslator::MUC_SBAR_ON_SERVER), dat->szMyNickname, mi->ptszModDispName, mi->tszIdleMsg);
+ } else {
+ if (si->ptszStatusbarText)
+ mir_sntprintf(szFinalStatusBarText, SIZEOF(szFinalStatusBarText), _T("%s %s"), mi->ptszModDispName, si->ptszStatusbarText);
+ else {
+ lstrcpyn(szFinalStatusBarText, mi->ptszModDispName, SIZEOF(szFinalStatusBarText));
+ szFinalStatusBarText[511] = 0;
+ }
+ }
+ SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)szFinalStatusBarText);
+ UpdateStatusBar(dat);
+ dat->Panel->Invalidate();
+ if(dat->pWnd)
+ dat->pWnd->Invalidate();
+ return TRUE;
+ }
+ break;
+
+ case WM_SIZE: {
+ UTILRESIZEDIALOG urd;
+ RECT rc;
+ int panelHeight = dat->Panel->getHeight() + 1;
+ LONG cx;
+
+ if (dat->ipFieldHeight == 0)
+ dat->ipFieldHeight = CInfoPanel::m_ipConfig.height1;
+
+ if (wParam == SIZE_MAXIMIZED)
+ PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0);
+
+ if (IsIconic(hwndDlg)) break;
+ ZeroMemory(&urd, sizeof(urd));
+ urd.cbSize = sizeof(urd);
+ urd.hInstance = g_hInst;
+ urd.hwndDlg = hwndDlg;
+ urd.lParam = (LPARAM)si;
+ urd.lpTemplate = MAKEINTRESOURCEA(IDD_CHANNEL);
+ urd.pfnResizer = RoomWndResize;
+ CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd);
+ //mad
+ BB_SetButtonsPos(dat);
+
+ GetClientRect(hwndDlg, &rc);
+ cx = rc.right;
+
+ rc.left = panelHeight <= CInfoPanel::LEFT_OFFSET_LOGO ? panelHeight : CInfoPanel::LEFT_OFFSET_LOGO;
+ rc.right = cx;
+ rc.top = 1;
+ rc.bottom = (panelHeight > CInfoPanel::DEGRADE_THRESHOLD ? rc.top + dat->ipFieldHeight - 2 : panelHeight - 1);
+ dat->rcNick = rc;
+
+ rc.left = panelHeight <= CInfoPanel::LEFT_OFFSET_LOGO ? panelHeight : CInfoPanel::LEFT_OFFSET_LOGO;
+ rc.right = cx;
+ rc.bottom = panelHeight - 2;
+ rc.top = dat->rcNick.bottom + 1;
+ dat->rcUIN = rc;
+
+ if (dat->hwndIEView || dat->hwndHPP)
+ Chat_ResizeIeView(dat);
+ DetermineMinHeight(dat);
+ }
+ break;
+
+ case GC_REDRAWWINDOW:
+ InvalidateRect(hwndDlg, NULL, TRUE);
+ break;
+
+ case GC_REDRAWLOG:
+ si->LastTime = 0;
+ if (si->pLog) {
+ LOGINFO * pLog = si->pLog;
+ if (si->iEventCount > 60) {
+ int index = 0;
+ while (index < 59) {
+ if (pLog->next == NULL)
+ break;
+ pLog = pLog->next;
+ if (si->iType != GCW_CHATROOM || !si->bFilterEnabled || (si->iLogFilterFlags&pLog->iType) != 0)
+ index++;
+ }
+ Log_StreamInEvent(hwndDlg, pLog, si, TRUE, FALSE);
+ mir_forkthread(phase2, si);
+ } else Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE, FALSE);
+ } else SendMessage(hwndDlg, GC_EVENT_CONTROL + WM_USER + 500, WINDOW_CLEARLOG, 0);
+ break;
+
+ case GC_REDRAWLOG2:
+ si->LastTime = 0;
+ if (si->pLog)
+ Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE, FALSE);
+ break;
+
+ case GC_REDRAWLOG3:
+ si->LastTime = 0;
+ if (si->pLog)
+ Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE, TRUE);
+ break;
+
+ case GC_ADDLOG: {
+ BOOL fInactive = (GetForegroundWindow() != dat->pContainer->hwnd || GetActiveWindow() != dat->pContainer->hwnd);
+
+ if (g_Settings.UseDividers && g_Settings.DividersUsePopupConfig) {
+ if (!MessageWindowOpened(0, (LPARAM)hwndDlg))
+ SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0);
+ } else if (g_Settings.UseDividers) {
+ if (fInactive)
+ SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0);
+ else {
+ if (dat->pContainer->hwndActive != hwndDlg)
+ SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0);
+ }
+ }
+
+ if (si->pLogEnd)
+ Log_StreamInEvent(hwndDlg, si->pLog, si, FALSE, FALSE);
+ else
+ SendMessage(hwndDlg, GC_EVENT_CONTROL + WM_USER + 500, WINDOW_CLEARLOG, 0);
+ break;
+ }
+
+ case GC_ACKMESSAGE:
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETREADONLY, FALSE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, WM_SETTEXT, 0, (LPARAM)_T(""));
+ return TRUE;
+
+ case WM_CTLCOLORLISTBOX:
+ SetBkColor((HDC) wParam, g_Settings.crUserListBGColor);
+ return (INT_PTR) hListBkgBrush;
+
+ case WM_MEASUREITEM: {
+ MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *) lParam;
+
+ if (mis->CtlType == ODT_MENU) {
+ if(dat->Panel->isHovered()) {
+ mis->itemHeight = 0;
+ mis->itemWidth = 6;
+ return(TRUE);
+ }
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+ }
+ else
+ mis->itemHeight = g_Settings.iNickListFontHeight;
+ return TRUE;
+ }
+
+ case WM_DRAWITEM: {
+ DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *) lParam;
+
+ if (dis->CtlType == ODT_MENU) {
+ if(dat->Panel->isHovered()) {
+ DrawMenuItem(dis, (HICON)dis->itemData, 0);
+ return(TRUE);
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+ }
+ else {
+ if (dis->CtlID == IDC_LIST) {
+ HFONT hFont, hOldFont;
+ HICON hIcon;
+ int offset, x_offset = 0;
+ int height;
+ int index = dis->itemID;
+ USERINFO * ui = UM_FindUserFromIndex(si->pUsers, index);
+ char szIndicator = 0;
+
+ if (ui) {
+ height = dis->rcItem.bottom - dis->rcItem.top;
+
+ if (height&1)
+ height++;
+ if (height == 10)
+ offset = 0;
+ else
+ offset = height / 2;
+ hIcon = SM_GetStatusIcon(si, ui, &szIndicator);
+ hFont = (ui->iStatusEx == 0) ? g_Settings.UserListFont : g_Settings.UserListHeadingsFont;
+ hOldFont = (HFONT) SelectObject(dis->hDC, hFont);
+ SetBkMode(dis->hDC, TRANSPARENT);
+
+ if (dis->itemState & ODS_SELECTED) {
+ FillRect(dis->hDC, &dis->rcItem, g_Settings.SelectionBGBrush);
+ SetTextColor(dis->hDC, g_Settings.nickColors[6]);
+ } else {
+ FillRect(dis->hDC, &dis->rcItem, hListBkgBrush);
+ if (g_Settings.ColorizeNicks && szIndicator != 0) {
+ COLORREF clr;
+
+ switch (szIndicator) {
+ case '@':
+ clr = g_Settings.nickColors[0];
+ break;
+ case '%':
+ clr = g_Settings.nickColors[1];
+ break;
+ case '+':
+ clr = g_Settings.nickColors[2];
+ break;
+ case '!':
+ clr = g_Settings.nickColors[3];
+ break;
+ case '*':
+ clr = g_Settings.nickColors[4];
+ break;
+ }
+ SetTextColor(dis->hDC, clr);
+ } else SetTextColor(dis->hDC, ui->iStatusEx == 0 ? g_Settings.crUserListColor : g_Settings.crUserListHeadingsColor);
+ }
+ x_offset = 2;
+
+ if (g_Settings.ShowContactStatus && g_Settings.ContactStatusFirst && ui->ContactStatus) {
+ HICON hIcon = LoadSkinnedProtoIcon(si->pszModule, ui->ContactStatus);
+ DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 8, hIcon, 16, 16, 0, NULL, DI_NORMAL);
+ CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0);
+ x_offset += 18;
+ }
+
+ if (g_Settings.ClassicIndicators) {
+ char szTemp[3];
+ SIZE szUmode;
+
+ szTemp[1] = 0;
+ szTemp[0] = szIndicator;
+ if (szTemp[0]) {
+ GetTextExtentPoint32A(dis->hDC, szTemp, 1, &szUmode);
+ TextOutA(dis->hDC, x_offset, dis->rcItem.top, szTemp, 1);
+ x_offset += szUmode.cx + 2;
+ } else x_offset += 8;
+ } else {
+ DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 5, hIcon, 10, 10, 0, NULL, DI_NORMAL);
+ x_offset += 12;
+ }
+
+ if (g_Settings.ShowContactStatus && !g_Settings.ContactStatusFirst && ui->ContactStatus) {
+ HICON hIcon = LoadSkinnedProtoIcon(si->pszModule, ui->ContactStatus);
+ DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 8, hIcon, 16, 16, 0, NULL, DI_NORMAL);
+ CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0);
+ x_offset += 18;
+ }
+
+ {
+ SIZE sz;
+
+ if (si->iSearchItem != -1 && si->iSearchItem == index && si->szSearch[0]) {
+ COLORREF clr_orig = GetTextColor(dis->hDC);
+ GetTextExtentPoint32(dis->hDC, ui->pszNick, lstrlen(si->szSearch), &sz);
+ SetTextColor(dis->hDC, RGB(250, 250, 0));
+ TextOut(dis->hDC, x_offset, (dis->rcItem.top + dis->rcItem.bottom - sz.cy) / 2, ui->pszNick, lstrlen(si->szSearch));
+ SetTextColor(dis->hDC, clr_orig);
+ x_offset += sz.cx;
+ TextOut(dis->hDC, x_offset, (dis->rcItem.top + dis->rcItem.bottom - sz.cy) / 2, ui->pszNick + lstrlen(si->szSearch), lstrlen(ui->pszNick) - lstrlen(si->szSearch));
+ } else {
+ GetTextExtentPoint32(dis->hDC, ui->pszNick, lstrlen(ui->pszNick), &sz);
+ TextOut(dis->hDC, x_offset, (dis->rcItem.top + dis->rcItem.bottom - sz.cy) / 2, ui->pszNick, lstrlen(ui->pszNick));
+ SelectObject(dis->hDC, hOldFont);
+ }
+ }
+ }
+ return TRUE;
+ }
+ }
+ }
+ break;
+ case WM_CONTEXTMENU:{
+ //mad
+ DWORD idFrom=GetDlgCtrlID((HWND)wParam);
+ if(idFrom>=MIN_CBUTTONID&&idFrom<=MAX_CBUTTONID)
+ BB_CustomButtonClick(dat,idFrom,(HWND) wParam,1);
+ }break;
+ //
+ case GC_UPDATENICKLIST: {
+ int i = SendMessage(GetDlgItem(hwndDlg, IDC_LIST), LB_GETTOPINDEX, 0, 0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_LIST), LB_SETCOUNT, si->nUsersInNicklist, 0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_LIST), LB_SETTOPINDEX, i, 0);
+ SendMessage(hwndDlg, GC_UPDATETITLE, 0, 0);
+ }
+ break;
+
+ case GC_EVENT_CONTROL + WM_USER + 500: {
+ switch (wParam) {
+ case SESSION_OFFLINE:
+ SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
+ SendMessage(si->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0);
+ return TRUE;
+
+ case SESSION_ONLINE:
+ SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
+ return TRUE;
+
+ case WINDOW_HIDDEN:
+ SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, 1);
+ return TRUE;
+
+ case WINDOW_CLEARLOG:
+ SetDlgItemText(hwndDlg, IDC_CHAT_LOG, _T(""));
+ return TRUE;
+
+ case SESSION_TERMINATE:
+ if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->hContact, (LPARAM)0))
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->hContact, (LPARAM)szChatIconString);
+
+ si->wState &= ~STATE_TALK;
+ dat->bWasDeleted = 1;
+ DBWriteContactSettingWord(si->hContact, si->pszModule , "ApparentMode", (LPARAM) 0);
+ SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, lParam == 2 ? lParam : 1);
+ return TRUE;
+
+ case WINDOW_MINIMIZE:
+ ShowWindow(hwndDlg, SW_MINIMIZE);
+ goto LABEL_SHOWWINDOW;
+
+ case WINDOW_MAXIMIZE:
+ ShowWindow(hwndDlg, SW_MAXIMIZE);
+ goto LABEL_SHOWWINDOW;
+
+ case SESSION_INITDONE:
+ if (M->GetByte("Chat", "PopupOnJoin", 0) != 0)
+ return TRUE;
+ // fall through
+ case WINDOW_VISIBLE:
+ if (IsIconic(hwndDlg))
+ ShowWindow(hwndDlg, SW_NORMAL);
+LABEL_SHOWWINDOW:
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ SendMessage(hwndDlg, GC_REDRAWLOG, 0, 0);
+ SendMessage(hwndDlg, GC_UPDATENICKLIST, 0, 0);
+ SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
+ ShowWindow(hwndDlg, SW_SHOW);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ SetForegroundWindow(hwndDlg);
+ return TRUE;
+ }
+ }
+ break;
+
+ case DM_SPLITTERMOVED: {
+ POINT pt;
+ RECT rc;
+ RECT rcLog;
+ BOOL bFormat = TRUE; //IsWindowVisible(GetDlgItem(hwndDlg,IDC_SMILEY));
+
+ static int x = 0;
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_LOG), &rcLog);
+ if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SPLITTERX)) {
+ int oldSplitterX;
+ GetClientRect(hwndDlg, &rc);
+ pt.x = wParam;
+ pt.y = 0;
+ ScreenToClient(hwndDlg, &pt);
+
+ oldSplitterX = si->iSplitterX;
+ si->iSplitterX = rc.right - pt.x + 1;
+ if (si->iSplitterX < 35)
+ si->iSplitterX = 35;
+ if (si->iSplitterX > rc.right - rc.left - 35)
+ si->iSplitterX = rc.right - rc.left - 35;
+ g_Settings.iSplitterX = si->iSplitterX;
+ SendMessage(dat->hwnd, WM_SIZE, 0, 0);
+ } else if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SPLITTERY) || lParam == -1) {
+ int oldSplitterY;
+ GetClientRect(hwndDlg, &rc);
+ rc.top += (dat->Panel->isActive() ? dat->Panel->getHeight() + 40 : 30);
+ pt.x = 0;
+ pt.y = wParam;
+ ScreenToClient(hwndDlg, &pt);
+
+ oldSplitterY = si->iSplitterY;
+ si->iSplitterY = bFormat ? rc.bottom - pt.y + DPISCALEY_S(1) : rc.bottom - pt.y + DPISCALEY_S(20);
+ if (si->iSplitterY < DPISCALEY_S(23))
+ si->iSplitterY = DPISCALEY_S(23);
+ if (si->iSplitterY > rc.bottom - rc.top - DPISCALEY_S(40))
+ si->iSplitterY = rc.bottom - rc.top - DPISCALEY_S(40);
+ g_Settings.iSplitterY = si->iSplitterY;
+ CSkin::UpdateToolbarBG(dat, RDW_ALLCHILDREN);
+ SendMessage(dat->hwnd, WM_SIZE, 0, 0);
+ } else if ((HWND) lParam == GetDlgItem(hwndDlg, IDC_PANELSPLITTER)) {
+ RECT rc;
+ POINT pt;
+ pt.x = 0;
+ pt.y = wParam;
+ ScreenToClient(hwndDlg, &pt);
+ GetClientRect(GetDlgItem(hwndDlg, IDC_CHAT_LOG), &rc);
+ if ((pt.y + 2 >= MIN_PANELHEIGHT + 2) && (pt.y + 2 < 100) && (pt.y + 2 < rc.bottom - 30))
+ dat->Panel->setHeight(pt.y + 2);
+ dat->panelWidth = -1;
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
+ if(M->isAero())
+ InvalidateRect(GetParent(hwndDlg), NULL, FALSE);
+ SendMessage(hwndDlg, WM_SIZE, DM_SPLITTERMOVED, 0);
+ break;
+ }
+ }
+ break;
+
+ case GC_FIREHOOK:
+ if (lParam) {
+ GCHOOK* gch = (GCHOOK *) lParam;
+ NotifyEventHooks(hSendEvent, 0, (WPARAM)gch);
+ if (gch->pDest) {
+ mir_free(gch->pDest->pszID);
+ mir_free(gch->pDest->pszModule);
+ mir_free(gch->pDest);
+ }
+ mir_free(gch->ptszText);
+ mir_free(gch->ptszUID);
+ mir_free(gch);
+ }
+ break;
+
+ case GC_CHANGEFILTERFLAG:
+ if (si->iLogFilterFlags == 0 && si->bFilterEnabled)
+ SendMessage(hwndDlg, WM_COMMAND, IDC_FILTER, 0);
+ break;
+
+ case GC_SHOWFILTERMENU: {
+ RECT rcFilter, rcLog;
+ POINT pt;
+
+ si->hwndFilter = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_FILTER), dat->pContainer->hwnd, FilterWndProc, (LPARAM)si);
+ TranslateDialogDefault(si->hwndFilter);
+
+ GetClientRect(si->hwndFilter, &rcFilter);
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_LOG), &rcLog);
+ pt.x = rcLog.right;
+ pt.y = rcLog.bottom;
+ ScreenToClient(dat->pContainer->hwnd, &pt);
+
+ SetWindowPos(si->hwndFilter, HWND_TOP, pt.x - rcFilter.right, pt.y - rcFilter.bottom, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
+ }
+ break;
+
+ case DM_SPLITTERGLOBALEVENT: {
+ DM_SplitterGlobalEvent(dat, wParam, lParam);
+ return(0);
+ }
+
+ case GC_SHOWCOLORCHOOSER: {
+ HWND ColorWindow;
+ RECT rc;
+ BOOL bFG = lParam == IDC_COLOR ? TRUE : FALSE;
+ COLORCHOOSER *pCC = (COLORCHOOSER *)mir_alloc(sizeof(COLORCHOOSER));
+
+ GetWindowRect(GetDlgItem(hwndDlg, bFG ? IDC_COLOR : IDC_BKGCOLOR), &rc);
+ pCC->hWndTarget = GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE);
+ pCC->pModule = MM_FindModule(si->pszModule);
+ pCC->xPosition = rc.left + 3;
+ pCC->yPosition = IsWindowVisible(GetDlgItem(hwndDlg, IDC_COLOR)) ? rc.top - 1 : rc.top + 20;
+ pCC->bForeground = bFG;
+ pCC->si = si;
+
+ ColorWindow = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_COLORCHOOSER), hwndDlg, DlgProcColorToolWindow, (LPARAM) pCC);
+ }
+ break;
+
+ case GC_SCROLLTOBOTTOM: {
+ return(DM_ScrollToBottom(dat, wParam, lParam));
+ }
+
+ case WM_TIMER:
+ if (wParam == TIMERID_FLASHWND)
+ if (dat->mayFlashTab)
+ FlashTab(dat, hwndTab, dat->iTabID, &dat->bTabFlash, TRUE, dat->hTabIcon);
+ break;
+
+ case WM_ACTIVATE:
+ if (LOWORD(wParam) != WA_ACTIVE) {
+ dat->pContainer->hwndSaved = 0;
+ break;
+ }
+
+ //fall through
+ case WM_MOUSEACTIVATE:
+ Chat_UpdateWindowState(dat, WM_ACTIVATE);
+ return 1;
+
+ case WM_NOTIFY: {
+ LPNMHDR pNmhdr = (LPNMHDR)lParam;
+ switch (pNmhdr->code) {
+ case EN_MSGFILTER: {
+ UINT msg = ((MSGFILTER *) lParam)->msg;
+ WPARAM wp = ((MSGFILTER *) lParam)->wParam;
+ LPARAM lp = ((MSGFILTER *) lParam)->lParam;
+
+ BOOL isShift, isCtrl, isMenu;
+ KbdState(dat, isShift, isCtrl, isMenu);
+
+ MSG message;
+ message.hwnd = hwndDlg;
+ message.message = msg;
+ message.lParam = lp;
+ message.wParam = wp;
+
+ if(msg == WM_SYSKEYUP) {
+ if(wp == VK_MENU) {
+ if(!dat->fkeyProcessed && !(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000) && !(lp & (1 << 24)))
+ dat->pContainer->MenuBar->autoShow();
+ }
+ return(_dlgReturn(hwndDlg, 0));
+ }
+
+ if(msg == WM_MOUSEMOVE) {
+ POINT pt;
+ GetCursorPos(&pt);
+ DM_DismissTip(dat, pt);
+ dat->Panel->trackMouse(pt);
+ break;
+ }
+ if(msg == WM_KEYDOWN) {
+ if ((wp == VK_INSERT && isShift && !isCtrl && !isMenu) || (wp == 'V' && !isShift && !isMenu && isCtrl)) {
+ SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), EM_PASTESPECIAL, CF_TEXTT, 0);
+ ((MSGFILTER *) lParam)->msg = WM_NULL;
+ ((MSGFILTER *) lParam)->wParam = 0;
+ ((MSGFILTER *) lParam)->lParam = 0;
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ }
+
+ if(msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN)
+ dat->pContainer->MenuBar->Cancel();
+
+ if ((msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) && !(GetKeyState(VK_RMENU) & 0x8000)) {
+
+ if(DM_GenericHotkeysCheck(&message, dat)) {
+ dat->fkeyProcessed = true;
+ return(_dlgReturn(hwndDlg, 1));
+ }
+
+ LRESULT mim_hotkey_check = CallService(MS_HOTKEY_CHECK, (WPARAM)&message, (LPARAM)(TABSRMM_HK_SECTION_GC));
+ if(mim_hotkey_check)
+ dat->fkeyProcessed = true;
+ switch(mim_hotkey_check) { // nothing (yet) FIXME
+ case TABSRMM_HK_CHANNELMGR:
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_CHANMGR, BN_CLICKED), 0);
+ return(_dlgReturn(hwndDlg, 1));
+ case TABSRMM_HK_FILTERTOGGLE:
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_FILTER, BN_CLICKED), 0);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_FILTER), NULL, TRUE);
+ return(_dlgReturn(hwndDlg, 1));
+ case TABSRMM_HK_LISTTOGGLE:
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_SHOWNICKLIST, BN_CLICKED), 0);
+ return(_dlgReturn(hwndDlg, 1));
+ case TABSRMM_HK_MUC_SHOWSERVER:
+ if(si->iType != GCW_SERVER)
+ DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_MESSAGE, NULL, L"/servershow", (LPARAM)NULL);
+ return(_dlgReturn(hwndDlg, 1));
+ default:
+ break;
+ }
+ }
+
+ if(msg == WM_KEYDOWN && wp == VK_TAB) {
+ if(((NMHDR *)lParam)->idFrom == IDC_CHAT_LOG) {
+ SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE));
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ }
+
+ if (pNmhdr->idFrom == IDC_CHAT_LOG && ((MSGFILTER *) lParam)->msg == WM_RBUTTONUP) {
+ CHARRANGE sel, all = { 0, -1 };
+ POINT pt;
+ UINT uID = 0;
+ HMENU hMenu = 0;
+ TCHAR pszWord[4096];
+ int pos;
+
+ pt.x = (short) LOWORD(((ENLINK *) lParam)->lParam);
+ pt.y = (short) HIWORD(((ENLINK *) lParam)->lParam);
+ ClientToScreen(pNmhdr->hwndFrom, &pt);
+
+ { // fixing stuff for searches
+ long iCharIndex, iLineIndex, iChars, start, end, iRes;
+ POINTL ptl;
+
+ pszWord[0] = '\0';
+ ptl.x = (LONG)pt.x;
+ ptl.y = (LONG)pt.y;
+ ScreenToClient(GetDlgItem(hwndDlg, IDC_CHAT_LOG), (LPPOINT)&ptl);
+ iCharIndex = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_CHARFROMPOS, 0, (LPARAM) & ptl);
+ if (iCharIndex < 0)
+ break;
+ iLineIndex = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_EXLINEFROMCHAR, 0, (LPARAM)iCharIndex);
+ iChars = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_LINEINDEX, (WPARAM)iLineIndex, 0);
+ start = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_FINDWORDBREAK, WB_LEFT, iCharIndex);//-iChars;
+ end = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_FINDWORDBREAK, WB_RIGHT, iCharIndex);//-iChars;
+
+ if (end - start > 0) {
+ TEXTRANGE tr;
+ CHARRANGE cr;
+ static char szTrimString[] = ":;,.!?\'\"><()[]- \r\n";
+ ZeroMemory(&tr, sizeof(TEXTRANGE));
+
+ cr.cpMin = start;
+ cr.cpMax = end;
+ tr.chrg = cr;
+ tr.lpstrText = (TCHAR *)pszWord;
+ iRes = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_GETTEXTRANGE, 0, (LPARAM) & tr);
+
+ if (iRes > 0) {
+ int iLen = lstrlen(pszWord) - 1;
+ while (iLen >= 0 && strchr(szTrimString, pszWord[iLen])) {
+ pszWord[iLen] = '\0';
+ iLen--;
+ }
+ }
+ }
+ }
+
+ uID = CreateGCMenu(hwndDlg, &hMenu, 1, pt, si, NULL, pszWord);
+
+ if ((uID > 800 && uID < 1400) || uID == CP_UTF8 || uID == 20866) {
+ dat->codePage = uID;
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "ANSIcodepage", dat->codePage);
+ } else if (uID == 500) {
+ dat->codePage = CP_ACP;
+ DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "ANSIcodepage");
+ } else {
+ switch (uID) {
+ case 0:
+ PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+ break;
+
+ case ID_COPYALL:
+ SendMessage(pNmhdr->hwndFrom, EM_EXGETSEL, 0, (LPARAM) & sel);
+ SendMessage(pNmhdr->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & all);
+ SendMessage(pNmhdr->hwndFrom, WM_COPY, 0, 0);
+ SendMessage(pNmhdr->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & sel);
+ PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+ break;
+
+ case ID_CLEARLOG:
+ ClearLog(dat);
+ break;
+
+ case ID_SEARCH_GOOGLE: {
+ char szURL[4096];
+ if (pszWord[0]) {
+ mir_snprintf(szURL, sizeof(szURL), "http://www.google.com/search?q=" TCHAR_STR_PARAM, pszWord);
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM) szURL);
+ }
+ PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+ }
+ break;
+
+ case ID_SEARCH_WIKIPEDIA: {
+ char szURL[4096];
+ if (pszWord[0]) {
+ mir_snprintf(szURL, sizeof(szURL), "http://en.wikipedia.org/wiki/" TCHAR_STR_PARAM, pszWord);
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM) szURL);
+ }
+ PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+ }
+ break;
+
+ default:
+ PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+ DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_LOGMENU, NULL, NULL, (LPARAM)uID);
+ break;
+ }
+ }
+ if (si->iType != GCW_SERVER && !(si->dwFlags & GC_UNICODE)) {
+ pos = GetMenuItemCount(hMenu);
+ RemoveMenu(hMenu, pos - 1, MF_BYPOSITION);
+ RemoveMenu(PluginConfig.g_hMenuEncoding, 1, MF_BYPOSITION);
+ }
+ DestroyGCMenu(&hMenu, 5);
+ }
+ break;
+ }
+
+ case EN_REQUESTRESIZE: {
+ if(pNmhdr->idFrom == IDC_CHAT_MESSAGE) {
+ REQRESIZE *rr = (REQRESIZE *)lParam;
+ DM_HandleAutoSizeRequest(dat, rr);
+ }
+ break;
+ }
+
+ case EN_LINK:
+ if (pNmhdr->idFrom == IDC_CHAT_LOG) {
+ switch (((ENLINK *) lParam)->msg) {
+ case WM_SETCURSOR:
+
+ if (g_Settings.ClickableNicks) {
+ if (!hCurHyperlinkHand)
+ hCurHyperlinkHand = LoadCursor(NULL, IDC_HAND);
+ if (hCurHyperlinkHand != GetCursor())
+ SetCursor(hCurHyperlinkHand);
+ return TRUE;
+ }
+ break;
+
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_LBUTTONDBLCLK: {
+ TEXTRANGE tr;
+ CHARRANGE sel;
+ BOOL isLink = FALSE;
+ UINT msg = ((ENLINK *) lParam)->msg;
+
+ dat->pContainer->MenuBar->Cancel();
+
+ tr.lpstrText = NULL;
+ SendMessage(pNmhdr->hwndFrom, EM_EXGETSEL, 0, (LPARAM) & sel);
+ if (sel.cpMin != sel.cpMax)
+ break;
+ tr.chrg = ((ENLINK *) lParam)->chrg;
+ tr.lpstrText = (TCHAR *)mir_alloc(sizeof(TCHAR) * (tr.chrg.cpMax - tr.chrg.cpMin + 2));
+ SendMessage(pNmhdr->hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM) & tr);
+
+ isLink = IsStringValidLink(tr.lpstrText);
+
+ if (isLink) {
+ char* pszUrl = t2a(tr.lpstrText, 0);
+ if (((ENLINK *) lParam)->msg == WM_RBUTTONDOWN) {
+ HMENU hSubMenu;
+ POINT pt;
+
+ hSubMenu = GetSubMenu(g_hMenu, 2);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hSubMenu, 0);
+ pt.x = (short) LOWORD(((ENLINK *) lParam)->lParam);
+ pt.y = (short) HIWORD(((ENLINK *) lParam)->lParam);
+ ClientToScreen(((NMHDR *) lParam)->hwndFrom, &pt);
+ switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL)) {
+ case ID_NEW:
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM) pszUrl);
+ break;
+ case ID_CURR:
+ CallService(MS_UTILS_OPENURL, 0, (LPARAM) pszUrl);
+ break;
+ case ID_COPY: {
+ HGLOBAL hData;
+ if (!OpenClipboard(hwndDlg))
+ break;
+ EmptyClipboard();
+ hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(TCHAR) * (lstrlen(tr.lpstrText) + 1));
+ lstrcpy((TCHAR*)GlobalLock(hData), tr.lpstrText);
+ GlobalUnlock(hData);
+ SetClipboardData(CF_UNICODETEXT, hData);
+ }
+ CloseClipboard();
+ SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE));
+ break;
+ }
+ mir_free(tr.lpstrText);
+ mir_free(pszUrl);
+ return TRUE;
+ } else if (((ENLINK *) lParam)->msg == WM_LBUTTONUP) {
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM) pszUrl);
+ SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE));
+ mir_free(tr.lpstrText);
+ mir_free(pszUrl);
+ return TRUE;
+ }
+ } else if (g_Settings.ClickableNicks) { // clicked a nick name
+ CHARRANGE chr;
+ TEXTRANGE tr2;
+ TCHAR tszAplTmpl[] = _T("%s:"),
+ *tszAppeal, *tszTmp;
+ size_t st;
+
+ if (msg == WM_RBUTTONDOWN) {
+ USERINFO *ui = si->pUsers;
+ HMENU hMenu = 0;
+ USERINFO uiNew;
+ while (ui) {
+ if (!lstrcmp(ui->pszNick, tr.lpstrText)) {
+ POINT pt;
+ UINT uID;
+
+ pt.x = (short) LOWORD(((ENLINK *) lParam)->lParam);
+ pt.y = (short) HIWORD(((ENLINK *) lParam)->lParam);
+ ClientToScreen(((NMHDR *) lParam)->hwndFrom, &pt);
+ CopyMemory(&uiNew, ui, sizeof(USERINFO));
+ uID = CreateGCMenu(hwndDlg, &hMenu, 0, pt, si, uiNew.pszUID, NULL);
+ switch (uID) {
+ case 0:
+ break;
+
+ case ID_MESS:
+ DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_PRIVMESS, ui->pszUID, NULL, (LPARAM)NULL);
+ break;
+
+ default:
+ DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_NICKLISTMENU, ui->pszUID, NULL, (LPARAM)uID);
+ break;
+ }
+ DestroyGCMenu(&hMenu, 1);
+ return TRUE;
+ }
+ ui = ui->next;
+ }
+ return TRUE;
+ }
+ else if (msg == WM_LBUTTONUP) {
+ USERINFO *ui = si->pUsers;
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_EXGETSEL, 0, (LPARAM) &chr);
+ tszTmp = tszAppeal = (TCHAR *) malloc((lstrlen(tr.lpstrText) + lstrlen(tszAplTmpl) + 3) * sizeof(TCHAR));
+ tr2.lpstrText = (LPTSTR) malloc(sizeof(TCHAR) * 2);
+ if (chr.cpMin) {
+ /* prepend nick with space if needed */
+ tr2.chrg.cpMin = chr.cpMin - 1;
+ tr2.chrg.cpMax = chr.cpMin;
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_GETTEXTRANGE, 0, (LPARAM) &tr2);
+ if (! _istspace(*tr2.lpstrText))
+ *tszTmp++ = _T(' ');
+ _tcscpy(tszTmp, tr.lpstrText);
+ }
+ else
+ /* in the beginning of the message window */
+ _stprintf(tszAppeal, tszAplTmpl, tr.lpstrText);
+ st = lstrlen(tszAppeal);
+ if (chr.cpMax != -1) {
+ tr2.chrg.cpMin = chr.cpMax;
+ tr2.chrg.cpMax = chr.cpMax + 1;
+ /* if there is no space after selection,
+ or there is nothing after selection at all... */
+ if (! SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_GETTEXTRANGE, 0, (LPARAM) &tr2) || ! _istspace(*tr2.lpstrText)) {
+ tszAppeal[st++] = _T(' ');
+ tszAppeal[st++] = _T('\0');
+ }
+ }
+ else {
+ tszAppeal[st++] = _T(' ');
+ tszAppeal[st++] = _T('\0');
+ }
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_REPLACESEL, FALSE, (LPARAM)tszAppeal);
+ free((void *) tr2.lpstrText);
+ free((void *) tszAppeal);
+ }
+ }
+ SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE));
+ mir_free(tr.lpstrText);
+ return TRUE;
+ }
+ }
+ return TRUE;
+ }
+ return TRUE;
+ }
+ }
+ break;
+
+ case WM_LBUTTONDOWN: {
+ POINT tmp; //+ Protogenes
+ POINTS cur; //+ Protogenes
+ GetCursorPos(&tmp); //+ Protogenes
+ if(!dat->Panel->isHovered()) {
+ cur.x = (SHORT)tmp.x; //+ Protogenes
+ cur.y = (SHORT)tmp.y; //+ Protogenes
+ SendMessage(dat->pContainer->hwnd, WM_NCLBUTTONDOWN, HTCAPTION, *((LPARAM*)(&cur))); //+ Protogenes
+ }
+ break;
+ }
+
+ case WM_LBUTTONUP: {
+ POINT tmp; //+ Protogenes
+ POINTS cur; //+ Protogenes
+ GetCursorPos(&tmp); //+ Protogenes
+ if(dat->Panel->isHovered())
+ dat->Panel->handleClick(tmp);
+ else {
+ cur.x = (SHORT)tmp.x; //+ Protogenes
+ cur.y = (SHORT)tmp.y; //+ Protogenes
+ SendMessage(dat->pContainer->hwnd, WM_NCLBUTTONUP, HTCAPTION, *((LPARAM*)(&cur))); //+ Protogenes
+ }
+ break;
+ }
+
+ case WM_MOUSEMOVE: {
+ POINT pt;
+ GetCursorPos(&pt);
+ DM_DismissTip(dat, pt);
+ dat->Panel->trackMouse(pt);
+ break;
+ }
+ case WM_APPCOMMAND: {
+ DWORD cmd = GET_APPCOMMAND_LPARAM(lParam);
+ if (cmd == APPCOMMAND_BROWSER_BACKWARD || cmd == APPCOMMAND_BROWSER_FORWARD) {
+ SendMessage(dat->pContainer->hwnd, DM_SELECTTAB, cmd == APPCOMMAND_BROWSER_BACKWARD ? DM_SELECT_PREV : DM_SELECT_NEXT, 0);
+ return 1;
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ //mad
+ if(LOWORD(wParam)>=MIN_CBUTTONID&&LOWORD(wParam)<=MAX_CBUTTONID){
+ BB_CustomButtonClick(dat,LOWORD(wParam) ,GetDlgItem(hwndDlg,LOWORD(wParam)),0);
+ break;
+ }
+ //
+ switch (LOWORD(wParam)) {
+ case IDC_LIST:
+ if (HIWORD(wParam) == LBN_DBLCLK) {
+ TVHITTESTINFO hti;
+ int item;
+ USERINFO * ui;
+
+ hti.pt.x = (short)LOWORD(GetMessagePos());
+ hti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(GetDlgItem(hwndDlg, IDC_LIST), &hti.pt);
+
+ item = LOWORD(SendMessage(GetDlgItem(hwndDlg, IDC_LIST), LB_ITEMFROMPOINT, 0, MAKELPARAM(hti.pt.x, hti.pt.y)));
+ ui = UM_FindUserFromIndex(si->pUsers, item);
+ //ui = SM_GetUserFromIndex(si->pszID, si->pszModule, item);
+ if (ui) {
+ if (g_Settings.DoubleClick4Privat ? GetKeyState(VK_SHIFT) & 0x8000 : !(GetKeyState(VK_SHIFT) & 0x8000)) {
+ LRESULT lResult = (LRESULT)SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), EM_GETSEL, (WPARAM)NULL, (LPARAM)NULL);
+ int start = LOWORD(lResult);
+ TCHAR* pszName = (TCHAR*)alloca(sizeof(TCHAR) * (lstrlen(ui->pszUID) + 3));
+ if (start == 0)
+ mir_sntprintf(pszName, lstrlen(ui->pszUID) + 3, _T("%s: "), ui->pszUID);
+ else
+ mir_sntprintf(pszName, lstrlen(ui->pszUID) + 2, _T("%s "), ui->pszUID);
+
+ SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), EM_REPLACESEL, FALSE, (LPARAM) pszName);
+ PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+ SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE));
+ } else DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_PRIVMESS, ui->pszUID, NULL, (LPARAM)NULL);
+ }
+
+ return TRUE;
+ } else if (HIWORD(wParam) == LBN_KILLFOCUS)
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_LIST), NULL, NULL, RDW_INVALIDATE);
+ break;
+
+ case IDC_CHAT_TOGGLESIDEBAR:
+ SendMessage(dat->pContainer->hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0);
+ break;
+
+ case IDCANCEL:
+ ShowWindow(dat->pContainer->hwnd, SW_MINIMIZE);
+ return FALSE;
+
+ case IDOK: {
+ char* pszRtf;
+ TCHAR* ptszText/*, *p1*/;
+ MODULEINFO* mi;
+ bool fSound = true;
+
+ if (GetSendButtonState(hwndDlg) == PBS_DISABLED)
+ break;
+
+ mi = MM_FindModule(si->pszModule);
+
+ pszRtf = Chat_Message_GetFromStream(hwndDlg, si);
+ SM_AddCommand(si->ptszID, si->pszModule, pszRtf);
+ ptszText = Chat_DoRtfToTags(pszRtf, si);
+ DoTrimMessage(ptszText);
+
+ if(mi && mi->bAckMsg) {
+ Utils::enableDlgControl(hwndDlg, IDC_CHAT_MESSAGE, FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETREADONLY, TRUE, 0);
+ } else SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, WM_SETTEXT, 0, (LPARAM)_T(""));
+
+ Utils::enableDlgControl(hwndDlg, IDOK, FALSE);
+
+ if(ptszText[0] == '/' || si->iType == GCW_SERVER)
+ fSound = false;
+ DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_MESSAGE, NULL, ptszText, (LPARAM)NULL);
+ mi->idleTimeStamp = time(0);
+ mi->lastIdleCheck = 0;
+ SM_BroadcastMessage(si->pszModule, GC_UPDATESTATUSBAR, 0, 1, TRUE);
+ if (dat && dat->pContainer) {
+ if (fSound && !nen_options.iNoSounds && !(dat->pContainer->dwFlags & CNT_NOSOUND))
+ SkinPlaySound("ChatSent");
+ }
+ mir_free(pszRtf);
+ mir_free(ptszText);
+ SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE));
+ }
+ break;
+
+ case IDC_SHOWNICKLIST:
+ if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_SHOWNICKLIST)))
+ break;
+ if (si->iType == GCW_SERVER)
+ break;
+
+ si->bNicklistEnabled = !si->bNicklistEnabled;
+
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ if (CSkin::m_skinEnabled)
+ InvalidateRect(hwndDlg, NULL, TRUE);
+ PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0);
+ break;
+
+ case IDC_CHAT_MESSAGE:
+ if (g_Settings.MathMod)
+ MTH_updateMathWindow(dat);
+
+ if (HIWORD(wParam) == EN_CHANGE) {
+ if (dat->pContainer->hwndActive == hwndDlg)
+ UpdateReadChars(dat);
+ dat->dwLastActivity = GetTickCount();
+ dat->pContainer->dwLastActivity = dat->dwLastActivity;
+ SendDlgItemMessage(hwndDlg, IDOK, BUTTONSETASFLATBTN + 14, GetRichTextLength(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)) != 0, 0);
+ Utils::enableDlgControl(hwndDlg, IDOK, GetRichTextLength(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)) != 0);
+ }
+ break;
+
+ case IDC_SMILEY:
+ case IDC_SMILEYBTN: {
+ SMADD_SHOWSEL3 smaddInfo = {0};
+ RECT rc;
+
+ if (lParam == 0)
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_SMILEYBTN), &rc);
+ else
+ GetWindowRect((HWND)lParam, &rc);
+ smaddInfo.cbSize = sizeof(SMADD_SHOWSEL3);
+ smaddInfo.hwndTarget = GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE);
+ smaddInfo.targetMessage = EM_REPLACESEL;
+ smaddInfo.targetWParam = TRUE;
+ smaddInfo.Protocolname = si->pszModule;
+ smaddInfo.Direction = 0;
+ smaddInfo.xPosition = rc.left;
+ smaddInfo.yPosition = rc.top + 24;
+ smaddInfo.hContact = si->hContact;
+ smaddInfo.hwndParent = dat->pContainer->hwnd;
+ if (PluginConfig.g_SmileyAddAvail)
+ CallService(MS_SMILEYADD_SHOWSELECTION, 0, (LPARAM) &smaddInfo);
+ }
+ break;
+
+ case IDC_CHAT_HISTORY: {
+ MODULEINFO * pInfo = MM_FindModule(si->pszModule);
+
+ if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_HISTORY)))
+ break;
+
+ if (ServiceExists("MSP/HTMLlog/ViewLog") && strstr(si->pszModule, "IRC")) {
+ char szName[MAX_PATH];
+
+ WideCharToMultiByte(CP_ACP, 0, si->ptszName, -1, szName, MAX_PATH, 0, 0);
+ szName[MAX_PATH - 1] = 0;
+ CallService("MSP/HTMLlog/ViewLog", (WPARAM)si->pszModule, (LPARAM)szName);
+ } else if (pInfo)
+ ShellExecute(hwndDlg, NULL, GetChatLogsFilename(si, 0), NULL, NULL, SW_SHOW);
+ }
+ break;
+
+ case IDC_CHAT_CLOSE:
+ SendMessage(hwndDlg, WM_CLOSE, 0, 1);
+ break;
+
+ case IDC_CHANMGR:
+ if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHANMGR)))
+ break;
+ DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_CHANMGR, NULL, NULL, (LPARAM)NULL);
+ break;
+
+ case IDC_FILTER:
+ if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FILTER)))
+ break;
+
+ if (si->iLogFilterFlags == 0 && !si->bFilterEnabled) {
+ MessageBox(0, CTranslator::get(CTranslator::GEN_MUC_FILTER_ERROR), CTranslator::get(CTranslator::GEN_MUC_FILTER_ERROR_TITLE), MB_OK);
+ si->bFilterEnabled = 0;
+ } else
+ si->bFilterEnabled = !si->bFilterEnabled;
+
+ SendDlgItemMessage(hwndDlg, IDC_FILTER, BUTTONSETOVERLAYICON, 0,
+ (LPARAM)(si->bFilterEnabled ? PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled));
+
+ if (si->bFilterEnabled && M->GetByte("Chat", "RightClickFilter", 0) == 0) {
+ SendMessage(hwndDlg, GC_SHOWFILTERMENU, 0, 0);
+ break;
+ }
+ SendMessage(hwndDlg, GC_REDRAWLOG, 0, 0);
+ SendMessage(hwndDlg, GC_UPDATETITLE, 0, 0);
+ M->WriteByte(si->hContact, "Chat", "FilterEnabled", (BYTE)si->bFilterEnabled);
+ break;
+
+ case IDC_BKGCOLOR: {
+ CHARFORMAT2 cf;
+
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwEffects = 0;
+
+ if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_BKGCOLOR)))
+ break;
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_BKGCOLOR)) {
+ if (M->GetByte("Chat", "RightClickFilter", 0) == 0)
+ SendMessage(hwndDlg, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_BKGCOLOR);
+ else if (si->bBGSet) {
+ cf.dwMask = CFM_BACKCOLOR;
+ cf.crBackColor = MM_FindModule(si->pszModule)->crColors[si->iBG];
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+ } else {
+ cf.dwMask = CFM_BACKCOLOR;
+ cf.crBackColor = (COLORREF)M->GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+ }
+ break;
+
+ case IDC_COLOR: {
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwEffects = 0;
+
+ if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_COLOR)))
+ break;
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_COLOR)) {
+ if (M->GetByte("Chat", "RightClickFilter", 0) == 0)
+ SendMessage(hwndDlg, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_COLOR);
+ else if (si->bFGSet) {
+ cf.dwMask = CFM_COLOR;
+ cf.crTextColor = MM_FindModule(si->pszModule)->crColors[si->iFG];
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+ } else {
+ COLORREF cr;
+
+ LoadLogfont(MSGFONTID_MESSAGEAREA, NULL, &cr, FONTMODULE);
+ cf.dwMask = CFM_COLOR;
+ cf.crTextColor = cr;
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+ }
+ break;
+
+ case IDC_CHAT_BOLD:
+ case IDC_ITALICS:
+ case IDC_CHAT_UNDERLINE: {
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
+ cf.dwEffects = 0;
+
+ if (LOWORD(wParam) == IDC_CHAT_BOLD && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_BOLD)))
+ break;
+ if (LOWORD(wParam) == IDC_ITALICS && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_ITALICS)))
+ break;
+ if (LOWORD(wParam) == IDC_CHAT_UNDERLINE && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_UNDERLINE)))
+ break;
+ if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_BOLD))
+ cf.dwEffects |= CFE_BOLD;
+ if (IsDlgButtonChecked(hwndDlg, IDC_ITALICS))
+ cf.dwEffects |= CFE_ITALIC;
+ if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_UNDERLINE))
+ cf.dwEffects |= CFE_UNDERLINE;
+
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+ }
+ break;
+
+ case WM_KEYDOWN:
+ SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE));
+ break;
+
+ case WM_MOVE:
+ break;
+
+ case WM_ERASEBKGND: {
+ HDC hdc = (HDC)wParam;
+ RECT rcClient, rcWindow, rc;
+ CSkinItem *item;
+ POINT pt;
+ UINT item_ids[3] = {ID_EXTBKUSERLIST, ID_EXTBKHISTORY, ID_EXTBKINPUTAREA};
+ UINT ctl_ids[3] = {IDC_LIST, IDC_CHAT_LOG, IDC_CHAT_MESSAGE};
+ int i;
+ bool fAero = M->isAero();
+ bool fInfoPanel = dat->Panel->isActive();
+ HANDLE hbp = 0;
+ HDC hdcMem = 0;
+ HBITMAP hbm, hbmOld;
+
+ GetClientRect(hwndDlg, &rcClient);
+ LONG cx = rcClient.right - rcClient.left;
+ LONG cy = rcClient.bottom - rcClient.top;
+
+ if(CMimAPI::m_haveBufferedPaint)
+ hbp = CSkin::InitiateBufferedPaint(hdc, rcClient, hdcMem);
+ else {
+ hdcMem = CreateCompatibleDC(hdc);
+ hbm = CSkin::CreateAeroCompatibleBitmap(rcClient, hdc);
+ hbmOld = (HBITMAP)SelectObject(hdcMem, hbm);
+ }
+
+ if(CSkin::m_skinEnabled && !fAero) {
+ CSkin::SkinDrawBG(hwndDlg, dat->pContainer->hwnd, dat->pContainer, &rcClient, hdcMem);
+ for (i = 0; i < 3; i++) {
+ item = &SkinItems[item_ids[i]];
+ if (!item->IGNORED) {
+
+ GetWindowRect(GetDlgItem(hwndDlg, ctl_ids[i]), &rcWindow);
+ pt.x = rcWindow.left;
+ pt.y = rcWindow.top;
+ ScreenToClient(hwndDlg, &pt);
+ rc.left = pt.x - item->MARGIN_LEFT;
+ rc.top = pt.y - item->MARGIN_TOP;
+ rc.right = rc.left + item->MARGIN_RIGHT + (rcWindow.right - rcWindow.left) + item->MARGIN_LEFT;
+ rc.bottom = rc.top + item->MARGIN_BOTTOM + (rcWindow.bottom - rcWindow.top) + item->MARGIN_TOP;
+ CSkin::DrawItem(hdcMem, &rc, item);
+ }
+ }
+ }
+ else {
+ CSkin::FillBack(hdcMem, &rcClient);
+
+ if(M->isAero()) {
+ LONG temp = rcClient.bottom;
+ rcClient.bottom = dat->Panel->isActive() ? dat->Panel->getHeight() + 5 : 5;
+ FillRect(hdcMem, &rcClient, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ rcClient.bottom = temp;
+ }
+ }
+
+ GetClientRect(hwndDlg, &rc);
+ dat->Panel->renderBG(hdcMem, rc, &SkinItems[ID_EXTBKINFOPANELBG], fAero);
+
+
+ dat->Panel->renderContent(hdcMem);
+
+ if(!CSkin::m_skinEnabled)
+ CSkin::RenderToolbarBG(dat, hdcMem, rcClient);
+
+ if(hbp)
+ CSkin::FinalizeBufferedPaint(hbp, &rcClient);
+ else {
+ BitBlt(hdc, 0, 0, cx, cy, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hbmOld);
+ DeleteObject(hbm);
+ DeleteDC(hdcMem);
+ }
+ if(!dat->fLimitedUpdate)
+ SetAeroMargins(dat->pContainer);
+ return(1);
+ }
+
+ case WM_NCPAINT:
+ if (CSkin::m_skinEnabled)
+ return 0;
+ break;
+ case WM_PAINT: {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwndDlg, &ps);
+ EndPaint(hwndDlg, &ps);
+ return 0;
+ }
+
+ case DM_SETINFOPANEL:
+ CInfoPanel::setPanelHandler(dat, wParam, lParam);
+ return(0);
+
+ case DM_INVALIDATEPANEL:
+ if(dat->Panel)
+ dat->Panel->Invalidate(true);
+ return(0);
+
+ case WM_RBUTTONUP: {
+ POINT pt;
+ int iSelection;
+ HMENU subMenu;
+ int isHandled;
+ int menuID = 0;
+
+ GetCursorPos(&pt);
+
+ if(dat->Panel->invokeConfigDialog(pt))
+ break;
+
+ subMenu = GetSubMenu(dat->pContainer->hMenuContext, 0);
+
+ MsgWindowUpdateMenu(dat, subMenu, MENU_TABCONTEXT);
+
+ iSelection = TrackPopupMenu(subMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL);
+ if (iSelection >= IDM_CONTAINERMENU) {
+ DBVARIANT dbv = {0};
+ char szIndex[10];
+ char *szKey = "TAB_ContainersW";
+ _snprintf(szIndex, 8, "%d", iSelection - IDM_CONTAINERMENU);
+ if (iSelection - IDM_CONTAINERMENU >= 0) {
+ if (!M->GetTString(NULL, szKey, szIndex, &dbv)) {
+ SendMessage(hwndDlg, DM_CONTAINERSELECTED, 0, (LPARAM)dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ break;
+ }
+ isHandled = MsgWindowMenuHandler(dat, iSelection, MENU_TABCONTEXT);
+ break;
+ }
+
+ case WM_LBUTTONDBLCLK: {
+ if (LOWORD(lParam) < 30)
+ PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0);
+ break;
+ }
+
+ case WM_CLOSE:
+ if (wParam == 0 && lParam == 0) {
+ if(PluginConfig.m_EscapeCloses == 1) {
+ SendMessage(dat->pContainer->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+ return(TRUE);
+ } else if(PluginConfig.m_HideOnClose && PluginConfig.m_EscapeCloses == 2) {
+ ShowWindow(dat->pContainer->hwnd, SW_HIDE);
+ return(TRUE);
+ }
+ _dlgReturn(hwndDlg, TRUE);
+ }
+ SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, 1);
+ break;
+
+ case DM_CONTAINERSELECTED: {
+ struct TContainerData *pNewContainer = 0;
+ TCHAR *szNewName = (TCHAR *)lParam;
+ if(!_tcscmp(szNewName, CTranslator::get(CTranslator::GEN_DEFAULT_CONTAINER_NAME)))
+ szNewName = CGlobals::m_default_container_name;
+ int iOldItems = TabCtrl_GetItemCount(hwndTab);
+ if (!_tcsncmp(dat->pContainer->szName, szNewName, CONTAINER_NAMELEN))
+ break;
+ pNewContainer = FindContainerByName(szNewName);
+ if (pNewContainer == NULL)
+ pNewContainer = CreateContainer(szNewName, FALSE, dat->hContact);
+ M->WriteTString(dat->hContact, SRMSGMOD_T, "containerW", szNewName);
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_DOCREATETAB_CHAT, (WPARAM)pNewContainer, (LPARAM)hwndDlg);
+ if (iOldItems > 1) // there were more than 1 tab, container is still valid
+ SendMessage(dat->pContainer->hwndActive, WM_SIZE, 0, 0);
+ SetForegroundWindow(pNewContainer->hwnd);
+ SetActiveWindow(pNewContainer->hwnd);
+ }
+ break;
+ // container API support functions
+
+ case DM_QUERYCONTAINER: {
+ struct TContainerData **pc = (struct TContainerData **) lParam;
+ if (pc)
+ *pc = dat->pContainer;
+ return 0;
+ }
+
+ case DM_QUERYHCONTACT: {
+ HANDLE *phContact = (HANDLE *) lParam;
+ if (phContact)
+ *phContact = dat->hContact;
+ return 0;
+ }
+
+ case GC_CLOSEWINDOW: {
+ int iTabs, i;
+ TCITEM item = {0};
+ RECT rc;
+ struct TContainerData *pContainer = dat->pContainer;
+ BOOL bForced = (lParam == 2);
+
+ iTabs = TabCtrl_GetItemCount(hwndTab);
+ if (iTabs == 1) {
+ if (/*!bForced && */CMimAPI::m_shutDown == 0) {
+ //DestroyWindow(GetParent(GetParent(hwndDlg)));
+ //PostMessage(hwndDlg, WM_CLOSE, 0, 1);
+ SendMessage(GetParent(GetParent(hwndDlg)), WM_CLOSE, 0, 1);
+ return 1;
+ }
+ }
+
+ dat->pContainer->iChilds--;
+ i = GetTabIndexFromHWND(hwndTab, hwndDlg);
+
+ /*
+ * after closing a tab, we need to activate the tab to the left side of
+ * the previously open tab.
+ * normally, this tab has the same index after the deletion of the formerly active tab
+ * unless, of course, we closed the last (rightmost) tab.
+ */
+ if (!dat->pContainer->bDontSmartClose && iTabs > 1 && !bForced) {
+ if (i == iTabs - 1)
+ i--;
+ else
+ i++;
+ TabCtrl_SetCurSel(hwndTab, i);
+ item.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, i, &item); // retrieve dialog hwnd for the now active tab...
+
+ dat->pContainer->hwndActive = (HWND) item.lParam;
+ SendMessage(dat->pContainer->hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc);
+ SetWindowPos(dat->pContainer->hwndActive, HWND_TOP, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), SWP_SHOWWINDOW);
+ ShowWindow((HWND)item.lParam, SW_SHOW);
+ SetForegroundWindow(dat->pContainer->hwndActive);
+ SetFocus(dat->pContainer->hwndActive);
+ SendMessage(dat->pContainer->hwnd, WM_SIZE, 0, 0);
+ }
+ //SM_SetTabbedWindowHwnd(0, 0);
+ //DestroyWindow(hwndDlg);
+ if (iTabs == 1)
+ SendMessage(GetParent(GetParent(hwndDlg)), WM_CLOSE, 0, 1);
+ else {
+ PostMessage(pContainer->hwnd, WM_SIZE, 0, 0);
+ DestroyWindow(hwndDlg);
+ }
+ return 0;
+ }
+
+ case DM_SETLOCALE:
+ if (dat->dwFlags & MWF_WASBACKGROUNDCREATE)
+ break;
+ if (dat->pContainer->hwndActive == hwndDlg && PluginConfig.m_AutoLocaleSupport && dat->hContact != 0 && dat->pContainer->hwnd == GetForegroundWindow() && dat->pContainer->hwnd == GetActiveWindow()) {
+ if(lParam)
+ dat->hkl = (HKL)lParam;
+
+ if (dat->hkl)
+ ActivateKeyboardLayout(dat->hkl, 0);
+ }
+ return 0;
+
+ case DM_SAVESIZE: {
+ RECT rcClient;
+
+ if (dat->dwFlags & MWF_NEEDCHECKSIZE)
+ lParam = 0;
+
+ dat->dwFlags &= ~MWF_NEEDCHECKSIZE;
+ if (dat->dwFlags & MWF_WASBACKGROUNDCREATE)
+ dat->dwFlags &= ~MWF_INITMODE;
+
+ SendMessage(dat->pContainer->hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rcClient);
+ MoveWindow(hwndDlg, rcClient.left, rcClient.top, (rcClient.right - rcClient.left), (rcClient.bottom - rcClient.top), TRUE);
+ if (dat->dwFlags & MWF_WASBACKGROUNDCREATE) {
+ POINT pt = {0};;
+
+ dat->dwFlags &= ~MWF_WASBACKGROUNDCREATE;
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETSCROLLPOS, 0, (LPARAM)&pt);
+ if(PluginConfig.m_AutoLocaleSupport) {
+ if(dat->hkl == 0)
+ DM_LoadLocale(dat);
+ else
+ PostMessage(hwndDlg, DM_SETLOCALE, 0, 0);
+ }
+ } else {
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ if (lParam == 0)
+ PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 1, 1);
+ }
+ return 0;
+ }
+
+ case DM_GETWINDOWSTATE: {
+ UINT state = 0;
+
+ state |= MSG_WINDOW_STATE_EXISTS;
+ if (IsWindowVisible(hwndDlg))
+ state |= MSG_WINDOW_STATE_VISIBLE;
+ if (GetForegroundWindow() == dat->pContainer->hwnd)
+ state |= MSG_WINDOW_STATE_FOCUS;
+ if (IsIconic(dat->pContainer->hwnd))
+ state |= MSG_WINDOW_STATE_ICONIC;
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, state);
+ return TRUE;
+ }
+
+ case DM_ADDDIVIDER:
+ if (!(dat->dwFlags & MWF_DIVIDERSET) && g_Settings.UseDividers) {
+ if (GetWindowTextLengthA(GetDlgItem(hwndDlg, IDC_CHAT_LOG)) > 0) {
+ dat->dwFlags |= MWF_DIVIDERWANTED;
+ dat->dwFlags |= MWF_DIVIDERSET;
+ }
+ }
+ return 0;
+
+ case DM_CHECKSIZE:
+ dat->dwFlags |= MWF_NEEDCHECKSIZE;
+ return 0;
+
+ case DM_REFRESHTABINDEX:
+ dat->iTabID = GetTabIndexFromHWND(GetParent(hwndDlg), hwndDlg);
+ return 0;
+
+ case DM_STATUSBARCHANGED:
+ UpdateStatusBar(dat);
+ break;
+
+ //mad: bb-api
+ case DM_BBNEEDUPDATE:{
+ if(lParam)
+ CB_ChangeButton(hwndDlg,dat,(CustomButtonData*)lParam);
+ else
+ BB_InitDlgButtons(dat);
+
+ BB_SetButtonsPos(dat);
+ }break;
+
+ case DM_CBDESTROY:{
+ if(lParam)
+ CB_DestroyButton(hwndDlg,dat,(DWORD)wParam,(DWORD)lParam);
+ else
+ CB_DestroyAllButtons(hwndDlg,dat);
+ }break;
+ //
+
+ case DM_CONFIGURETOOLBAR:
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ break;
+
+ case DM_SMILEYOPTIONSCHANGED:
+ ConfigureSmileyButton(dat);
+ SendMessage(hwndDlg, GC_REDRAWLOG, 0, 1);
+ break;
+
+ case EM_THEMECHANGED:
+ DM_FreeTheme(dat);
+ return DM_ThemeChanged(dat);
+
+ case WM_DWMCOMPOSITIONCHANGED:
+ BB_RefreshTheme(dat);
+ memset((void *)&dat->pContainer->mOld, -1000, sizeof(MARGINS));
+ CProxyWindow::verify(dat);
+ break;
+
+ case DM_ACTIVATEME:
+ ActivateExistingTab(dat->pContainer, hwndDlg);
+ return 0;
+
+ case DM_ACTIVATETOOLTIP: {
+ if (IsIconic(dat->pContainer->hwnd) || dat->pContainer->hwndActive != hwndDlg)
+ break;
+
+ dat->Panel->showTip(wParam, lParam);
+ break;
+ }
+
+ case DM_SAVEMESSAGELOG:
+ DM_SaveLogAsRTF(dat);
+ return(0);
+
+ case DM_CHECKAUTOHIDE:
+ DM_CheckAutoHide(dat, wParam, lParam);
+ return(0);
+
+ case WM_NCDESTROY:
+ if (dat) {
+ memset((void *)&dat->pContainer->mOld, -1000, sizeof(MARGINS));
+ PostMessage(dat->pContainer->hwnd, WM_SIZE, 0, 1);
+ delete dat->Panel;
+ if(dat->pContainer->dwFlags & CNT_SIDEBAR)
+ dat->pContainer->SideBar->removeSession(dat);
+ free(dat);
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+ }
+ break;
+
+ case WM_DESTROY: {
+ int i;
+
+ if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->hContact, (LPARAM)0))
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->hContact, (LPARAM)szChatIconString);
+ si->wState &= ~STATE_TALK;
+ si->hWnd = NULL;
+ si->dat = 0;
+ si->pContainer = 0;
+
+ //SetWindowLongPtr(hwndDlg,GWLP_USERDATA,0);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTERX), GWLP_WNDPROC, (LONG_PTR)OldSplitterProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTERY), GWLP_WNDPROC, (LONG_PTR)OldSplitterProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LIST), GWLP_WNDPROC, (LONG_PTR)OldNicklistProc);
+ SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_UNSUBCLASSED, 0, 0);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), GWLP_WNDPROC, (LONG_PTR)OldMessageProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHAT_LOG), GWLP_WNDPROC, (LONG_PTR)OldLogProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_WNDPROC, (LONG_PTR)OldFilterButtonProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_COLOR), GWLP_WNDPROC, (LONG_PTR)OldFilterButtonProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_BKGCOLOR), GWLP_WNDPROC, (LONG_PTR)OldFilterButtonProc);
+
+ TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSING, 0);
+
+ if(!dat->fIsAutosizingInput)
+ DBWriteContactSettingWord(NULL, "Chat", "SplitterX", (WORD)g_Settings.iSplitterX);
+
+ if(dat->pContainer->settings->fPrivate && !IsAutoSplitEnabled(dat))
+ DBWriteContactSettingWord(NULL, "Chat", "splitY", (WORD)g_Settings.iSplitterY);
+
+ DM_FreeTheme(dat);
+
+ UpdateTrayMenuState(dat, FALSE); // remove me from the tray menu (if still there)
+ if (PluginConfig.g_hMenuTrayUnread)
+ DeleteMenu(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)dat->hContact, MF_BYCOMMAND);
+
+ if (dat->hSmileyIcon)
+ DestroyIcon(dat->hSmileyIcon);
+
+ if (dat->hwndTip)
+ DestroyWindow(dat->hwndTip);
+
+ if (hCurHyperlinkHand)
+ DestroyCursor(hCurHyperlinkHand);
+
+ i = GetTabIndexFromHWND(hwndTab, hwndDlg);
+ if (i >= 0) {
+ SendMessage(hwndTab, WM_USER + 100, 0, 0); // clean up tooltip
+ TabCtrl_DeleteItem(hwndTab, i);
+ BroadCastContainer(dat->pContainer, DM_REFRESHTABINDEX, 0, 0);
+ dat->iTabID = -1;
+ }
+ if(dat->pWnd) {
+ delete dat->pWnd;
+ dat->pWnd = 0;
+ }
+ //MAD
+ M->RemoveWindow(hwndDlg);
+
+ TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSE, 0);
+ break;
+ }
+ }
+ return(FALSE);
+}
diff --git a/plugins/TabSRMM/docs/INSTALL b/plugins/TabSRMM/docs/INSTALL
new file mode 100644
index 0000000000..bc4049f3df
--- /dev/null
+++ b/plugins/TabSRMM/docs/INSTALL
@@ -0,0 +1,43 @@
+
+ INSTALLING tabSRMM
+ ==================
+
+1.Miranda Requirements
+----------------------
+
+a) Miranda IM, Version 0.9.0.0 or later
+
+
+2) OS Requirements
+------------------
+
+For the UNICODE version, Windows 2000 or later is required. Windows XP or
+later are the only supported platforms.
+
+The x64 Version will require a 64bit Windows XP, Vista or Windows 7 AND can
+only work with a 64bit Miranda installation.
+
+HOW TO INSTALL
+--------------
+
+1) Copy the plugin DLL into your miranda plugins folder. Make sure that you HAVE
+ THE RIGHT VERSION (either ANSI or UNICODE). If unsure what you have downloaded,
+ do the following:
+ *) locate the plugin DLL in windows explorer
+ *) right click it, choose Properties... and navigate to the version tab. There
+ you will see the version number and also ANSI or UNICODE.
+
+DO NOT INSTALL A UNICODE build on a non-UNICODE Miranda installation. The opposite
+should work, but is not supported. In both cases, tabsrmm will throw a warning message
+when you start Miranda telling you that you had mixed UNICODE and ANSI versions.
+
+2) Install the icon pack (see below).
+
+INSTALLING THE ICON PACK - IMPORTANT !!
+---------------------------------------
+
+You need to copy the included tabsrmm_icons.dll into the \icons folder.
+If you don't, you'll receive an error message about a missing resource
+dll, and you won't see any icons on the toolbar and elsewhere. More
+information about setting up icons can be found in README.ICONS.
+
diff --git a/plugins/TabSRMM/docs/MetaContacts.TXT b/plugins/TabSRMM/docs/MetaContacts.TXT
new file mode 100644
index 0000000000..5afa62aa1d
--- /dev/null
+++ b/plugins/TabSRMM/docs/MetaContacts.TXT
@@ -0,0 +1,35 @@
+ tabSRMM + Metacontacts
+ ......................
+
+As of 0.0.9.5 tabSRMM contains support for the MetaContacts plugin by SjE. You
+can find this plugin here:
+
+http://www.miranda-im.org/download/details.php?action=viewfile&id=1595
+
+When you open a message tab for a meta contact, tabSRMM will automatically
+detect the MC and its current settings. The small protocol icon in the status
+bar of the container will show the icon for the active protocol of the MC.
+If you right-click this icon, you get a context menu from which you can:
+
+* change the default protocol
+
+* "force" a given protocol for sending to the MC. You cannot force a protocol, which
+ is offline, either on your or the other side.
+ If the forced protocol goes offline at any time (again, either on your or the
+ other side doesn't matter), the MC will revert to the "Auto selection mode"
+ and use the default or the "most online" protocol.
+
+In any case, a forced protocol will be "unforced" when you close the tab (i.e.
+revert to automatic protocol selection).
+
+While forcing works, you should still be careful with it. It shouldn't be necessary
+in most cases, as the metacontacts protocol will always ensure that its using the
+"most online" proto. It may make sense if your buddy asks you to send on a specific
+protocol though (for whatever reason...)
+
+This status bar icon is also there for non-metacontacts, but is not going to do
+anything other than showing the protocol in use for that tab. If you hover over
+it, then it will display a tooltip with your current nickname and the protocol
+name.
+
+
diff --git a/plugins/TabSRMM/docs/POPUPS.TXT b/plugins/TabSRMM/docs/POPUPS.TXT
new file mode 100644
index 0000000000..ae6aea392e
--- /dev/null
+++ b/plugins/TabSRMM/docs/POPUPS.TXT
@@ -0,0 +1,84 @@
+
+tabSRMM event notifications (also known as "popups"
+---------------------------------------------------
+
+Beginning with 0.9.9.95, tabSRMM has its own event notification system
+built into the plugin. That means, you should deactivate or uninstall
+existing event notifications plugins like NewEventNotify. If you want
+to continue using an external event notification plugin, you can disable
+tabSRMMs own system by doing the following:
+
+* Open Mirandas options dialog, go to Message Sessions -> Event notifications
+* Check "Disable ALL event notifications..."
+
+This will disable tabSRMMs own event notifications, and you'll never see popups
+or other types of notifications. You can then use an external plugin for
+this purpose (like any version of NewEventNotify.dll)
+
+In any way, you should always only have one system running at any given time.
+If you decide to use an external event notification plugin, then you should
+disable tabSRMMs internal system and vice versa. Having both active, may cause
+troubles like double popups and more. If you get double popups, then this is
+a strong indication for more than one event notification system being active.
+
+Why use tabSRMMs own event notification system?
+
+Simply, because it works better :) Since it is tightly integrates into the
+message dialog, it can do some things which an external plugin cannot. Also,
+most external plugins are written with top-level message windows in mind and
+therefore don't work very well with tabbed chat windows.
+
+Also, tabSRMMs event notify system is not limited to popups only. It can use
+the following ways to announce incoming messages:
+
+1) popups (need popup.dll installed - I suggest using a recent version of
+ popup PLUS or YAPP - the latter being more stable and actively maintained.
+
+2) On Screen Display (OSD). You can either use wbOSD or the old OSD plugin
+ - both available on the miranda file listing.
+
+3) Balloon (system tray) tooltips. Only available on Windows 2000 or
+ later.
+
+Configuration of event notifications is done on the "Message Sessions >
+Event Notifications" page. Most options should be familar if you have ever been
+using a NewEventNotify plugin.
+
+The "announce method" specifies in which way you want to see the event
+notifications (popups, osd or balloon tooltips). The combo box will only
+contain entries which are available (the necessary plugin is installed and
+detected).
+
+
+If you have choosen that you want to see notifications, even if a message
+window is already open (UNCHECK "Don't announce event when message dialog
+is open"), you can further configure that on a "per container" base. You
+can find these options on the containers menu bar (Container->Event
+popups")
+
+The relevant options are:
+-------------------------
+
+1) Enable popups if minimized
+ The container and all its tabs will show popups if the container has
+ been minimized to the taskbar.
+
+2) Enable popups if unfocused
+ More aggressive popup behaviour. Now, you will always see event popups
+ unless the container is in the foreground (active and focused).
+
+3) Always enable popups for inactive tabs.
+ This is the most aggressive setting. You will always see popups, UNLESS
+ the container is focused (in the foreground) and the tab which received
+ the event is the active one (selected).
+
+The last option will basically show you popups for all your open sessions,
+except for the session which is active (in the foreground).
+
+You can set default values for these under Options->Message containers
+which will apply to containers at creation time. Once a container exists,
+it has its own copy of these settings, so if you need to change them, you
+will have to use the container settings dialog (right click the title- or
+button bar of an open container or use the system menu and choose
+"Container Options".
+
diff --git a/plugins/TabSRMM/docs/changelog.OLD b/plugins/TabSRMM/docs/changelog.OLD
new file mode 100644
index 0000000000..0449d8840b
--- /dev/null
+++ b/plugins/TabSRMM/docs/changelog.OLD
@@ -0,0 +1,2596 @@
+ Project Information:
+ ====================
+
+Name: tabsrmm
+Homepage: http://tabsrmm.sourceforge.net
+SF.NET Project Page: http://www.sourceforge.net/projects/tabsrmm/
+Support: http://www.miranda.or.at/forums/
+
+ --------------------
+
+ Version History:
+ ================
++ : new feature
+* : changed
+! : bufgix
+- : feature removed or disabled because of pending bugs
+
+Version 0.9.9.100
+
+ Changelog is now provided online and updated more often.
+ http://miranda.or.at/2006/03/05/tabsrmm-changelog/
+
+
+Version 0.9.9.99(3 - nightly build #47) - 2006/02/xx
+
+ + added hotkey (CTRL-n) for sending a MSN nudge. Requires recent version of MSN plugin
+
+ * remmoved own copy of xStatus icons from tabSRMM. It is now using the ICQJ XStatus
+ API to get the icon (works only with recent versions of ICQJ).
+
+Version 0.9.9.99(2 - nightly build #46) - 2006/01/20
+
+ + enabled the send menu entry to force a "timeout less" sending mode. The option can
+ also be found on the contact preferences dialog (user menu) and basically does the
+ following: If enabled, the message window does NOT wait for a sending confirmation
+ of the protocol. This means that you'll never get notified if something goes wrong
+ while sending the message. Only enable it if you have constant timeout problems for
+ this particular contact.
+
+ This option is a "per contact" setting and there is no global counterpart. It is meant
+ to help solving troubles with "problematic" contacts (that is, contacts which often
+ cause timeouts when sending messages, because of networking or other issues).
+
+ + enhancement: The "vertical maximize" feature can now also be triggered by holding the
+ CTRL key while clicking the maximize button. The old way of setting vertical maximize
+ for each container permanently (container options dialog) is still available though.
+
+ * reduced the number of scrolling commands sent to IEView when resizing and/or creating
+ the message window. This should speed up IEView somewhat when using more complex
+ templates.
+
+ * the info panel avatar now follows the avatar visibility setting on the Message Window->
+ General option page. For example, if this is set to "Globally off", no avatars will
+ appear on the info panel.
+
+ * message window avatar display(s) (both bottom and info panel) now respect the avatar
+ service "Set as hidden" property which one can configure for a contacts picture.
+ So you are no longer forced to view really ugly avatars :)
+
+Version 0.9.9.99(1) - 2005/12/27
+
+ + added option to enable/disable drop shadows (options->Message Window->containers)
+
+ ! fix: the options to set message log background colors were disabled when using font
+ service.
+
+Version 0.9.9.99 - 2005/12/23 - happy Xmas :)
+
+ * improvments for own avatar display. Now, this uses the avatar service (minimum
+ version 0.0.1.11) for managing your own avatars. tabSRMM now always shows the proper
+ avatar you have configured for a given protocol under Main Menu -> View/Change my details.
+
+ Setting your own avatar in the message window is possible (right click your avatar image
+ and choose "Set your avatar...". However, the menu entry may appear grayed which means
+ that the protocol does not support setting the avatar from "outside" its own option
+ pages. Currently, only MSN allows to set the avatar using an external service.
+
+ + added workaround for the "Unknown Contact" problem with some protocols (fallback to
+ non-unicode nickname). (unicode build only).
+
+ + added EXPERIMENTAL feature - real time message log trimming.
+
+ What the.... ?
+
+ This feature was inspired (or suggested) by one user on the forum. At first,
+ i thought that it is almost impossible to implement with the rich edit control as
+ our message history viewer. But I found a reasonable way to do it anyway.
+
+ It is for people who are rarely closing their message windows. As a result, a growing
+ message history in the chat window(s) may consume HUGE amounts of memory, especially when
+ emoticons and message log icons are enabled.
+
+ The solution? Trim the message log to a maximum number of events (e.g. 200) - older events
+ will disappear from the top of the message history and only the N most recent events
+ will remain in the chat window. As a result, memory requirements may drop significantly.
+
+ The feature is different from the already exsting "load N number of old history events",
+ because it works in "real time". Whenever a new message is sent or received, the
+ message history will be trimmed at the top so that only old text will disappear.
+
+ How to use?
+ Set the global limit for all message windows on the "Message Log" options page. A per-
+ contact setting is also available in the "tabSRMM settings" dialog which you can reach
+ from the contacts context menu. The per contact setting overrides the global value.
+
+ NOTE: changing this setting will not affect message windows which are already open,
+ so you need to close and re-open them.
+
+ One word of warning, though. This feature has a side effect. In order to "know" where to cut
+ off the message history, markers need to be placed in the text. The markers are hidden
+ number sequences (which actually correspond to database event handles), but when you copy
+ text from the log, the rich edit control will copy the hidden text. As far as I know, there
+ is no way to avoid this.
+
+ Also, depending on your template, the top of the message log may not always look perfectly
+ formatted, because text is removed from the top only.
+
+ NOTE2: won't work with IEView as IEView uses a completely different way of displaying
+ messages and tabSRMM has no control over the contents of the IEView message history
+ window.
+
+ ! FIX: Alt-M didn't properly create the embedded multisend contact list.
+
+ + added a color control for setting the info panel fields background color to the font
+ configuration dialog. Previously, this was only possible with font service.
+
+ * improved avatar display on the info panel. Avatars will no longer waste horizontal space
+ if their width is smaller than their height (like most ICQ avatars). The size of the
+ avatar field is now properly calculated so that the avatar fits.
+ Also, the info panel does no longer show the "unknown" avatar for contacts which don't
+ have a contact picture available.
+
+ * redesigned the info panel somewhat. The ugly check box is gone, the fields have been
+ re-arranged to allow more space for the nickname.
+
+ + the option to allow active status message retrieval when hovering the info panel field
+ can now be found under Options->Message Window->General
+
+ ! bugfix - message window did not react on manual nick name changes on the contact list
+ (changing CList/MyHAndle).
+
+ + added a "simple" event popup configuration mode. Its on options->Message Window->Event
+ notifications and knows 3 modes:
+ * Notify always -> popups will show for each message
+ * Notify for unfocused sessions -> popups will show for minimized or background message
+ windows.
+ * Notify only when no window is open -> Message popups will only appear when no message
+ window is open for that contact.
+
+ The simple mode skips some of the advanced popup configuration options, including the
+ "per container settings". It also skips the "Sync sounds" option.
+
+ + added the per contact infopanel setting to the per contact settings dialog.
+
+ + added option to specify the type of border for the avatar(s) in the message window.
+ There are 5 options:
+ * None
+ * Automatic
+ * Sunken
+ * 1 pixel solid
+ * rounded border
+
+ Automatic means that it will draw a solid border for normal avatars, while for transparent
+ or semi-transparent images, a sunken frame will be drawn.
+ The color for solid borders can be configured aswell.
+
+ The options are on the "General" tab, in the "Avatar options" section.
+
+ * fixed bug with non-appearing message log icons
+
+ * fixed wrong hotkey Ctrl-C was opening the user preferences dialog instead of doing the
+ usual copy action. User preferences is now on Alt-C
+
+ + some smoother and less "jumpy" resizing when switching tabs after container size changed.
+
+ + when using the "Trim message log feature", the message input area now tries to delete the
+ invisible markers when copying text from the message log to the message input area.
+
+ + new hotkey: Alt-F (send file, brings up the send file dialog)
+
+ ! fixed a few minor visual glitches (button mode tabs clipping issues)
+
+Version 0.9.9.98 - 2005/11/07
+
+ * several sanity checks added (pointers, window handles)
+
+ ! status bar remembers typing notification state when switching tabs even with
+ the session list button active.
+
+ + added about dialog
+
+ ! fixed small visual glitch with multisend indicator
+
+ + hotkey: Ctrl-T -> toggle menu bar
+
+ ! local avatars (load a local picture) can now use relative pathnames when the picture
+ you selected is located in a subdirectory of your miranda folder.
+
+ + added first run configuration dialog
+
+ + added "per container themes". It is now possible to define a private .tabsrmm theme
+ file for a container. This includes the entire theme, fonts, colors, template message
+ log settings.
+
+ ! bugfix (UI problem in the global/local radio button of the user preferences dialog).
+
+ * changed multisend contact list. It is no longer created automatically for each tab
+ you open, instead, the contact list is only created when you activate the multisend
+ feature and destroyed when it is no longer needed. Saves quite *some* resources and
+ loading time, especially with complex contact lists (clist_nicer, clist_modern and
+ such).
+
+ * updated for new smileyadd api (event for changed emoticon configuration). Changing
+ smileyadd options will now instantly reconfigure smileyadd settings in all open message
+ windows (button icon + smileys in the message window).
+
+ + added support for the updater plugin
+
+ + removed tabsrmms own avatar loading and managment code. It now builds on top of the
+ avatar service plugin (loadavatars.dll). You need this plugin installed in order to
+ get avatars working.
+
+ + added ability to render transparent PNG images when set as local contact pictures by
+ the avatar service.
+
+ ! fixed bug with formatting parser - ignore messages when they contain curly braces ( {
+ and } ) to avoid conflicts with the rtf syntax.
+
+ * several unicode fixes (status messages, xstatus messages and names, title bar format
+ (%m variable) and more.
+
+ * upgraded build environment to Visual C++ 8.0 (VSNET 2005).
+ New project file(s) are added to the source tree. tabSRMM_8.sln and tabSRMM_8.vcproj
+ are VC++ 8 compatible project files and can only be used with visual studio 2005.
+ The project files for Visual Studio .NET 2003 (tabSRMM.sln and tabSRMM.vcproj) are
+ still available.
+
+Version 0.9.9.97 - 2005/07/23
+
+ ! extended status tooltip working with all (recent) ICQ.dll builds.
+
+ ! fixed clock symbol for some special situations.
+
+ + new title format variable: %m -> meta status. Has nothing to do with metacontacts.
+ How it works: If an extended status is set, it will be used. If not, the normal
+ protocol status is shown. Also supports custom status mode names using the XStatusName
+ db setting (supported by ICQJ and ISee).
+
+ ! typo in the template parser (%m variable)
+
+ * removed smiley selection window focus workaround. No longer necessary, because
+ fixed smileyadd doesn't mess up input focus any more.
+
+ + new shortcut: Ctrl-K -> clear input area
+
+ ! fixed %D and %E variables
+
+ + updated for smileyadd 1.5.0 (by borkra). Beginning with this release, tabSRMM does
+ no longer require its own smileyadd plugin and therefore this plugin has been removed
+ from the archive.
+
+ I suggest to update to the most recent smileyadd, available from:
+
+ http://www.miranda-im.org/download/details.php?action=viewfile&id=2152
+
+ It is strongly recommended to use this version, because it fixes a lot of issues and
+ has some internal improvements. It is fully compatible with all SRMM-based message
+ windows and therefore works with SRMM, tabSRMM, scriver and others.
+
+Version 0.9.9.96 - 2005/07/18
+
+ ! null pointer check when retrieving status message. Fixes crash when retrieving
+ status messages.
+
+ ! fixed window icon problem (autoswitch related)
+
+ * added range checks for the panel splitter (don't save/load "invalid" values)
+
+ ! fixed icon on the "visibility indicator" in the info panel (only, when
+ using the manual quick toggle mode).
+
+ ! fixed "sticky" unread icon (didn't always go away when container got the focus.
+
+ ! corrected some typos
+
+ ! minor info panel fixes (toolbar menu)
+
+ * allow close tab within error state (visible error controls), Unsent messages which
+ returned an error are canceled. Messages "in progress" may still be sent, but the
+ ACK will then go to nowhere after the msg window has been closed.
+
+ * version bump (0.9.9.96)
+
+ * added %x variable for the titlebar to show the extended status mode description.
+ The following variables are now available:
+ %n - Nickname
+ %s - Status mode description
+ %c - container name
+ %u - UIN
+ %p - protocol
+ %x - extended status mode description (icq only)
+
+ + added ability to use underlined fonts in the message window when configured with
+ the font service plugin.
+
+ + the user notes field now follows the message input area configuration more closely.
+
+ ! some container settings didn't "stick" when set from the system menu or title bar
+ (stay on top, hidden titlebar)
+
+ + added support for unicode popups (tabsrmm_unicode only, obviously). It will auto-
+ matically detect a unicode-enabled popup.dll and use it.
+
+ * removed the clock icon from the contacts local time display. It is replaced by clock
+ symbols from the Wingdings font.
+
+ + added ability to configure several aspects of the info panel. Fonts and colors for
+ various fields can now be changed. Also, you can set up the background color for the
+ fields and their frame style.
+ Requires the font service plugin.
+ Frame style can be set on the "Tabs and layout" option page.
+
+ ! fixed Alt-GR (right alt) problem with some hotkeys.
+
+ + added hotkeys: it is now possible to cycle tabs using the multimedia keys:
+ "Browser backward" switches to the previous tabs
+ "Browser forward" switches to the next tab.
+ This should work with all properly configured multimedia keyboards and most
+ mice featuring extended button mapping (e.g. it works with the Logitech MX 510)
+ If it doesn't work for you, then your system is not configured properly.
+ NOTE: requires Windows 2000 or later.
+
+ * don't send typing notifications while opening a message window with a "saved" message.
+
+ * info panel can now retrieve and show custom extended status names and extended status
+ messages (very recent build of ICQJ required). If no custom status name is available,
+ the "built in" will be used, depending on the extended status code.
+
+ ! ignore icon pack version info check was, well, ignored... :)
+
+ ! fixed %E variable (did sometimes convert date/time to empty strings).
+
+Version 0.9.9.95 - 2005/06/28
+
+ * container icon and title is now set earlier so that the container does not
+ show "Dialog" while tabs are created.
+
+ * fixed rtf parser to deal with some (rare) rich edit bugs.
+
+ * changed tab layouting for single AND multiline BUTTON tabs. Both modes are
+ now using fixed width tabs and the layouting code will try to always "fill"
+ the rows. An option to set the default fixed tab width has been added
+ to the tab appearance configuration dialog.
+
+ + new feature for event notifications (popups only):
+
+ tabSRMM can now remove popups for a contact under the following situations:
+
+ 1) container receives focus
+ 2) you start typing a reply
+ 3) you send a reply
+
+ The feature can be configured on the Options->Event Notifications page (in the
+ listbox with all the checkboxes inside - at the very end of the list).
+
+ Whenever one of these options is checked, tabSRMM will remove ALL popups for the
+ contact when one of the above conditions is true. Note that you can combine them,
+ but that doesn't make much sense. 1) (focus) always happens before any other event.
+
+ The feature is pretty useful if you have multiple popups from a single contact on
+ screen.
+
+ - removed status bar message "keyboard layout saved". No longer needed, because
+ the keyboard layout is now always visible as 2-digit code in the 2nd status bar
+ panel.
+
+ * minor layout changes in the message window. Toolbar buttons are slightly smaller
+ and got a better look when using classic Windows theme (3d effect toned down a
+ a bit).
+
+ * implemented a suggestion by Joe @ Whale, using IsUnicodeAscii() to check if a given
+ message really needs to be sent as unicode. If not, the message is sent ANSI only.
+ The advantage is that this may save A LOT of database / history size, because it
+ avoids storing every message twice (both ansi and UCS-2 parts). With the new
+ system, an UCS-2 part is only saved (and sent) when needed. Messages containing
+ 7bit characters only (0x00 - 0x7f, most latin characters) are safe to be sent as ansi.
+
+ ! fixed bug with formatting buttons
+
+ * removed "ding" sounds when using some hotkeys (Alt-S for example)
+
+ * various langpack updates
+
+ * ICON PACK: updated "unknown.bmp" (default avatar image). Thanks to Faith for the
+ .bmp.
+
+ * several (internal) changes to focus handling and tab activation. Some things have been
+ simplified in the code, and in some areas additional safety checks were added.
+ May result in new focus/redraw bugs, but overall, the new system is an
+ improvement. It just needs to stabilize.
+
+ * toolbar buttons are now always "flat" when using visual styles under XP. They no
+ longer use push button skinning. Beveled (3d) buttons are still available for
+ classic windows theme.
+
+ * DISMISS EVENT is back, but with a big warning when you first activate it / and or
+ run miranda with that option active. Also, it is only available for "click" actions,
+ you cannot set dismiss event for the popup timeout action.
+
+ * the tab control is now a full window class, and no longer only subclassed.
+
+ + new hotkeys:
+ ALT-I: quick show / hide the info panel
+ ALT-B: toggle BiDi option (switch between RTL and LTR)
+
+ * new option to format the title bar using variables. The format string for the title
+ bar is simple and may be up to 50 characters long. It can contain any text you want
+ and the following variables as placeholders:
+
+ %n - Nickname
+ %p - protocol
+ %u - UIN
+ %s - Status mode
+
+ You can set the default format string for all containers under Message Sessions->
+ Message Window->Containers.
+
+ You can also set a private title bar format string in the container options dialog.
+ Just tick "use private title format" and set the format template string.
+
+ * possible fix for a rare redrawing bug, resulting in black background on tabs (visual
+ styles, tabs at the top only).
+
+ * prevent custom template background colors from taking the rgb value 0,0,0 to avoid
+ a problem with icon transparency and "pure" black bg color. A pure black bg color
+ is converted to rgb(1,1,1).
+
+ + added support for the FontService plugin by sje to customize message window fonts and back-
+ grounds. If font service plugin is enabled, tabSRMMs own font+color configuration page
+ is disabled. However, tabSRMM still maintains its own copy of font + color settings in
+ the DB so that you can switch between using font service and the old dialog easily.
+
+ + restored "mark on double click" for the message history log.
+
+ * the info panel splitter now follows the settings for the normal splitter (global, private
+ saving policy etc.).
+
+ + added visual styles support for button tabs (using pushbutton skins).
+
+ ! fixed transparency issues when changing focus
+
+ + activating the smiley selection window does no longer switch containers transparency to
+ "inactive".
+ NOTE: requires new build of smileyadd.dll (included in this release) and does NOT work
+ with IEViews smiley selection window. Sorry for that, but it needs a small change in
+ the smiley selection window code. So I would have to distribute a modified IEView aswell
+ (which I don't like).
+
+ + added global options for container(s). The container options dialog now allows you to
+ set the options for any container to "global" or "private". All containers using global
+ options share one set of container configuration flags (and transparency values).
+ Title bar format and container window position/size can be set independently to either
+ global or private.
+
+ + added the info panel allowing for dual avatar display.
+
+ + added idle detection (if the protocol supports it) and render icons "dimmed" for idle
+ contactst.
+
+ + improved support for international nicknames. tabSRMM can now encode nicknames with the
+ ANSI codepage you've set for a given contact. To set a codepage, do the following:
+ * right click the message log in an open tabSRMM message window and select a code page
+ OR
+ * use the user preferences dialog (tabSRMM settings), available from the contacts context
+ menu
+
+ + more info panel stuff - ability to show the local time of the contact (if a timezone is
+ provided). Now also shows the protocol beside the status mode.
+
+ + hovering the status field in the info panel will try to retrieve the away message for
+ that contact and show it using a tooltip. Away msg retrieval is limited to once per
+ minute to avoid abuse by flooding the contact with awaymsg requests.
+ The little checkbox between the avatar and the status field can be used to disable
+ that feature (to avoid "accidentially" retrieving the status msg).
+
+ + tree views in various option pages were updated to use better check box and node
+ images.
+
+ + support for the scrolling service in future builds of IEView was added. Now, ieview
+ will always properly scroll down the message log.
+
+ + setting the own avatar, using the bottom avatar display (when the info panel is active)
+ will now set the protocols avatar. At the moment, this works only with MSN, because
+ it's the only protocol providing the SetAvatar service.
+
+ + added support for extra status icons (icq5). Requires a recent build of ICQJ (alpha) or
+ ISee. The extra status icon is visible in the info panel, just in front of the nickname.
+
+ + added ability to set a timezone for any contact, using the user preferences dialog box
+ (tabSRMM settings in the user context menu). This will work with all protocols and
+ OVERRIDE the contacts timezone provided by the protocol (currently, only icq provides a
+ timezone information).
+
+ If a valid timezone is found, the contacts local time will be shown in the info panel,
+ and can be used for message log timestamps.
+
+ + added "paste and send" feature. Available as a hotkey (Ctrl-D) or from the context menu
+ in the input area. Pastes the current contents of the clipboard to the message input area
+ and immediately sends the message. Needs to be enabled under Options->General->Sending
+ Messages.
+
+ + added tooltip to the info panel nickname field when the contact has set an extended
+ status (icq only).
+
+Version 0.9.9.95pre7 - 2005/05/23
+
+ * double click works again for closing tabs (even with button tabs)
+
+ ! bugfix: redraw errors when restoring a maximized container
+
+ + added a help window to the template editor describing all the variables and
+ modifiers.
+
+ * 2nd try to fix Ctrl-W and Ctrl-F4 (Win 9x only)
+
+ + added option to force some extra redraws (options -> tabs and layout -> Force
+ more aggressive window updates). If enabled, it will force additional re-
+ draws.
+
+ * optimized visual styles rendering on the tab control. Don't draw unneeded stuff.
+
+Version 0.9.9.95pre6 - 2005/05/20
+
+ ! bugfix - tab control did not use the proper visual style part for leftmost
+ tabs.
+
+ ! bugfix - in some cases, the wrong font was used for drawing the tab labels
+ so that they appeared oversized and clipped (or the opposite which resulted
+ in too much padding).
+
+ ! fixed Ctrl-W and Ctrl-F4 causing crashes.
+
+ * rewrote automatic container creation. Should be faster now, and hopefully
+ with less problems.
+
+ * changed visual style drawing method on tabs. Now, it uses real transparency
+ so it should work with all visual styles w/o drawing problems or inaccuracies.
+
+ ! when changing the style or theme, tab colors are re-read when using standard
+ windows colors to draw tab labels and backgrounds.
+
+ + added current 2-digit input locale identifier to the status bar.
+
+ + autlocale does no longer use WM_INPUTLANGCHANGEREQUEST, because that's causing
+ troubles with some systems (reasons unknown). Instead, it now uses WM_INPUTLANGCHAGE
+
+Version 0.9.9.95pre5 - 2005/05/20
+
+ ! fixed bugs with the new custom tab control. No more label clipping errors
+ (hopefully). Also, when using classic windows theme, bottom tabs are
+ are restored to their default look and no longer show as buttons.
+
+ + added option to use standard windows colors for button style tabs to mark the
+ active and hot-tracked tab.
+
+ + added "autolayout" option for single row tab controls. If enabled, all tabs
+ will have the same width, depending on the number of tabs and available
+ space. Works only, if the tab control is in "single row mode". Tab text will
+ be clipped accordingly and filled with ellipsis (...), if needed.
+
+ The option to set the tab control to "single row" has been removed from the
+ container options and moved to the "Tab Appearance" dialog. It is now a
+ global setting. Multi-row tab controls are still supported however.
+
+ ! fixed weird bug with mousewheel behaviour when IEView is active.
+
+ * changed the "tabs and layout" option page to use a tree view with check-
+ boxes to make it consistent with other option pages.
+
+Version 0.9.9.95pre4 - 2005/05/20
+
+ * docs updated (Popups.txt, readme.txt, README.ICONS)
+
+ + added an option to disable tabSRMMs internal event notifications system
+ (options -> Message Sessions -> Event notifications). Use this, if you
+ want to continue using an external NewEventNotify plugin. This will only
+ prevent tabSRMM from showing popups or other notifications. Things like
+ the session list will continue to work.
+ The same switch is available on the tray context menu (Disable all event
+ notifications)
+
+ ! don't re-create the tray icon after explorer crash, if tray icon support
+ is disabled.
+
+ + variables added: %cX for setting a font color, & as variable modifier to
+ "skip" the contextual font setting.
+
+ * improvements to the tray and floater. There is a new option to show the
+ floater only when the contact list is minimized (not visible). Also, a bug
+ with windows minimized to the tray has been solved.
+
+ * optimized the template parser for more speed (as a penalty, the code size
+ increased a few k).
+
+ * several UI improvements to increase usabilty.
+
+ + added custom tab control with the ability to show skinned tabs at the bottom
+ properly. Also, it can be configured to act as a "button bar".
+ Right click a tab and choose "Configure Tab Appearance" to set some
+ options.
+
+ In "classic mode" (visual styles not available or disabled), bottom tabs
+ will always look "flat" (like a switch bar).
+
+ + added mousewheel-controlled tab switching. If you move the mousewheel while
+ the pointer is over the tab bar area, it will switch tabs. Moving the wheel
+ upwards will switch to the previous tab, while moving the wheel downwards
+ will switch to the next tab.
+
+ + added flicker-free avatar drawing
+
+ + changed grouping mode slightly. Last midnight will now break a group in any
+ case, so messages from yesterday cannot be grouped with messages from today.
+
+Version 0.9.9.95pre3 - 2005/05/10
+
+ ! fixed HUGE bug with bbcode color handling.
+
+ ! fixed memory leak in ShowPicture() (avatar handling). thanks to ghazan.
+
+ + added various settings to the message log and general options pages (icon/
+ symbol config, default send format).
+
+ + attempt to fix the mouswheel problem.
+
+ ! fixed month number variable
+
+ + added %fX variable (switch to font).
+
+ * autoreplacer should work again.
+
+ * fixed few visual glitches (multiple send indicator and switch toolbar on/off,
+ overlapping multisend indicator and message input area).
+
+ * free() sendqueue buffers in Unload() to stop BC complaining.
+
+ * msg log icons are no longer cached to allow fully "transparent" icons in
+ the message log. slightly slower when loading lots of events, but not
+ dramatically.
+
+ ! fixed bug with WYSIWYG formatting in the input box.
+
+ * bbcodes are no longer stripped when bbcode support is off. They are now ignored.
+
+ * redesigned the event popups option page. Separate settings for the floater are
+ now available.
+
+ + added option to show/hide floater (independent of tray icon support)
+
+ + added option to show the floater functionality in the message window. If enabled,
+ the status bar will show a small icon in the bottom left corner. Left click it
+ for a session list (list of open tabs), right click it for the tray menu to access
+ favorites, recent list and some global options. Again, this option is not related
+ to tray icon or floater support and can be enabled without the tray icon or the
+ floater being visible.
+
+ * some improvments to the template editor.
+
+ + fixed bug with favorite contacts menu.
+
+ + New hotkeys added:
+ Alt-NumPad/ -> set focus to the message log
+ Alt-NumPad* -> set focus to the message input area
+ Alt-M -> activate multisend mode (and set the focus to the multisend contact list
+ Alt-NumPad+ and AltNumPad- cycle tabs (same as CtrlPgUp/Dn)
+
+ ! fixed bug with IcoLib support (icons disappearing, crashes)
+
+Version 0.9.9.95pre1/2 - 2005/04/15
+
+ + added message templates for the default message log. As a result, many options
+ are now different or gone, because they can be replaced by using custom
+ templates in a better way.
+
+ Please refer to: http://www.miranda.or.at/forums/index.php/topic,610.0.html
+ for some documentation about available variables and templates in general.
+
+ + Icon packs have been updated with proxal icons. Both the XP and the default
+ (98/ME) packs are now using the icons from the proxal set).
+
+ * no more smiley button in forwarding sessions, both for smileyadd and ieview.
+ Depending on the smiley pack configuration, smileyadd or ieview may crash,
+ because forwarding windows are not assigned to a specific protocol.
+
+ ! quoting selection with ieview may fail in a few very rare cases.
+
+ * Splitter position is now saved in a private database entry. It is no longer
+ shared with SRMM or other SRMM-based message windows. As a result, message
+ windows may come up with a default splitter position.
+
+ + added support for SRMM-style "focused" and "unfocused" incoming message
+ sounds. Focused, in that context, means that the container needs to be the
+ foreground window and the tab needs to be active. All inactive tabs or containers
+ are considered "unfocused".
+
+ Sound effects can be configured under Miranda Options->Events->Sounds
+
+ + added quick sound toggle switch on the status bar. The icon shows whether
+ sounds are off or on. Clicking the icon will toggle sound effects, holding
+ SHIFT while clicking the icon will apply the current state to all *open*
+ containers. Sound toggle is a per container setting and will be saved when
+ you close a container.
+
+ + save the font for the input area under SRMsg aswell so that the MSN plugin
+ will find it.
+
+ + the rich edit log can now recognize simple BBCode tags for formatting text in
+ bold, italic and underline.
+
+ + The parser has been updated and can now convert the rich edit output from the
+ message input box into bbcodes. It can still parse to "simple" tags (the */_
+ stuff) though. There is a new submenu in the protocol menu on the toolbar which
+ allows you to select which formatting method you want. You can also set this
+ "per contact" since not everybodys IM client can handle bbcodes.
+
+ + the message grouping mode has been overhauled. Just check it out - it looks
+ better :)
+
+ + integrated an own version of event notifications. tabSRMM no longer requires a
+ EventNotify plugin. This stuff has a lot of options, including support for system
+ tray baloon tooltips instead of popups (these can announce unicode messages). Also,
+ a very comprehensive system tray support has been added.
+
+ ! fixed a very rare unicode-related problem when using ieview.
+
+ + added message API 0.0.0.3 as outlined in SRMM.
+
+ + added 2 submenus to the right-click tray menu: "Favorite Contacts" and "Recent
+ Sessions". The first lets you save up to 20 contacts as favorites. To save a
+ contact as favorite, open a message window and click the small dropdown button
+ on the toolbar, right of the user menu button. There is a submenu called "Favorites"
+ which allows you to add or remove a contact from the list of favorites.
+
+ The "Recent Sessions" list automatically saves the 20 most recently used sessions
+ (whenever you close a message window). Both favorites and recent sessions are
+ stored in the DB, so they will survive a miranda restart.
+
+ + added "auto select and copy" for the message history log. If you release the left mouse
+ button when text is selected in the log it will be copied to the clipboard instantly.
+ You need to enable this on the "General" option page ("Auto-copy message log selection")
+
+ * Hold CTRL to instantly insert the selected text in the message input area (plain text)
+ at the current cursor position (may replace any selection in the input area).
+ * Hold CTRL-ALT - as above, but inserts formatted text
+
+ * changed hotkeys: Alt-Left/Alt-Right for tab switching to Ctrl-PgUp/PgDown. Alt-Left/Right
+ causes some strange and annoying effects with some non-western keyboard layouts.
+ Reasons unknown so far.
+
+ + added hotkey to invoke the Protocol Menu: Ctrl-P (works with and without toolbar visible).
+
+ + included a new build of smileyadd which should fix the "gadu gadu" protocol bug (no smileys
+ visible on GG). The included smileyadd.dll is for TABSRMM ONLY.
+
+ ! various resource leaks fixed - thanks to ghazan for hunting them down :)
+
+ ! automatically creating tabs or windows does no longer switch and "steal" keyboard
+ layout (autolocale bug)
+
+ ! IEview no longer steals focus from the input area when a container has been created in
+ the background (minimized)
+
+ + added option to disable animation when minimizing containers to the system tray
+
+ + added tooltip for the tray icon so that XP remembers the autohide status of this icon.
+
+ + various popup fixes - they now show auth and added requests properly (including nickname
+ and protocol from which they came).
+
+ * the "add contact bar" is gone, because it was wasting way too much screenspace and made
+ the dialog layouting more complex than necessary. Instead, 2 buttons (Add it, Don't add)
+ are now visible for any contact which has not been permanently added to your contact list.
+ These buttons appear just right of the message input area (and left of the avatar, if
+ present) and are independent of the toolbar setting.
+
+ + added support for IEViews "save message log as html" feature. Choose File->Save Message
+ Log As..." from the menubar.
+
+ * reorganized message log options. Message log formatting is now global by default. A new
+ dialog has been added to the user menu (Messaging Options) which allows you to override
+ all "per contact" options.
+
+ + added hotkey: F12 toggles "freeze message log updates". When enabled, all updates to the
+ message log are frozen until you disable it again. That means, new messages are NOT sent
+ to the message log. However, these messages are not lost, they are internally queued and
+ will be written to the message log when you unfreeze it. This is useful, if you want to
+ read the message log w/o being disturbed by new arriving messages causing the log to scroll
+ to the bottom automatically.
+
+ + added better mouswheel handling. Using the mousewheel now scrolls the control with the
+ pointer in it (no need to change focus).
+
+ * replaced the tray-icon double click with a middle mouse button click action.
+
+ ! fixed: wrong (own) nickname may show up in the message log history for metacontacts.
+
+ + tray icon will now be recreated after explorer has crashed (and restarted).
+
+ * Meta Contacts support: show user details page of current protocol instead of the meta
+ contacts page.
+
+ + added a "floater" to access the session list and tray menus when tray icon support is
+ disabled. The floater is a small window which will stay on top and has 2 icons - one
+ will open the session list, the other will give you access to the tray icon context
+ menu holding some options and the favorites and recent menus.
+ Useful if you don't like the tray icon or usually work with a hidden taskbar.
+
+Version 0.9.9.94 - 2005/04/11
+
+ * small fix with static avatars and toolbar button hiding.
+
+ + added support for the Math Module plugin. Requires recent MathModule
+ version. MathMod support can be activated on the Message Log options
+ page (only, if the plugin is active, otherwise the option is grayed out)
+
+ * attempt to fix a rich edit "feature" which may sometimes automatically change
+ input locale (keyboard layout).
+
+Version 0.9.9.93 - 2005/04/11
+
+ * updated translation template, added german translation
+
+ * some option pages updated (conditionally enable/disable controls)
+
+ * removed unused "Sound" submenu from the menu bar.
+
+ * icon descriptions for IcoLib are now translateable (see the section at the
+ end of the language template).
+
+ + added MS_MSG_GETWINDOWAPI ("MessageAPI/WindowAPI") service for Message
+ API 0.0.0.2 specs
+
+ * when using the "Send Later" send mode, a log message informs you about
+ successfully passing the message over to buddypounce. If using IEView, the
+ message is printed to the status bar instead.
+
+ * MetaContacts support - the status icons in the title bar and on the tool
+ bar are now showing the actual protocol icons. Also, smileyadd will now use
+ the smiley set which has been configured for the actual protocol. No more
+ need to define an extra smiley set for the MetaContacts protocol (does not
+ work with IEView though, because IEView does its smiley selection alone).
+
+ Consequently, the MetaContacts control menu has been moved from the status
+ bar to the tool bar -> right click the protocol button for the MetaContacts
+ context menu.
+
+ ! fixed small visual glitch with the add contact bar.
+
+ * changed memory handling for the sendqueue and input history.. fixed possible
+ memory corruption with DBCS strings.
+
+ * some IEView related updates.. codepage for force ansi send mode
+
+ + quoting support for IEView (requires very recent IEView, not yet released)
+
+ + bumped version requirement. Beginning with 0.9.9.93, tabSRMM REQUIRES Miranda
+ 0.4 or later.
+
+Version 0.9.9.92 - 2005/03/31
+
+ * plugins like HTTPServer (and all others which try to feed text into the message
+ input area) should now work with the unicode version of tabsrmm.
+
+ ! fixed broken dialog layout on forward message
+
+ ! nicknames may again contain characters like { and } w/o messing up the message
+ log display.
+
+ * status bar remembers typing notification state
+
+ * static avatar code changed. It's now really static, although, internally
+ it is using the dynamic resizing code aswell. Static avatar mode can be
+ selected on the "General" options page, and you can specify a height limit for
+ avatars. Bigger images will be scaled down accordingly. When moving the splitter
+ upwards, the image will be vertically centered within the available space.
+ The splitter position may be adjusted to make enough space for the avatar.
+
+ NOTE: If you set the limit to 0, the avatars are hard limited to 100 pixels
+ in height (MSN appears to have the biggest avatars at 96x96 pixels).
+
+ ! GUI fixes (option pages)...
+
+ + it is now possible to set RTL as default text direction (Message Log options
+ page). The per-contact override is still working though, so if you have RTL set
+ as default, you can switch to LTR for some contacts.
+
+ ! splitter position is now decoupled from the message log settings. There is a new
+ submenu in the protocol menu dropdown on the toolbar where you can setup splitter
+ parameters (global, local, private).
+
+ Global: all tabs / windows use the same splitter position. Note that, when using
+ static avatars, splitter position may need to be corrected so that the avatar
+ can fit.
+
+ Per contact: Each contact has its own splitter position.
+
+ Private: This works as an "per contact" override. When using private, this contact
+ will always use its own splitter position and ignore global settings
+ completely. Useful, if you basically want a global splitter position, but
+ override it for a few contacts (for whatever reason given).
+
+ Also, the splitter menu allows you to disable auto-saving of the splitter position
+ when a tab is closed. "Save now" does exactly this - it saves the splitter position
+ depending on the current mode (global, per contact, private).
+
+ ! fixed some issues with forwarding and non-standard container modes (single window,
+ limited # of tabs/container).
+
+Version 0.9.9.91 - 2005/03/28
+
+ * non-unicode version now sets the IEEF_NO_UNICODE flag for IEview. That may
+ resolve some crash problems.
+
+ * some fixes related to the new icon loading stuff (ico lib).
+
+ * rich edit max size fix for the message log
+
+ * more aggressivly obeys the maxmessagelen flag returned by a
+ protocol to set the maximum allowed size of a message typed into the input
+ area.
+
+ ! fixed typing notify icon in contact list and tray (did appear as blank).
+
+Version 0.9.9.9 - 2005/03/24
+
+ * after quoting, input focus is set to the message input area.
+
+ + added support for the IcoLib plugin. If IcoLib is installed, you can change
+ tabSRMM icons using the GUI provided by IcoLib. You still NEED to install
+ an icon pack and put it into \plugins. This icon pack provides the default
+ icons, and you must not remove it, even if you override icons via IcoLib.
+
+ Iconpacks are still supported, so if you don't use IcoLib, you can still
+ change your icons by installing a different tabsrmm_icons.dll.
+
+ - the feature to load an icon pack at runtime has been removed, because of the
+ IcoLib support. IcoLib is a more comfortable way to change your icons at
+ runtime w/o having to restart miranda.
+
+ ! fixed vertical maximize when taskbar is at the top (hope so)
+
+ * the avatar does no longer react on left button clicks. This stops the flickering
+ aswell. Right button click still works and opens the context menu.
+
+ + added new send mode "send later". Buddypounce plugin is required for this
+ (otherwise it is disabled). It will just pass the message to buddypounce for
+ later delivery. Note: since buddypounce does not support unicode messages,
+ an implicit "force ansi" send mode is used.
+
+ * dialog layout tweaks. It is now possible to get rid of all borders, including
+ the outer tab control padding. The relevant settings are on the "tabs and
+ layout" option page. You can set inner and outer border/padding values. It's
+ a bit hard to explain what they do - best thing is to play around with them
+
+ + new options (message log option page). "Attempt to fix future timestamps.
+ CAUTION: may have side effects. What it does is simple: When appending incoming
+ events during a session (while the window is open), it does not check for the
+ timstamps and just appends them to the log. This will fix the issue, that messages
+ with a timestamp "in the future" will always appear at the bottom of the log.
+ It works only wile the window is open, it does not and CAN not work for loading
+ the history.
+
+Version 0.9.9.9 - 2005/03/19
+
+ ! vertical maximize didn't allow to restore the window from the taskbar
+
+ + new hotkey Shift+Alt T toggles the menubar in the current container (remember,
+ Alt-T toggles the toolbar).
+
+ * vertical maximize can now be set quickly from the menu bar (view menu).
+
+ + added handler for ACKTYPE_FAILED (possibly used by "delete avatar" feature(s)
+
+ * changed smileybutton icon handling - if no button smiley is available in the
+ smileypack, the icon from the icons.DLL is now used by default.
+
+ * when "send formatting info is disabled", formatting buttons are hidden from the
+ toolbar.
+
+ * shift-clicking the user menu button now copies the real UIN of a metacontact (the
+ UIN of the "most online" protocol) and not the metacontact UIN itself (which is
+ pretty useless).
+
+Version 0.9.9.8 - 2005/03/04
+
+ + added icon pack version information. Valid icon packs need to contain a string
+ identifier ("__tabSRMM_ICONPACK 1.0__") in order to be recognized. You can still
+ load icon packs without this identifier, but you'll get a warning message.
+ This was added to avoid problems when specifiyng a DLL which is, in fact, not
+ a valid icon pack for tabSRMM. In such cases, the plugin could even crash badly
+ on startup, which can be a very annoying (and hard to find) bug.
+
+ Also, with version information in the icon pack, future versions of tabsrmm may
+ work with "old" icon packs.
+
+ When you edit an iconpack, DO NOT change the string table identifier. The ordinal
+ number for the string identifier is 101.
+
+ The version check can be disabled on the "tabs and layout" page (just below the
+ option to load a new icon pack at runtime) by unchecking "Perform version check on Icon DLL"
+
+ + added option to "vertical maximize" a container (per container setting). If enabled,
+ a container is maximized only in its vertical dimension, so that the window will
+ take the entire screen *height*, but will keep its current width. When disabled,
+ the container will show default maximize behaviour (taking entire screen).
+
+ ! fixed bug with soft line feeds (SHIFT-Enter) when sending formatting info is enabled.
+
+ * changing message log or other option will no longer wipe the text from the input
+ area.
+
+ ! reset last eventtype and timestamp (for grouping messages) before rebuilding the log.
+ This fixes an issue where the first message in the log could be visible with "in group"
+ formatting (w/o an icon, nickname and long timestamp).
+
+ ! ctrl-enter inserts linefeed when "send on enter" is active. I broke that a few
+ versions ago.
+
+ * if an ansi codepage is set for the current contact (right click the message log and
+ select a codepage), the unicode version now uses this codepage to encode the ansi
+ part of the message. If no codepage is set, the default, system wide, codepage (CP_ACP)
+ will be used. This will only affect the unicode version, the ansi version is always
+ using the current codepage.
+
+ * force ansi send extended to receive - if set, messages received from a "force ansi"
+ contact will ignore the unicode part.
+
+Version 0.9.9.7 - 2005/03/04
+
+ ! re-enabled the "show multisend" menu bar item.
+
+ ! export/import themes now show the appropriate file selection window (open/save as)
+
+ ! fixed send on shift enter.
+
+ ! "Flat message log" now tries to remove static edges from ieview and message input
+ area aswell.
+
+ ! detecting IEView on startup didn't work with some configurations.
+
+ ! When "send formatting info" was active in the non-unicode version, additional
+ linefeeds were sent at the end of each message.
+
+ ! new send mode - force ANSI. When enabled, messages will be sent as pure ansi,
+ using the current codepage. Useful when the client of your buddy has troubles
+ receiving unicode messages. This setting is a "per contact" OVERRIDE and WILL
+ STICK even if you close the message window until you deactivate it.
+ This has only an effect in the unicode version of tabSRMM - the non-unicode always
+ sends ANSI.
+
+ + the protocol menu is back. At the moment, it has only one submenu for configuring
+ the message log. It is now possible to switch between rich edit and IEView "on the
+ fly" while the message window is open. Please note, that these settings are saved
+ to the contacts db record, so you can now override the message log being in use
+ on a "per contact" basis.
+ Example: You have set the default option to use the IEView plugin (message log
+ options). You can now override this setting for a specific contact and force
+ the default message log.
+ (or vice versa, of course).
+
+ + made hotkeys translateable. Please refer to the translation template included in the
+ archive to figure out which strings need to be translated. The hotkeys are at the
+ very end of this file.
+
+ + new hotkey - Alt-T (default). Toggles toolbar quickly.
+
+Version 0.9.9.6 - 2005/02/23
+
+ ! flicker-free formatting button update
+
+ ! changed multisend UI a bit. There is now a new button just right of the send button.
+ It's called "send menu" and looks like a small dropdown toolbar button. If you click
+ it (hotkey is Ctrl-S) a menu will open, allowing you to set the sending mode. 3
+ modes are available at the moment:
+ 1) Default (send to contact only).
+ 2) Send to multiple Users - will open the multisend window, allowing you to choose
+ up to 20 contacts.
+ 3) Send to container - this replaces the /all command (which didn't work well with
+ the new message input box code anyway) and will send the message to all tabs
+ in the current container.
+
+ More "sending modes" may be added in the future.
+
+ The old multisend button is gone, however, if you are in *any* multisend mode, an
+ icon will appear left of the input box, indicating that the message you are typing
+ *may* be sent to more than a single contact.
+
+ ! applying any options does no longer hide the error controls, if the window/tab is in
+ "error state".
+
+ * support for IEView's smiley-selection window added. If you have enabled the support
+ for the "external log" (ieview), the smiley button will now show IEViews smiley
+ selection control. This requires IEView 1.0.1.7 or later.
+
+Version 0.9.9.5a - 2005/02/22
+
+ Bugfix release only.
+
+ ! tab icons were partially broken because of the "load icon pack at runtime" feature.
+
+ ! The menu entry to select in/out icons did not work properly.
+
+ ! when loading a new icon pack at runtime, all message windows will be closed before
+ applying the new icons. A dialog box will inform you about this and you can, of course,
+ cancel the process.
+
+ ! the "protocol menu" button was visible, even it does not (yet) provide any functionality.
+
+ ! The option "do not resize avatars less than x pixels in height" should now work ok.
+
+ ! fixed possible problem with unicode detection.
+
+Version 0.9.9.5 - 2005/02/17
+
+ First, this requires a new tabsrmm_icons.dll format. Icons have been added , so you'll
+ need to upgrade your icon packs. You can use the provided .DLL files as a template
+ as always. The new ordinal numbers are:
+
+ #19 secureim disabled
+ #20 secured connection
+
+ 19 and 20 are only necessary, if you have a tabsrmm compatible SecureIM.dll (which
+ is not yet available).
+
+ #21 this icon is now used for status changes
+
+ + merged std's patch for improved indenting with tabstops. This option works best
+ with the following msg log settings:
+ *) grouping enabled
+ *) message body in a new line
+ *) mark followup messages with timestamps
+
+ It is a new message log option, available either as global or per-contact option
+ (depending on the message log option mode - global or per-contact).
+
+ + merged Ghosts patch for interaction with the SecureIM plugin. It needs an updated
+ Secure IM plugin which is not yet released.
+
+ ! fixed a resizing issue with "windowshade" mode (if you're using windowblinds or other
+ utilities which support "rolling up" a window and reduce it to the title bar only.
+
+ * changed the option pages to use a tab control. Now, tabSRMM inserts not more than
+ 2 entries into the options "tree" of Mirandas main options dialog.
+ * Message windows (all settings concerning the log, containers, layout etc.)
+ * typing notify (the old typing notify dialog).
+ * fonts and colors - still an extra page.
+
+ Thanks to JdGordon for providing the sample source code :)
+
+ + options->fonts and colors: New setting "Extra microspacing at the end of a paragraph".
+ Does exactly this. It adds "n" pixels of additional space after a paragraph and
+ before the grid line (if using them). This is to avoid the rather ugly look with
+ some fonts, where characters like "j, g, y" etc." are sitting directly ON the
+ grid line. You have to tweak this setting depending on the font you are using
+ for displaying messages - some fonts need it, others dont. Set it to 0 to
+ disable the effect.
+
+ + The hotkey Alt+X now works like in other programs - it interpretes the characters
+ preceding the cursor as hexadecimal representation of a valid unicode character code
+ and inserts this character right at the cursor.
+ e.g. type "263a" and hit Alt+X - it will insert a little face.
+
+ ! in status change events, the nickname was displayed with the wrong font/color setting
+ (own nickname configuration).
+
+ * changed ACK code - the "per message window" ack handler is now replaced by a global
+ ack dispatcher.
+
+ + multisend is back, still EXPERIMENTAL though. Use with care and be warned that some
+ stuff, like error handling, doesn't work as it should. Multisend is currently limited
+ to 20 contacts/send - this may or may not change in the future, depending on how well
+ it works.
+
+ ! when creating tabs minimized in the background, the container didn't always flash as
+ it should.
+
+ + added new icon to the tabsrmm_icons.dll ordinal #21 - used for status change messages
+ in the message log.
+
+ + added new color option in the "Fonts and colors" dialog. It is now possible to set the
+ color of the *horzontal" grid lines independently of the background color. The vertical
+ grid lines can not use this color (its a rich edit limitation), but you can disable them
+ if you want.
+
+ + added *basic* theming support. The message log menu (menubar or toolbar button) contains
+ 2 new entries which allow you to export or import all visual settings to/from .ini
+ format files. The following things are exported:
+ * all fonts (including colors, style, charset etc..)
+ * all background colors
+ * all message log formatting options.
+ The files are using a .tabrmm extension but are standard plaintext .ini files.
+
+ + added extra font setting for error messages. Previously, they were using the same font
+ as status changes did. The new font setting is appended to the font list, so you don't
+ need to reconfigure everything this time :)
+
+ * unified all eventhooks - finally.
+
+ + added simple text formatting routines for formatting *bold* /italic/ and _underline_
+ in the message log. Some code was taken from the textformat plugin and adopted to
+ tabSRMM (unicode aware, some small changes)-
+
+ * added message log options: "use symbols instead of icons". This will use symbols
+ from the webdings font for marking events in the message log, instead of drawing
+ icons. The advantage is that this is WAY faster and uses only a fraction of the
+ memory consumed by the icon code. There are 2 new font settings (symbols incoming
+ and symbols outgoing) - you can set the size+color, but not the font itself (it
+ is forced to use the Webdings symbol font).
+
+ - removed static avatar layout. Avatars are now always dynamically resized and the layout
+ is constantly tweaked to avoid a "damaged" tool bar. A new option is available
+ under Options->Messaging:
+ [ ] Always keep the button bar at full width
+ This option, when enabled, will prevent the avatar from using toolbar space. Its
+ useful if you have enabled the formatting buttons, because they will increase the
+ space needed on the toolbar significantly.
+
+ [ ] Do not resize avatars less than [___] pixels in height.
+ When opening a window/tab, the avatar will be kept in its original size when it is
+ less than x pixels heigh (where x is configurable). The splitter position will be
+ set so that the avatar can be drawn unresized.
+
+ ! fixed dividers screwing up linespacing sometimes.
+
+ * UIN is now cached for non-metacontacts (saves service calls at every status change and
+ titlebar update.
+
+ * UIN can now be shown in the status & title bar. The UIN button is gone from the tool-
+ bar.
+
+ * changed toolbar code. Its no longer possible to hide button groups separately. You
+ can now quickly show/hide the toolbar from a menu entry (view->tool bar) or from the
+ container options dialog. Toolbar is also no longer a global, but a "per container"
+ setting, so you can have different configurations in different containers.
+ Toolbar resizing and button hiding is now dyanmic. The layout code will hide less
+ important buttons when there is not enough space.
+
+ + new option -> Tabs and layout: Flat message log. When checked, the message log will
+ appear w/o a border or static window edge.
+
+ + ability to configure which buttons should be hidden first when the available space
+ on the button bar is not sufficient to display all buttons. You can choose between the
+ formatting controls and the standard buttons. You can also choose if you want the send
+ button to be hidden automatically.
+
+ * The "add contact" button is gone from the standard toolbar. For contacts which are not
+ on the contact list, additional controls will be shown "on demand", including a button
+ to add them.
+
+ * improved formatting code - you can now write something like _this_is_nice_ and the
+ formatting code will ignore tags within words. Options->message log->Format whole words
+ only. In general, this will ignore formatting "tags" (*/_) within words, which means
+ that you can only format whole words.
+
+ + it's now possible to change the icon theme "on the fly". You can load a new icon .dll
+ under Options->Message Window->Tabs and layout. All icons will be updated "on the fly".
+
+Version 0.9.9.4 - 2005/01/24
+
+ + added support for the snapping windows plugin. Yeah, even if I personally HATE
+ snapping windows, its done. Why? Because this great plugin makes it so easy -
+ a single line of code is enough :)
+ You can find this great plugin here:
+ http://www.miranda-im.org/download/details.php?action=viewfile&id=923
+
+ However, its off by default, you need to activate it by checking the option
+ under Options->Message sessions->Message containers.
+
+ * changed window flashing code. Its now using FlashWindowEx() which means that
+ tabSRMM won't work on Windows 95 anymore, but I don't think thats a problem :)
+ The advantage is a code which is less complex and saves resources as well (the
+ old code had to deal with timers for flashing the windows, the new code doesn't
+ need to do this anymore).
+
+ Another advantage is that you can now set the number of flashes (only applies to
+ containers which are using the "default" value and are NOT set to flash forever)
+ and the flashing interval. You can find both options under Options->Message sessions->
+ Container options.
+
+ ! The option "use contacts local time" should no longer break message grouping when
+ the adjusted time of the buddy is "in the future".
+
+Version 0.9.9.3 - 2005/01/20
+
+ + new "per container option": "Use static icon" - if checked, the
+ container will use a static icon instead of showing the contacts
+ status icon. The icon will be obtained from the tabsrmm_icons.dll
+ using ordinal #18 (IDI_CONTAINER). If you're using a modified
+ tabsrmm_icons.dll, you'll have to reshack it and supply a valid
+ icon.
+
+ The message icon will still be visible when the container has unread
+ events in one of its tabs, but the status icon(s) will be replaced by
+ the static container icon.
+
+ * the tabsrmm_icons.dll will now be recognized in both the .\plugins and
+ .\icons subdirectories.
+ Order of search is:
+ a) .\plugins
+ b) .\icons
+
+ ! just another focus fix - in some cases, containers didn't gain the focus
+ when they actually should. Opening sessions using hokeys (HotContact plugin)
+ should now work again.
+
+ ! metacontacts support - don't force a protocol when the MetaContacts protocol
+ returns an error.
+
+ ! metacontacts support - check for forced protocol at tab creation.
+ PLEASE UPDATE your MetaContacts plugin -> at least 0.8.0.8 is now required
+ by tabsrmm.
+
+ + new option: "Flash contact list and tray icons for new events in unfocused windows".
+ This is some kind of "icq style" event notification - the contact list and
+ the tray icon will flash when you receive a message in a window which is not
+ focused. Only the first event for each contact will trigger the flashing and
+ it will go away when the tab receives the focus. You may also click the tray icon
+ or double click the contact in the clist to activate the tab.
+
+ You can find this option under "Options->Message sessions->Messaging"
+ Note that, this MAY cause problems with other events like incoming file transfers.
+
+Version 0.9.9.2 - 2005/01/18
+
+ ! fixed - status icon on the container did not appear when the title bar
+ was forced to not show the buddy status text.
+
+ ! the dialog box for choosing the autopopup status modes is now translateable.
+
+ ! hopefully fixed the long standing bug which was causing the container to
+ steal the focus, even when it was created minimized on the taskbar.
+
+ * NEW SEND QUEUE system - work in progress, handle with care :)
+ multisend is temporarily disabled, because it doesn't really work right
+ now, but in the end it should, and it should work even better than the
+ old system.
+
+ The rewritten send queue may cause troubles with error handling, so please
+ backup your old tabsrmm.dll first. You have been warned.
+ Also, icon feedback may be broken as of now.
+
+Version 0.9.9.1 - 2005/01/14
+
+ ! fixed a few translation bugs (menu bar, the new status mode dialog)
+
+ + new option: typing notify->Flash window once on typing events.
+ This can be disabled to avoid the flashes when a typing notification
+ arrives...
+ It is enabled by default and replaces the old option to enable the
+ typing notify window icons (which is gone).
+
+ ! manually opening a container does not give him a message icon instead
+ of the status icon.
+
+ * when a container shows a message icon indicating unread events in one
+ of its tabs, the typing notify icon may temporarily override the message
+ icon.
+
+ + meta contact support: When the toolbar button is set to show the full UIN,
+ it will now display the UIN of the active subcontact, instead of the
+ MetaContact ID# (which is a simple number and not really important to know).
+
+Version 0.9.9.0 - 2005/01/08 - BETA
+
+ This is the first official "BETA" version of tabSRMM. It will be released on
+ Mirandas plugin page as well as my sourceforge project site. There are a few
+ known bugs left, but otherwise the plugin works fine and has lots of new options
+ and features since the last "official" release which was 0.0.8.
+
+ * removed debugging option to disable micro linefeeds
+
+ * minor layout changes (avatar field alignment and tab control client area)
+
+ * removed obsolete code for layouting the multisend splitter in the old way.
+
+ * reviewed all dialog boxes and maxed the horizontal space for most
+ configuration options (checkboxes mainly) to make translation into other
+ languages easier.
+
+ * included new version of NewEventNotify which should help against double
+ popups when using the metacontacts plugin.
+
+ * the option "Remove trailing empty lines" is now on by default.
+
+ + added basic support for the metacontacts plugin. There is a new status
+ bar indicator showing the protocol in use. It is there for all contacts,
+ but for metacontacts it opens a context menu if you click the protocol
+ icon with your right mouse button.
+
+ * changed internal typing notification code - it's now using the popup configuration
+ setting from the current container so that you can have the baloon-type
+ tray notifications or flashing icons based on the state of the current window
+ (minimized, unfocused etc.)
+
+ ! the error control buttons were not translateable. Fixed.
+
+ * metacontacts support: unforce protocol added to tab closing code and the
+ context menu in the status bar.
+
+ * tabsrmm can now display notifications and debug messages using ballon-type
+ tray notifications. This feature no longer depends on the popup plugin.
+ See: Options->Message Session->Messaging->Notifications. Three settings are
+ available:
+ * None (disable them completely)
+ * Tray notifications (use baloon-style tray tooltips)
+ * Popups - use popups. If the popup plugin is not installed, it will fall
+ back to tray notifications.
+
+ * the included NewEventNotify plugin can now use the OSD (on screen display)
+ plugin to display its notifications about new messages. You need to have
+ the OSD plugin installed and you need to actiavte it under:
+ Options->Popups->Event Notify->Use OSD plugin instead of popups.
+ NOTE: this is experimental - the osd plugin is very new and may contain
+ bugs.
+
+ + added a tooltip to the new status bar panel - it shows your own nickname
+ and the active protocol.
+
+ ! (hopefully) fixed a possible "crash at exit" problem.
+
+-----------------------
+
+ + session stats tracking code added. tabSRMM will now track the stats of a
+ session, including the session length, the number of sent and received
+ messages, the total amount of sent and received characters, and the number
+ of delivery failures.
+ There is no code (yet) to display these stats though.
+
+-----------------------
+
+ + merged bids crash fixes for the smileyadd plugin into my own version of
+ smileyadd for tabSRMM.
+
+ + added versioninfo block to the resources.
+
+ + added an option to specify on which status modes, windows and tabs may be
+ created automatically on incoming events.
+ Check "Options->Message sessions->Message tabs->Setup Status modes...
+
+ * changed the title bar + icon notification code. The message icon is now ex-
+ clusivly used for indicating a waiting event in a tab. Typing notifications
+ will be shown in the title bar, unless the window is focused.
+ Typing notification messages + icons should no longer remain when the window
+ receives a "typing off" message.
+
+ Version 0.0.9.5 - 2005/01/04
+
+ ! fixed close tab on double click
+
+ ! fixed missing PREF_UNICODE on resend attempts
+
+ * new event for the event API - its fired before a message is sent. An external
+ plugin can use it to alter the content of the message input area.
+ This is for developers only - The event is sent via the MSG_WINDOW_EVT_CUSTOM
+ event type and the tabMSG_WINDOW_EVT_CUSTOM_BEFORESEND subtype is passed
+ via the evtCode field of the TABSRMM_SessionInfo structure. A pointer to this
+ structure is passed via MessageWindowEventData.local.
+ (see m_tabsrmm.h and m_message.h for further details).
+
+Version 0.0.9.4 - 2004/12/02
+
+ * small change in smileyadd and tabSRMM's interface to smileyadd as an attempt
+ to fix a rare bug with smiley background color in chat.dll windows.
+ YOU NEED TO REPLACE smileyadd.dll with the version in the archive, otherwise
+ smiley backgrounds in tabsrmm will not work when using the individual background
+ colors.
+
+ + new option - > auto close tab after x minutes of inactivity.
+ Does exactly that. Tabs don't get autoclosed when:
+ a) unread messages are there (the tab icon is flashing)
+ b) the input area contains characters
+
+ Things, which reset the inactivity timer:
+
+ a) typing in the input area
+ b) new message arriving
+ c) activating/focusing the tab
+
+ ! fixed disappearing avatar when applying options
+
+ ! fixed right-alt-v does no longer paste.
+
+ * quoting does no longer replace the entire typed message. The quoted text is now
+ inserted at the caret location.
+
+ * You can now disable "Send on SHIFT Enter".
+
+ * The small timestamp for grouped messages can be replaced by a simple ">" character.
+
+ * added a new icon pack to the archive which you can find in the contrib directory.
+ This iconpack was contributed by Faith Healer. Thanks for sharing :)
+
+ + added the new event api also found in SRMM to support external plugins.
+
+ + added new option to delete temporary contacts when closing a session.
+
+ + SHIFT-INS now behaves like CTRL-V and pastes plain text.
+
+Version 0.0.9.3 - 2004/11/14
+
+ * unified the unsent and charcounter displays on the statusbar. The new format
+ is now: x/yyyy where is is the number of queued messages (normally 0) and yyyy
+ the number of chars typed into the input box.
+ Reason: Make space on the status bar for new indicators coming in the future.
+
+ * When using dynamic avatar resizing, the maximum size of an avatar is no longer
+ limited to 300 x 300 pixels. It can be up to 1024x768 pixels (not recommended though,
+ as this will use quite some memory) and will be downsized to match the splitter
+ position.
+
+ * the dynamic avatar resizing now enforces a horzontal size limit - the avatar cannot
+ gain more than 80% of the width of the window width so the message input area
+ will never completely disappear because of the avatar taking all the available
+ space. Note that this may corrupt the aspect ratio of an avatar picture.
+
+ ! fixed severe bug with avatars (messing up contacts handle)
+
+ * added smart avatar resizing - when using the dynamic avatar resizing option,
+ the layouting code will now take care that the avatar won't take too much space
+ of the button bar. it will try to keep all the button visible.
+
+ * threaded streaming (icon + smiley replacement) is now only used for filling the
+ initial message log. For adding single messages to the log, the threading stuff
+ is a waste because of its overhead.
+
+ ! a divider should not appear at the very beginning of the message log, even if the
+ session qualifies for a divider because of its unfocused state.
+
+ Version 0.0.9.2 - 2004/11/13
+
+ * various avatar layouting fixes.
+
+ * removed "Send on double enter" as this is broken due to the rich edit input
+ area.
+
+ * fixed MingW32 Makefile - works with GCC 3.4.1 and recent MingW32 builds.
+ Note, compiling with GCC results in a dll about 60-70 k larger than the
+ Visual C++ build - this is normal and no reason to worry...
+
+ * the "unsent" display did not update properly when changing tabs.
+
+ * the small line just below the menu bar (menu bar separator) is now coupled
+ with the visibility of the menu bar. It's invisible while the menu bar is
+ hidden.
+
+Version 0.0.9.1 - 2004/11/11
+
+ * RTL didn't fully work for the message input area
+
+ * added small 2pixel margins to the message input area to make it look better
+
+ * If you're using per-contact message log settings, you can now apply the current
+ log formatting options to all your contacts by choosing the option from the menu.
+
+ * 2 new options for globally setting avatar display mode:
+ * On, if present -> show avatar if there is a valid one
+ * Globally off. Never show any avatar. No exceptions.
+
+ * dynamic avatar resizing added. Check this under options -> messaging.
+ It will resize the avatar so that it fits depending on the current splitter
+ position. Splitter setting is enforced, so it will never change because of
+ the size of the avatar.
+
+ * The unicode version is no longer using a RichEdit20W control for the input
+ area. Instead, its using the "A" version in conjunction with the extended
+ API for fetching and setting unicode strings.
+
+Version 0.0.8.99 - 2004/11/07
+
+ * the unicode version now uses utf-8 encoding to store various unicode settings
+ in the DB. No more blobs.
+
+ * ability to show the tabs at the bottom. Looks fine with classic windows theme,
+ but may look strange with visual styles.
+ NOTE: Please don't complain - the official word from MS is that bottom tabs
+ are UNSUPPORTED under Windows XP when using visual styles. So either find
+ a style with "symmetric" tab skins (they look fine with bottom tabs in most
+ cases) or don't use bottom tabs.
+ Or use classic theme :)
+
+ * New menubar added. It can be hidden (as a per container setting) and contains
+ many options which are normally only accessible via various option pages.
+
+ * input area is now a rich edit control instead of a normal multiline edit box.
+ It was changed to allow future additions like text formatting
+
+ * new avatar setting: Disable automatic Avatar updates. You can find it in the
+ avatar menu on the toolbar and in the new menu bar. This setting is "per contact"
+ only and will prevent automatic avatar changes, if you have, for example, set
+ your own custom picture for a specific contact.
+
+ * simplified the font settings a bit. There are now less than before and they
+ were moved to another DB module path. So you will probably have to reconfigure
+ your fonts :(
+
+ * fast copy the UIN to the clipboard by clicking on the usermenu button (second
+ button from the left) while holding the shift key.
+
+ * Global settings for avatar display added. See Options -> Messaging. There are
+ 3 modes available to activate avatars per default, per default for protocols
+ which support them, or manually per contact.
+
+Version 0.0.8.98 - 2004/10/17
+
+ * fixed middle click close did not respect the "warn onl close" setting.
+
+ * fixed small cosmetical issue with the status bar tn icon.
+
+ * fixed typing notify icon not clickable if char count panel was disabled.
+
+ * changed font and color configuration dialog. It now uses the same system
+ also used by the contact list font configuration screen. It's more
+ convient and easier to setup. You will probably have to re-setup some of
+ your font and color options.
+
+ * redone the message log options dialog. Now, with the fonts moved to their
+ own page, this option page is less cluttered and easier to use.
+
+ * changed the code which loads the smiley button icon. It now uses a button-
+ icon (if the smileypack contains one). If not, it tries to load the :) icon
+ and resizes it to 16x16 (if necessary). If all fails, a default icon from
+ the icon.dll is used.
+
+ * made the thin (1pixel) grid lines optional. They are causing troubles with
+ some versions of the rich edit control. If you happen to get "invisible"
+ messages at the end of the log, turn off the "Thin grid lines" option.
+
+ * changed the way indent works. There is now also a right-indent value.
+ If no indent value is given, a default of 3 pixel is used for left and right
+ margins.
+
+ * ARGH, don't free() a pointer which might be needed ages later :)
+ This one was ugly, causing crashes after a failed message delivery.
+
+ * redone the error controls. They are now at the top of the window, so there
+ is no more need to hide the button bar in order to show the error controls.
+
+ * New message log formatting option: Group subsequent messages. If this is on
+ and you receive or send more than 1 message in a row, then those messages
+ will be "grouped". There will be no divider (grid line) between the grouped
+ messages, and only the first one will show the full header (nick and complete
+ timestamp). Subsequent messages will only show a short timestamp (no date).
+
+ To make this look "good" you will probably have to play a bit with timestamp
+ and indentation settings.
+
+ * the message log code now caches rtf font formatting strings for the. This will save
+ a few dozens of DB accesses and font calculations PER EVENT (message) when
+ building the message log. The speedup when loading 100 old events is
+ noticeable, even on fast machines.
+
+ * its now possible to sync sounds for incoming message with the current container
+ option
+
+ * improved "scroll to bottom" code. Works better when aligning avatar settings.
+
+ + added ability to use "relative" timestamps like "Today" and "Yesterday"
+
+ + added option to display date in "long" format (depends on your regional settings)
+
+ * various fixes for the rich edit streaming code. All options, including thin
+ grid lines should now work for the Windows XP SP2 version of the rich edit
+ control.
+
+ * moved the status bar to the container window. Previously, each tab had its own
+ status bar, which is a waste of resources. Now, they have to share a single
+ status bar.
+
+ + added EXPERMIMENTAL multithreading for replacing icons and smileys in the message
+ log. The option is on the messaging options page and is off by default.
+
+
+Version 0.0.8.95 - 2004/10/06
+
+ * sendquue stuff added. No more disabled input box while a message is sent.
+
+ * more smileyadd changes, tabSRMM now has "native" support for a custom version
+ of smileyadd. It also places its own smileybutton.
+
+ * icons splitted into a resource DLL. You NEED TO COPY ONE OF THE INCLUDED
+ tabsrmm_icons.dll to your Miranda plugin folder, otherwise you won't get
+ any icons.
+
+ + new feature: you can toggle your own typing notifications FOR THIS CONTACT
+ ONLY by clicking the icon in the lower right corner of the window.
+
+ NOTE that this only toggles the checkbox also found in the main miranda
+ options, so it will NOT force sending tn to contacts which are, for
+ example, not on your visible list.
+
+ * a small (2 pixel) padding has been added to the message log window, even
+ when the normal indent is switched off.
+
+ * grid lines are now only 1 pixel in width (they were 2).
+
+ + the smiley button now shows the default smiley icon used for the :) smiley
+ (if available). The icon will be sized down to SM_CXSMICON/SM_CYSMICON
+ if necessary in order to fit on the button.
+
+ If no default icon is available in the smiley pack, a fallback icon from
+ tabsrmms own icon.dll will be used.
+
+ * subclassed the tab control to make "close on middleclick" possible.
+
+Version 0.0.8.92 - 2004/10/02
+
+ * disabled the streaming thread stuff - it was causing problems which could
+ be fixed, but require some more work "under the hood".
+
+ * simplified divider code. No need to stream en extra event for these little
+ lines.
+
+ * displaying message log icons should be way faster now
+
+ * fixed smileybutton appearance somewhere in the message log when button bar
+ was disabled.
+
+ * MSN avatars now update the mTooltip "Photo" page (if present).
+
+Version 0.0.8.91 - 2004/09/26
+
+ ! message log icons are now forced into 16x16 format
+
+ ! the message log icon code now only searches the appended text when a new
+ message arrives which results in much faster operations for logs holding
+ a huge amount of text.
+
+ + new option to limit the maximum number of tabs per container. This works
+ only for unassigned contacts (contacts which open in the default container)
+ and is not available when using the CLIST group container mode (grouping
+ your contacts according to your clist group configuration and then breaking
+ them up again wouldn't make sense anyway).
+
+ Set the limit to 1 if you want one window per contact.
+
+ * changed the EVENTTYPE for the status logging code. This will avoid such events
+ beeing classified as "SMS" events.
+
+ NOTE: if you experience troubles with the log ignoring the color/font settings
+ for old and new events: This is a result of this change and it will AUTOMATICALLY
+ go away as soon as there are no more old status change events in the log. So
+ you could for example limit the number of old events loaded...
+
+ There is also a new "NewEventNotify.dll" which you need to install in order to
+ avoid the "unknown event" popups if you have:
+ a) status change logging enabled, and
+ b) enabled the NewEventNotify option to get notifications on "other" events.
+
+ * loading the avatar is now using its own thread to avoid a frozen main thread
+ while loading remote pictures.
+
+ + new option on "message tabs" options page: You can remove the static edges on
+ the splitter and the line just below the message log to get a completely "flat"
+ looking toolbar.
+
+ + new container mode: "Use single window mode". This will create implicit containers
+ for each session you open. It will completely ignore all container assignments
+ you have made (they will stay intact though, so you could switch back to
+ manual or CLIST group mode at any time) and open a single window per contact.
+
+ + added msg log icon for status changes (global "user online" icon.
+
+ + added multithreaded streaming. Now, all streaming is done by a separate thread
+ which frees the main thread from doing this. This can avoid a "frozen" main
+ thread and unresponsive ui when large amounts of data need to be streamed into
+ the message log window.
+ This is EXPERIMENTAL, it may cause other unexpected problems.
+
+ * disabled UNDO functionality in the Rich Edit control (message log). It's not
+ needed (the control is read-only) and just wastes resources.
+
+ + new icon set for the button bar. Contributed by a member from the Miranda
+ community. Very nice and colorful icons, the button bar looks a lot better
+ now :)
+
+ * more tightly interoperration with smileyadd. tabSRMM now has its own smiley
+ button. You can also change smiley replacement "on the fly" and do no longer
+ need to restart miranda. The code will detect if smileyadd is available and
+ installed. Please DISABLE the button inserted by smileyadd under
+ Options->Events->Smileys unless you want the button appear twice :) The new
+ smiley button also solves the "focus lost" problem, now the input area
+ regains focus after inserting a smiley.
+
+ * button bar icons are now loaded once at plugin startup. There is no need for
+ each tab having its own copy of the icons, since those icons are static and
+ never change during the "lifetime" of the plugin.
+
+ * its now possible to disable the multithreaded streaming code in case you have
+ problems. It's enabled by default and you can disable it on Options->Messaging
+ You NEED TO RESTART miranda if you change this setting.
+
+Version 0.0.8.9 - 2004/09/24
+
+ + new "mIRC style" tab selection hotkeys. ALT-1 to ALT-0 will select the
+ corresponding tab. ALT-1 will select the leftmost (first) tab, and ALT-0
+ the rightmost (last) tab. Maybe confusing if you have more tabs than
+ actually fit on a single row.
+
+ + added a few pixels of padding "inside" the message log so that characters
+ won't touch the inner border of the rich edit control anymore.
+
+ * container system menu: rearranged menu items so that close will always be
+ at the bottom of the menu (hinted by OnO).
+
+ * new option on the message log page: Use Arrow icons: This will replace the
+ message icons in front of each message with small arrows showing the direction.
+ A green arrow marks outgoing, and a red arrow incoming events.
+
+ * experimental fix for highlighting issues when using individual background
+ colors. Trailing lines are now removed from the message if they are empty.
+ It's still possible to have empty lines within a message, but if the last
+ line of the message body is *completely* empty, it will be removed.
+
+ This solves the problem which occured with individual background colors
+ where those empty lines were actually drawn with the default background
+ color (very ugly).
+
+ You need to activate this explicitely on the "Message Log Options" page.
+
+ * avatar changes: It's now again possible to choose an avatar from the message
+ window if you do not have mTooltip installed. Just click the picture menu
+ button (left of the history button) and choose "Load a local picture as avatar".
+ Note that the avatar section must be visible (toggle it on before), otherwise
+ the menu item will be greyed out. Selecting the avatar from the message window
+ will also write the picture to the mTooltip setting (if available), so you
+ don't have to change the picture twice if you're using mTooltip plugin.
+
+ * fixed CTRL-backspace. If there are more lines than the input box can actually
+ display w/o scrolling, ctrl-backspace was always setting the cursor to the
+ start of the text. Now, the cursor is always placed at the end.
+
+ * changed MSN avatar code. Now, a single event hook cares about all sessions. This
+ should avoid performance problems on slower machines with lots of MSN sessions
+ opened.
+
+Version 0.0.8.8 - 2004/09/21
+
+ ! fixed a few layout issues with multisend clist not updating correctly
+
+ + added support for the new avatar notifications of the MSN protocol. This
+ will require very recent builds of MSN and Miranda. Avatars are now up-
+ dated in "real time" whenever they change.
+
+Version 0.0.8.7 - 2004/09/19
+
+ * new icon code for showing message log icons. It uses code from smileyadd
+ to insert icons as ole objects so they can use the "proper" background color
+ if you're using different colors for incoming and outgoing messages.
+
+ * message input area has now a "static edge" instead of the frame. Looks better
+ and matches the border style of the message log (also a static edge type).
+
+Version 0.0.8.6 - 2004/09/17
+
+ ! fixed bug with autoswitch tabs and tabs created in the background (they
+ didn't flash after autoswitching to another tab).
+
+ ! layout changes. It's now possible to hide all tab control borders if
+ multiple tabs are opened by setting the value for "Tab control border"
+ to zero (Message tabs options page).
+ If only one tab is open and you have configured tabSRMM to hide the tab
+ bar, then no borders will be visible as well.
+
+Version 0.0.8.5 - 2004/09/16
+
+ + added individual background colors for incoming and outgoing messages. Set
+ the colors under Options>Message Sessions->Message log and activate the
+ option. You can also activate the "grid" which will show grid-like lines
+ between the messages. The grid uses the default background color.
+
+ Known issues with this feature: a)Smileys are rendered with the default bg
+ color, because smileyadd cannot know about the new colors (it assumes that
+ the message log window has only one background color). Workaround: don't use
+ high contrast colors between the default and the individual colors. For
+ example, use a light grey as default color and a light blue/red for
+ the individual colors.
+ b) Icons break the background color stuff. No idea why and how to fix it
+ so if you care then don't use icons and the individual bg colors at
+ the same time.
+
+ * changed buddypounce interoperability. Now, tabSRMM does no longer add the
+ messages to the history. Instead you get a notification about the message
+ being sent to buddypounce for later delivery. Buddypounce adds them to the
+ database when it actually sends them.
+
+Version 0.0.8.4 - 2004/09/14
+
+ * changed avatar code.
+
+ + new mouse "gesture". Double click the button bar while holding the left ALT key
+ to show/hide the button bar and its controls. This is only temporary and will
+ not affect the global options under Message Sessions->Messaging. It will also
+ not be saved anywhere.
+
+ + dividers can now use the popup configuration (basically, this wil dividers
+ make appear in tabs which would also trigger a event notification popup,
+ based on the containers popup configuration mode).
+
+ + avatars are now updated in "real time" when you change the picture on the
+ photo page.
+
+Version 0.0.8.3 - 2004/09/13
+
+ + added a "send later" button to the error dialog which appears when a message
+ send fails. Clicking it will hand over the message to the buddy pounce
+ plugin for later delivery. Obviously, this feature requires the Buddy
+ Pounce plugin to be installed, otherwise the button will be inaccessible.
+
+ + added new option -> "use contact list group names for organizing containers"
+ You can find this option on the Container options page under Options->Message Sessions.
+ If this option is enabled, tabSRMM automatically assigns contacts according to
+ the group in which they are. Containers with the name of the group are created
+ automatically if needed. Contacts which are not in any group will be opened in
+ the default container.
+
+ Also note that, if this option is enabled, the options to attach contacts manually
+ are disabled, so you cannot change the container assignments until you disable
+ the option again.
+
+ Using this option will NOT overwrite assignments you have created manually.
+
+Version 0.0.8.2 - 2004/09/11
+
+ * moved all option pages to a new group. "Message Sessions".
+
+ * the options concerning auto creation of tabs are now disabled if the "auto
+ popup" feature is checked. Remember, auto-popup always overrides the
+ "background create" features.
+
+Version 0.0.8.1 - 2004/09/11
+
+ ! fixed "ding" sound when closing the last tab
+
+ ! fixed the option pages (apply button was always highlighted)
+
+ * removed the global container options page, because it was confusing more than
+ anything else :)
+ Container options can now only be changed by using the container options
+ dialog box, which is available by:
+ a) the system menu of any container
+ b) the tab control context menu (right click any tab)
+ c) the button bar context menu (right click an empty space on the button bar)
+
+ ! don't autoswitch on status change events.
+
+ * autoswitch now also works when creating tabs in the "background" and the
+ container was minimised to the taskbar.
+
+Version 0.0.8 - 2004/09/10
+
+ + merged "/all" mod by JdGordon. Allows you to send a message to all tabs within
+ the current container.
+ Just type /all message and the message will be sent to everyone in the current
+ container.
+
+ WARNING: Depending on the IM network and their terms of use, this might be
+ considered as some kind of mass-messaging. Some networks may disconnect you or
+ even ban your account for some time in that case. I suggest that you do not
+ use this feature with a lot of contacts opened.
+
+ + container transparency added.
+
+ + container option dialog added. Most container settings are now saved on a "per-
+ container" base. This includes settings for: titlebar on/off, hide tabs when only
+ one tab is presend, flashing mode, sticky (stay on top) and the service report
+ facility.
+
+ There are still settings in the Prefrences page, but these will only affect new
+ containers.
+
+ * redesigned the option pages. There are now 2 pages - "Message tabs" for the
+ general options and "Message Containers" for the container-specific settings.
+ The old option page was getting too messy...
+
+ + added new feature: deferred timeout error handling.
+ To use this feature, the following things must be present:
+
+ * popup/popup Plus plugin must be active.
+ * popups must not be disabled.
+ * the option must be activated under Options>Message tabs>use popups for timeout errors
+ messages.
+
+ This is how it works: If the tab in which the error occurs is not active, then it
+ will NOT show the error dialog box. Instead, it will display a red popup and change the
+ tab icon to a red "X". The popup will show the error text reported by the protocol
+ and the icon will stay until you activate the tab.
+
+ ! fixed: options were only available with "expert mode settings" enabled.
+
+ * changed context menu. Removed the additional entrys from the right-click menu in the
+ message log. Now, the tab-context menu includes them.
+
+ + The tab-context menu is now also available by right-clicking the button bar.
+
+ + implemented rename/delete containers.
+
+ + added shortcut: Ctrl-W -> closes the active tab.
+
+ + added icon flashing for tabs created in the background.
+
+ * use contacts local time is now a per-contact setting. It is available from the new
+ "message log options" menu which you can reach by clicking the button.
+
+ * changed most of the message log options to "per contact" settings. You WILL most
+ likely need to reconfigure the defaults under Options->Messaging log (only applies
+ to yes/no switches, all font settings are still global and will remain so).
+
+ There is a new button which opens a pulldown menu when clicked. Basically, all
+ these settings can now be saved on a "per contact" basis. If you don't like it this
+ way, you can tick the option "Ignore per-contact settings under Options->Message tabs.
+
+ - removed the RTL button. The switch can now be found in the newly introduced
+ "Message log options" menu.
+
+ ! made "autosave msg" unicode aware. Note that, the unicode version of tabSRMM uses
+ a different way to store the message. This means, that you will not see what you have
+ saved with the non-unicode version and vice versa.
+
+ ! fixed quoting for unicode.
+
+ ! fixed bug with container options dialog not showing when container was minimized to
+ the taskbar.
+
+ * made the /all command unicode-aware
+
+ * fixed container delete/rename functions for the unicode version
+
+ * allow for gloabl splitter position (check the message log options menu)
+
+ + new container setting system added. Container names are now fully unicode-aware.
+ The unicode version uses different places to store its setting, so it will not
+ collide with settings written by the non-unicode version.
+
+ * more changes for "per-contact" message log options.
+
+ + new option: it is now possible to have containers created minimized, if you also
+ have the option "Auto create tab on event" activated. Just check "Also create
+ container, but do not activate it".
+
+ ! attempt to fix the ALT-S problem. The new layout does no longer allow for trans-
+ lating the "Send" button. Since this is a picture button anyway and does not
+ display any text, this solution should be fine.
+
+ * better visual cues for typing notification. If minimized or in the background,
+ the container now changes its title to show who is actually typing.
+ The "stuck" titlebar icon should no longer occur.
+
+ * internal layouting changes. new option to set left and right borders between window
+ border and the tab control. Set this to zero if you want the smallest possible border.
+
+ + added a "close container" entry to the tab-context menu to make closing a container
+ easier if title bar is hidden (remember, the tab-context menu is also available by
+ right-clicking the button bar).
+
+ ! fixed easydrag - window should no longer detach from the mouse pointer while left button
+ is still down.
+
+ + ability to hide statusbar. This is a global setting available from Options->Message tabs,
+ but you can override it on a per-contact base from the message log options menu.
+
+ + New submenu added to the tab context menu. It contains a list of all available
+ containers so you can quickly attach a message tab without using the container attach
+ dialog.
+
+ ! fixed the "warn on close" feature for containers. It was possible to force more than
+ one warning message dialog.
+
+ - removed old message layout.
+
+ * New layout option: "Multisend CLIST splits message history only"
+ If enabled, the embedded contact list will only take horizontal
+ space from the message history window. Everything else will retain its full width.
+
+ * tabSRMM is now a "conversion style only" message module. The old single send/read
+ modes have been disabled.
+
+ * The "Warn on close tab" feature does no longer ask if you exit miranda with
+ message windows opened.
+
+ * double-clicking the empty space on the button bar will now minimize the container.
+ Holding CTRL while double-clicking will close the container and holding down SHIFT
+ will toggle the titlebar.
+
+ ! fixed bug - double clicking an inactive tab caused problems when more than a single
+ row of tabs was shown in the control.
+
+ + added: "enable popups if unfocused". A new "per container" setting which will basically
+ do the same as "enable popups if minimized" but extend this to containers which are
+ only sent to the background but may still be visible on screen (at least, partially).
+
+ * if status bar is hidden, typing notify will change the tab icon on the active tab as
+ well.
+
+ + implemented a way to log and display status changes in the message window. You can
+ enable this globally under Options->Messaging log. There is however an option to override
+ the setting on a per-contact basis. Choose "Never log status changes" from the message
+ log options menu to disable it for a contact. You may NEED to disable it for RSS
+ contacts, because the status change events, if logged to the history, may confuse
+ the RSS plugin.
+
+ * the bottom limit for the horizontal splitter now takes into account whether the status
+ bar is hidden or not.
+
+ + two new hotkeys added: alt-left and alt-right for easy tab switching
+
+ * changed ESC to "minimize container". Use the more stadardized CTRL-W or CTRL-F4
+ shortcuts for closing tabs or ALT-F4 to close the entire container.
+
+ * added one more option for even more popup configuration. Please read POPUPS.TXT
+ for more information on this topic. it's getting complex :)
+
+ + added "input history". You probably know this from irc clients like mIRC. Basically,
+ the input line remembers the last n messages you sent (where n can be configured in
+ the options). By pressing CTRL-Arrow Up or CTRL-Arrow Down you can scroll through
+ the stored messages quickly.
+
+ * improved the input history:
+ 1) cursor is always at the end of the recalled message.
+ 2) the input history now saves the contents of the input area (if any) when replacing
+ it with an entry from the history. Scrolling down "past" the end of the history
+ will restore the previously saved content.
+
+ + added "single row tab control" to the container settings.
+
+ * made "close on esc" optional for those who don't like the newly introduced ESC
+ behaviour (minimize).
+
+ * changed closing behaviour. This should fix an ugly "crash on close container" in
+ some (although very rare) situations.
+
+ * changed the message-log scrolling hotkeys. It should no longer be possible to scroll
+ past the end of the log.
+
+ + it is now possible to have different background colors for the message log and the
+ message input area.
+
+ + added the "global search hotkeys" CTRL-SHIFT-U and CTRL-SHIFT-R. They are working
+ exactly like CTRL-U/CTRL-R, except that they search all open containers for unread
+ events.
+ If, for some reason, you cannot use those hotkey, because another applictaion needs
+ the keyboard shortcuts, you can configure the modifier keys under Options->message tabs.
+ Available choices are:
+ CTRL-SHIFT (default)
+ CTRL-ALT
+ SHIFT-ALT
+
+ + added SHIFT-RETURN as another shortcut for sending a message.
+
+ + Dividers added. When active, they will draw a small horizontal line above the first
+ unread event in an inactive (unfocused) message session. Those lines are a visual cue
+ to help you finding messages which have been received while you were absent more
+ easily. Activating the window will cause a new divider to appear the next time you
+ put the window into the background (but only, if an event arrives while the window
+ is in the background or minimized).
+
+ Dividers look best if you choose a small font (maybe 4 pixel) for them. There is a new
+ font setting under Options->Message log for the divider available. Just change the
+ default value to make dividers use less space. Note that dividers are not stored
+ permanently. They will go away whenever the log is rebuilt (i.e. when you apply new
+ options ore when you close and open the tab).
+
+ + autoswitch tab feature added. If enabled, minimized containers may automatically
+ switch to a tab whenever a new event arrives.
+
+ + added support to compile and link tabSRMM with GCC using MINGW32. Use MAKEFILE.W32
+ for compiling the unicode version, and MAKEFILE.W32.ANSI for the non-unicode version.
+ I also added a project file for Dev-CPP.
+ Tested with very recent versions of MINGW32 (GCC 3.4.1)
+
+ + moved project to sourceforge.
+
+ Version 0.0.6 - 2004/08/13
+ --------------------------
+
+ + minimize window on exit is now working (of course, it minimizes the entire
+ container).
+
+ ! fixed more focus issues (damn, this Win32 dialog manager does suck)
+
+ + implemented a basic system to determine the minimum required window size
+ for the container (internal stuff, but will be required later).
+
+ ! prevent the horizontal splitter from having a position "outside" of the
+ window after restoring a maximized window.
+
+ * cosmetical changes for the new window layout
+
+ * changed the code for "always scroll log to bottom" again. Should work better
+ (and faster) now.
+
+ This works far more "intelligent" than before. A tab will remember its scroll
+ position in the log while you switch to another tab. It will however automatically
+ scroll the log to the bottom under the following conditions:
+ * a message arrived
+ * the container size changed while the tab was inactive
+ * you move the splitter
+
+ ! fixed some issues when closing tabs.
+
+ + merged mod#32 from srmm_mod. show history (old) events with different fonts/colors.
+
+ * changed user picture layout. The picture is now allowed to use the vertical space
+ of the button bar. This will save some vertical space for the message log if the
+ picture is shown.
+
+ + new option: Show full UIN on the button bar. This defaults to enabled and if you
+ disable it, you will get the old usermenu button instead of the larger button
+ showing the full UIN. If you disable this option, you will gain some space on
+ the button bar. The full UIN is then set as a tooltip for the usermenu button.
+
+ At the moment, this is a global setting affecting all tabs, it will be a
+ "per - contact" option in the future. It is only in effect for the new window
+ layout.
+ It also doesn't dynamically update while the tab is open and only affects newly
+ created tabs (yet).
+
+ ! fixed glitch with autolocale. Even when deactivating it, it wasn't really 100%
+ inactive.
+
+ ! (hopefully) fixed another Win98 - specific crash (closing the last tab).
+
+ + new option: "Enable popups if container is minimized". If this is enabled, the
+ container will not report open message tabs while minimized. "Service enabled"
+ popup plugins like my modified version of NewEventNotify or Bi0s TypingNotify
+ will then think that there is no message window open and display their popup
+ notifications.
+
+ Enable this, if you want notifications while the container is minimized to the
+ statusbar.
+
+ ! fixed flickering on save button while typing.
+
+ + multiple container support added. Basically you can now have as much containers
+ as you want. You can assign contacts to a new container by richt-clicking either
+ the tab of the contact or in the message area of the active tab. A dialog box
+ will appear allowing you to select one of the already existing container
+ definitions. You can also create a new container if you want.
+ The container "default" gets some special treatment: It acts as the container
+ in which all unassigned contacts will open their tabs.
+
+ The UI will be improved a bit, but don't expect too much. I will definately
+ NOT add drag'n drop support for re-arranging tabs, because it would be quite
+ hard to implement and not worth the effort. There are better and more important
+ things to do.
+
+ ! fixed a few layout issues on the button bar (unequal spacing).
+
+ * flashing tab icons will now show the eventtype (file, url, message).
+
+ * changed "easy drag" implementation.
+
+ ! restored msg could overwrite initial text (used by, for example, http share
+ file plugin). fixed. Now, the initial text passed to the message tab at creation
+ will *always* overwrite any saved msg.
+
+ - removed hotkey ctrl-h (for history). It was redundant anyway, because history is
+ available via Alt-H.
+
+ + added mod#11 from srmm_mod (message input area accept dropped files)
+
+ + some container options (stay on top, dont report if minimized, no titlebar) are now
+ saved on a "per container" basis. The settings on the option page are now used as
+ default values for new containers.
+
+Version 0.0.5b - 2004/08/13
+
+ + 2 new options:
+ * flash always - continously flash the container until activated.
+ (doesn't currently work with the "autocreate tabs" feature).
+ * Never flash - disable window flashing (tab icons will still flash)
+
+ ! fixed auto-save on exit. Saved msg now goes away if you close the
+ container when the message input area is empty.
+
+ ! fixed: new layout picture-dependent splitter calculations could confuse
+ splitter settings when switching to old layout.
+
+ * a few internal changes (resizing, tab item handling...) always check return
+ value from GetTabIndexFromHWND()
+
+ ! fixed focus & tab handling. Re-enabled Alt-Hotkeys inside the dialog.
+
+ + new icons for the RTL and userpic button. Thanks to kreisquadratur
+ (author of the original srmm_mod)
+
+ * more "new" layout changes. Smaller borders, especially the right one. Items
+ are now better aligned.
+
+ + merged "use contacts local time" from srmm_mod. If enabled, the message log
+ will show the local time of your contact instead of your own time. This does,
+ of course, require that a contact has a properly configured timezone in
+ his profile.
+
+Version 0.0.5 - 2004/08/10
+
+ + added autolocale support. You need to enable this under Options->Tabbed Messaging.
+ How it works: It remembers the input locale setting for each contact. Just set
+ the desired keyboard layout (either via hotkey or via the language bar) and the
+ statusbar should show a message saying that the locale has been saved.
+ tabSRMM will then switch locale whenever you activate or open a tab for this
+ contact again.
+
+ If you open a message window for a contact which does not yet have a locale
+ information saved to its db record, tabSRMM will save the current input locale
+ as the standard for this contact.
+
+ NOTE: DONT use the autolocale plugin with tabSRMM. Since both plugins will then
+ try to modify locale settings, strange things could happen :)
+
+ ! fixed small display problem with the multisend button and the new window
+ layout.
+
+ ! fixed a few issues with "autocreate tabs" feature. They now only show up if the
+ container is already open and don't steal focus on the active tab any longer.
+ They also properly open in the background and do no longer confuse the layout
+ of the tab bar when more than a single row of tabs is needed.
+
+ ! fixed compatibility issue with Window 98/ME which was introduced in 0.0.4a
+
+ * another attempt to fix the "log not always scrolling to the bottom" issue.
+
+ * minor layout changes for the "new layout" - the horizontal splitter now has
+ a static edge which makes it easier to spot.
+ Removing the buttons and the info text will narrow down the splitter.
+
+ + added small margins to the rich edit control (message log).
+
+ ! Restoring the window position should now always work. New database keys are
+ used, so the first time using this release the container will popup at the
+ default position with the default size.
+
+ + new hotkeys:
+ CTRL-U activate the first tab with unread messages (flashing icon)
+ CTRL-R activate the tab with the most recent unread event.
+
+ ! fixed crash when changing icon sets (recreating the image list).
+
+ * In order to free up some space on the button bar, I removed the "userinfo"
+ button. Instead, you can click the protocol icon to bring up the dialog
+ with contact information. This only applies to the new window layout.
+
+ + new option: hide tab bar when only one tab is open.
+
+ * resizing now causes less flicker than before.
+
+ + Resurrected the quote button. Only for the new window layout though.
+
+ + Ability to save typed message on close window. Works automagically, no
+ need to configure anything.
+
+ * more layout changes for the "new" window layout. The usermenu-button is
+ gone. Instead of this button, I made the username field clickable.
+
+ * several cleanups in the code and resource file. .DLL filesize -= 14k :)
+
+ ! fixed some redraw/resizing issues when using the classic windows theme.
+
+ + user picture support added. This works only with the new message window
+ layout and at the moment it can only display locally stored user pictures.
+ The code was merged from srmm_mod with only minor modifications.
+
+Version 0.0.4a - 2004/08/07
+
+ ! fixed critical (crash) bug with error dialogs after message timeout.
+
+ ! fixed tab titles not updating when the option "show status text on
+ tabs" was disabled.
+
+ ! CTRL-L (clear message log) was missing, even it was mentioned in the changelog.
+
+ ! attempt to fix a possible crash-on-send bug.
+
+ ! fixed crash on forwarding messages (hope so).
+
+ + added tab icons for typing notification (if tab is not active, tab icon will
+ change and show typing status) - THIS IS WORK IN PROGRESS, typing notification
+ still does not work as it should.
+
+ + merged UNICODE fix by ghazan (possible crash with link handling)
+
+ ! fixed internal window closing issues when only one tab was active (possible
+ crash).
+
+ * tooltips now also display the status text
+
+ * all hotkeys changed again. They are now working with CTRL-SHIFT excluivly.
+ The hotkeys for scrolling the log can be enabled/disabled on the options page
+ for those who prefer having advanced editing features in the input box.
+
+ + new hotkey: CTRL-F4 -> close active tab.
+
+ * essential hokeys (ctrl-tab, ctrl-f4) now also work while the message input
+ area is "greyed".
+
+ + added "double click closes tab" feature.
+
+ + added "no title bar mode" (switch from window menu - doubleclick the border
+ to get the titlebar back). There is also an option to make it permanent for
+ newly created tab containers.
+ If the titlebar is off, you can still drag the window by using the small border
+ at the top or the right of the container window.
+
+ ! hopefully fixed the issue which caused the icons for specific protocols not
+ to load on startup.
+
+ + new option: vertical tab padding. You can specify the vertical padding (in pixel)
+ on the tabs. The value largely depends on the icon sets you're using - if you
+ use some larger icons, you may want to increase the default value of 3 in
+ order to avoid clipping on the icons. If you tend to use small icons, you
+ can reduce this value to 2 or even 1 pixels, making the tabs using less vertical
+ space.
+
+ + new option: short caption on containers. when active, only the nickname is shown
+ in the titlebar, otherwise nickname and statustext are shown.
+
+ + new feature: auto create tabs. Works similar to "auto popup window on receive"
+ but the new tab is created in the background and the container window does not
+ popup if it was minimized to the taskbar (instead it flashes if a new tab was
+ created). You can still make the container "auto popup" if you want - the option
+ is just below the "auto create tabs" setting.
+
+ ! fixed "no titlebar mode" for classic (non themed) windows style. Window didn't
+ update correctly after removing/adding the titlebar.
+
+ * a few minor resizing and geometry changes
+
+ + new message dialog layout (optionally, you have to enable it under Options->
+ tabbed messaging). This is work in progress and not fully implemented. There
+ will be an option for showing a user picture and more.
+
+This is the third alpha release. It contains bug fixes and a few new features.
+
+Version 0.0.3c - 2004/08/02
+---------------------------
+
+ + basic support for status icons on the tabs. This feature was contributed
+ by perf who asked me if I could need some help with development.
+
+ Currently, it uses the "global" status icons and not all icons do actually
+ look nicely on the tabs (some highcolor icons look seriously "broken").
+
+ This feature will be developed further so we will hopefully have full protocol
+ icon support in the future.
+
+ * some resizing changes. Also contributed by perf.
+
+ * changed the way hotkeys work. The old system was causing troubles. At the
+ moment, hotkeys do only work while the message input area has the focus.
+ Should not be a problem, because this is the case most of the time.
+
+ the following hotkeys are currently implemented:
+
+ * CTRL-TAB -> next tab (cycle if last was selected)
+ * CTRL+SHIFT-TAB -> previous tab (cycle if leftmost was selected)
+ * CTRL-H display history
+
+ Message log scrolling hotkeys:
+ ------------------------------
+ * CTRL-SHIFT-Arrow UP: scroll up in history
+ * CTRL-SHIFT-Arrow-Down: scroll down history
+ * CTRL-SHIFT-PageDown: scroll down faster
+ * CTRL-SHIFT-PageUp: scroll up faster
+ * CTRL-SHIFT-HOME: scroll to top of log
+ * CTRL-SHIFT-END: scroll to bottom of log
+
+ * CTRL-L: clear log (same as context menu entry)
+
+ * in case of a send error (timeout, protocol offline and so on), the message
+ dialog was never re-enabled again after the user clicked on "try again" or
+ cancel button in the error dialog. This bug caused the message window to
+ hang and the only way to get rid of it was to close the container. Fixed.
+
+ * when resizing, the message log scrolls to the bottom so that the last few
+ lines shouldn't disappear any longer.
+
+ ! attempt to fix the problem which is caused by wrong container geometry
+ information saved to the database.
+ If you get the message "Invalid geometry information found. Applying default values"
+ more than once, please let me know.
+
+ + context menu added to the tabs. Only a few options at the moment, but more
+ to come...
+
+ * tabSRMM related options moved to their own option page. It's under
+ Options->Tabbed Messaging.
+
+ + Ability to cut the length of the nicknames displayed on tabs. This should
+ prevent some extraordinary wide tabs for really long nicknames. Optionally,
+ a tooltip can be set for the tab, showing the full nickname.
+
+ + Option to select wheter protocol status should be shown on tabs in plain
+ text format. If disabled, only the nickname will be shown, making the
+ tabs even smaller.
+
+ ! activating the embedded contact list (multisend button) didn't properly work
+ if the container was maximized. Fixed.
+
+ ! fixed focus handling. Container passes the enter key (IDOK command) to the
+ active child, thus re-enabling the "TAB -> ENTER" sequence for sending
+ messages again.
+
+ + new option - show timestamp after nickname: If the message log is set to
+ display both the timestamp and the nickname, then the order in which they
+ appear can be set here.
+
+ * changed window flashing code. should work better now.
+
+ ! when sending a message by hitting ENTER while the send button had the
+ focus, the focus did remain on the send button. fixed. (for those who
+ prefer the TAB-ENTER sequence).
+
+ ! fixed several issues with closing tabs by using the context menu.
+
+ + NewEventNotify now works with tabSRMM. You HAVE to use the supplied DLL
+ in order to make it work with tabbed message sessions. Just replace
+ your existing NewEventNotify.DLL with the one provided in the tabSRMM
+ package.
+
+ + FULL status icon support implemented. Made the imagelist global (shared
+ by all containers), load all icons at plugin initialisation (should speed
+ up the creation of new containers)
+
+ Version 0.0.2 - 2004/07/26
+---------------------------
+
+ * statusbar does no longer have a size grip (SBARS_SIZEGRIP removed)
+ NOTE: only for tabs, toplevel msg dialogs will get it when they are back.
+
+ + settings only used by tabSRMM moved to a new key in the database. The plugin
+ will continue to share common settings with SRMM (fonts, colors etc..)
+
+ ! "Cascade new windows" caused display errors with newly created tabs if
+ the container already had one or more tab opened in it. Fixed.
+
+ ! The plugin is now statically linked against msvcr71.dll and therefore
+ should no longer complain about this dll missing.
+
+ ! saving geometry information about the container could sometimes lead to
+ unexpected results which could cause problems while trying to restore
+ the geometry the next time the container was created.
+
+ * thinner outer border. Did look ugly with lower screen resolutions.
+
+ ! when a contact changed its status and its tab was not the active one,
+ the window title was still updated and therefore didn't any longer
+ show the name of the _active_ tab.
+
+ ! minor cosmetical fixes with send button alignment.
+
+ + It is now possible to have miranda ask if you really want to close a
+ tab. Warning is diabled by default, you can turn it on via Options->Messaging.
+
+ + Some hotkey support added:
+
+ 1. ESC = close current tab (was always there)
+ 2. CTRL+SHIFT+TAB -> select previos tab
+ 3. CTRL+TAB -> select next tab.
+
+ Both options are set to wrap around if you have either the leftmost or rightmost
+ tab selected.
+
+ 4. CTRL+H -> show history
+ 5. CTRL+ALT+ARROW UP -> move the focus to the message log (use page up/down for scrolling)
+ 6. CTRL+ALT+ARROW DOWN -> move focus to the message input area.
+
+ + merged the RTL support from srmm_mod originally written by kreisquadratur
+
+ ! workaround for some strange splitter issues. The vertical multisend splitter
+ is re-enabled again.
+
+ ! fixed a few resizing issues when restoring the window from maximized state.
+
+ ! display / refreshing errors after forwarding a message should be fixed.
+
+ + added a new menu item to the system (window) menu: Stay on top (make the
+ container "sticky").
+
+ + added a UNICODE build which is, however, completely untested. It compiles
+ without warnings though :)
+
+
+Version 0.0.1 - 2004/07/23
+--------------------------
+
+ * initial release
+
diff --git a/plugins/TabSRMM/docs/changelog.txt b/plugins/TabSRMM/docs/changelog.txt
new file mode 100644
index 0000000000..d5d1f52406
--- /dev/null
+++ b/plugins/TabSRMM/docs/changelog.txt
@@ -0,0 +1,777 @@
+ Project Information:
+ ====================
+
+Name: tabsrmm
+Homepage: http://miranda.or.at
+Download: http://code.google.com/p/silvercircle/downloads/list
+Source: http://code.google.com/p/miranda (tabSRMM code is in Miranda SVN)
+
+Addtional annoucements can be found at my blog:
+ http://blog.miranda.or.at
+
+
++ : new feature
+* : changed
+! : bugfix
+- : feature removed or disabled because of pending bugs
+
+View CHANGELOG.OLD to see pre-1.0 relevant changes. Version 1.0.0.0 was declared
+splitted from trunk and declared as "stable" branch 2006/07/30. Released to
+the file listing the same day.
+
+ Global version information:
+ ===========================
+-----------------
+Version 2.0.x.x was released in October 2007 and is the current "stable" version.
+It NEEDS Miranda 0.7.x and will not work on older versions.
+
+Version 2.2.1.x is for Miranda 0.8 and was released in June 2009
+
+Version 3.x is for Miranda 0.9 and incompatible with older Miranda cores. There
+are currently no downloads for it, you'll have to compile it from source.
+
+-----------------
+
+ Detailed change log
+ ===================
+
+Version 3.1.99.7 - 2010/12/10
+
+ * fixed visual anomalies when the tool bar is hidden
+
+ * TAB does no longer focus the send button when the tool bar
+ is hidden.
+
+ * MUC: strip unneeded trailing white space characters from messages
+ to prevent them from breaking highlighting.
+
+Version 3.1.99.6 - 2010/10/28
+
+ * MUC: don't touch clist group at startup
+
+ * MUC: delay RTF header creation (workaround for a nasty bug that could
+ cause a hang on start). Not really a fix at this time.
+
+ * fixed a few minor visual glitches.
+
+Version 3.1.99.5 - 2010/10/15
+
+ ! fixes for overlay icons
+
+ * changed location for aero settings. It's no longer considered an advanced
+ tweak. The options are now global container settings.
+
+ * merged all fixes from stable tree
+
+ * MUC: strip all formatting codes from topics so that they are not messed
+ up in the info panel or status bar.
+
+
+Version 3.1.99.2 - 2010/09/02
+
+ ! propagate outgoing typing notifications to the active subcontact
+
+ * renamed sound group names for IM and group chats to make their meaning more
+ obvious.
+
+
+Version 3.1.99.1 - 2010/08/28
+
+ ! bug fix: topic in info panel did not refresh immediately when it was changed
+
+ * updater support for the version on the addons site.
+
+ ! load system libraries in a safe way.
+
+ ! bugfix (MUC): Do not lose input focus after autocomplete did not find
+ a matching nick name when the option to allow TAB in the input area is
+ enabled.
+
+ ! bug fix (MUC): Allow undo for nick - autocomplete actions
+
+
+Version 3.0.2 - 2010/08/25
+
+ * first stable release for 3.0.x - forked from 3.0.1.3
+
+
+Version 3.0.1.3 - 2010/08/10
+
+ * MUC: added code for case-insensitive highlighting of messages
+ containing your own nick name.
+
+ * MUC: fixed background color for popups (should now use the correct
+ color set for the MUC log background).
+
+ * added custom warning messages when importing a theme via
+ Customize->Message window skin.
+
+ * fixed wrong 32 pixel icon in the container options dialog. Now using
+ the message icon (for which we have both 16 and 32 pixel variants).
+
+ * avoid creating new windows and event notifications on non-message
+ events (e.g. file transfers).
+
+
+Version 3.0.1.2 - 2010/08/09
+
+ * finished v5 theme support (improved exporting and importing group
+ chat settings)
+
+ * re-activated global message log background color and separated it
+ from MUC background color (allows for different background colors for
+ single and group chats)
+
+ * fixed autocomplete (MUC) bugs
+
+Version 3.0.1.1 - 2010/08/05
+
+ * fixed disappearing code page selection menu.
+
+ * don't create MUC log files in the main profile directory any longer.
+
+ * MUC highlight: removed %m for own nick and replaced it with a separate
+ setting that allows white spaces in own nick names.
+
+
+Version 3.0.1.0 - 2010/08/04
+
+ * disabled some known buggy and incomplete features to get ready for
+ 3.0 release.
+
+ * set final feature set for version 3 - some less important things are
+ pushed back.
+
+ * MUC: disc logging, properly check log base path for trailing backslashes
+ when using folders plugin.
+
+ * MUC: protect log root folder from being deleted while MIM is running.
+
+
+Version 3.0.0.40 - 2010/07/10
+
+ * various fixes and improvements for Windows 7 task bar support.
+
+ * option to warn when closing a tab is gone. A replacement has been added which
+ will show you a warning when you are about to close a window with multiple tabs.
+ This warning uses a custom warning dialog and can be disabled by checking its
+ "Do not show this message again" option.
+
+ * fix for auto switching tabs incorrectly focusing tab when creating a new
+ one in the background.
+
+ * fixed crash when forcefully terminating Miranda while a custom warning
+ dialog is still open.
+
+Version 3.0.0.39 - 2010/06/24
+
+ * task bar previews: removed placeholders and implemented real previews of
+ the message window contents.
+
+ * redesigned container options dialog for better translations. Most
+ options now offer much more space for translated strings.
+
+ * attempt to fix stuck typing notifications on arriving messages
+
+Version 3.0.0.38 - 2010/06/21 - released with Miranda 0.9.alpha#11
+
+ * implemented warning dialog boxes with a "do not show this message again"
+ checkmark for various error- or informational messages.
+
+ * disabled aero peek previews when a skin is in use because of various
+ unresolved problems. Might be adressed at a later time.
+
+ * updated icon pack version to 5 and re-enabled a mandatory version check
+ on startup. The warning message can be disabled though.
+
+Version 3.0.0.37 - 2010/06/15
+
+ * changed logic for calculating relative skin path names. You will most likely
+ have to reload your skins.
+
+ * fixed a possible crash when unloading/reloading skins.
+
+ * some updates for task bar thumbnails.
+
+Version 3.0.0.36 - 2010/06/04 - released with Miranda 0.9.alpha#10
+
+ * task bar support (Win 7), removed check for running DWM. Task bar tabs should
+ now work with classic and non-aero themes in Windows 7 (no thumbnails, though,
+ because they require Aero to be active).
+
+ * renamed misleading option for task bar support as it implied to require an Aero
+ theme (which is not the case).
+
+ * another tool bar rendering fix - don't use gradients for the tool bar background
+ at all with classic Windows theme, unless both tool bar background colors are
+ properly set.
+
+ * Aero peek (task bar tabs) now default to enabled.
+
+Version 3.0.0.35 - 2010/05/29
+
+ * taskbar thumbnails (Win7): better support for MUC tabs, set active session
+ should now work.
+
+ * autoclose tabs: converted to a more useful autoclose/autohide container
+ feature and moved to container options.
+
+ * fixed a bug where installing a language pack could break hotkeys (translation
+ issue)
+
+ * fixed "black tool bar bug" when classic windows theme is active on XP or later.
+
+Version 3.0.0.34 - 2010/05/27
+
+ * fixed crash when running on Windows 2000
+
+ * cleaned up the mess in the TSButton class
+
+ * More work on Aero Peek thumbnail previews. Added custom thumbnails for MUC chat
+ rooms and server windows.
+
+ * updated msglog mark read code with some recent changes for srmm.
+
+
+Version 3.0.0.33 - 2010/05/22
+
+ * some issues fixed
+
+ * improved compatibility for old (TabSRMM 2) skins
+
+ * preliminary support for large status icons on the Windows 7 task bar (Miranda 0.9
+ required).
+
+ * option to show avatars on task bar added to container settings (only
+ when running on Windows 7).
+
+ * option to enable/disable Windows 7 task bar features removed (now always on,
+ when running on Windows 7).
+
+ * Added aero peek for the Windows 7 task bar. Per tab thumbnails are partially
+ implemented, so you get a similar UI as seen in other tabbed applications
+ under Windows 7 (IE 8, Opera 10, for example). Still experimental, so it is
+ disabled by default (Message Sessions->Advanced tweaks is where you can enable
+ it). A Restart is required.
+
+
+Version 3.0.0.32 - 2010/05/16
+
+ * menu bar is now using tool bar colors when using custom message window
+ colors
+
+ * fixed changelog URL for users of updater plugin and created new online
+ change log for TabSRMM 3 development versions
+
+ * added separate translation for default container name (avoid using common
+ translation for "default").
+
+Version 3.0.0.31 - 2010/05/xx
+
+ * fixed drawing problem with animated info panel avatars
+
+ * moved all legacy color settings to font service
+
+ * added theme support for new color settings (+ updated theme version to
+ v5).
+
+ * fixed issue with own nickname when it has not been set on the protocol's
+ option page (use own UID instead).
+
+
+Version 3.0.0.30 - 2010/05/12
+
+ * MUC: replaced (non working) log truncating with log rotation. Old log files
+ are archived when the size exceeds the maximum allowed length for a single
+ channel log file.
+
+ * updated some dialogs to make more space for translations.
+
+ * added UI button for quickly opening the MUC logs base folder.
+
+ * implemented right and middle click actions for side bar buttons (close/context
+ menu)
+
+
+Version 3.0.0.29 - 2010/05/11
+
+ * fixed a number of drawing problems
+
+ * DB tweak to force tool bar always use visual styles
+
+ * added 2 new common colors for painting the UI in aero and visual styles
+ mode.
+
+ * improved exporting and importing of theme files to support UI settings that
+ are new in TabSRMM 3.
+
+
+Version 3.0.0.27 - 2010/05/06
+
+ * send menu pulldown button is now always available, even if the
+ send button itself is disabled.
+
+ * fixed few problems with tool bar configuration dialog.
+
+ * send later UI improved
+
+ * skin selection dialog improved (added button for quickly closing
+ all open message windows when loading or unloading a skin).
+
+Version 3.0.0.26 - 2010/04/30
+
+ * fixed the painting of close buttons on tabs when using a skin (they
+ were incorrectly using visual styles instead of the button skin)
+
+ * new skin item for the switch bar background
+
+ * send later out of hidden state (see: http://wiki.miranda.or.at/SendLater)
+
+Version 3.0.0.25 - 2010/04/23
+
+ * bug fixes
+ * added two new switch bar layouts (more complex, allow showing avatars
+ on the switch bar buttons).
+ * fix for a crash when AVS plugin is not available.
+
+Version 3.0.0.22 - 2010/04/01
+
+ * Alpha snapshot released to my googlecode site.
+ * many bug fixes and small improvements, new skin selection dialog
+ * still INCOMPLETE and not all features are fully working.
+
+Version 3.0.0.8 - 3.0.0.21
+
+ * again, many, many changes and new things. Refer to the Wiki page
+ (http://miranda.or.at/TabSrmm:Development3_0_KnownIssues) for more information.
+
+Version 3.0.0.4 - 3.0.0.8
+
+ * Ongoing rewrite of the plugin. New infopanel, MUC highlighting, aero effects
+ among many other things were added. Still in alpha stage.
+
+Version 3.0.0.3 - 2009/08/20
+
+ * too many changes to list here. Major rewrites in many areas, aero support
+ new menu bar (rebar-based), new, more dynamic info panel layout and drawing,
+ support for core hotkey service added, folders support extended, reworked
+ some groupchat options, got rid of old protocol names where possible
+
+Version 3.0.0.2 - 2009/07/30
+
+ * Major rewrites in some areas
+ * converted source to C++
+ * basic aero support added (experimental, disabled by default, you have to set
+ a database value BYTE "useAero" under the "Tab_SRMsg" module and set its
+ value to 1. Restart required
+ * many parts of the plugin rewritten in C++ (just started, more to come)
+
+Version 3.0.0.1 - 2009/07/20
+
+ * MAJOR changes in some areas. Info panel overhaul and more. Expect
+ tabSRMM to be unstable for a while. 2.2.1.x will continue to exist for user
+ of a stable Miranda. 3.0.0.x is currently for TESTING ONLY.
+
+Version 3.0.0.0 - 2009/07/20
+
+ ! various visual glitches fixed.
+ ! fixed problem with private container theme (using relative pathnames)
+ ! plugin version updated and restricted to Miranda 0.9.x development
+ branch.
+
+Version 2.2.1.19 - 2009/07/08
+
+ ! fixed some slowdowns when opening new tabs
+ * branched to Miranda - stable (0.8.x).
+
+Version 2.2.1.18 - 2009/06/28
+
+ ! bug fixes
+ ! Hotkeys rearranged (Ctrl-y and Ctrl-l disabled, Ctrl-r moved to Alt-r)
+
+Version 2.2.1.17 - 2009/06/21
+
+ ! fixed possible crash, introduced by the new %a variable
+ ! fixed some problems with global Ctrl-Shift-U hotkey
+
+Version 2.2.1.16 - 2009/06/14
+
+ * replaced internal protocol name with user defined account name in some places
+ (e.g. info panel).
+
+ * added new variable for title bar formatting: %a will be replaced with the
+ user defined account name for the current contact.
+
+ * various fixes and updates by core developers.
+
+ * released for Miranda 0.8.0
+
+Version 2.2.1.14 - 2009/03/05
+
+ * fixed untranslateable strings
+
+
+Version 2.2.1.13 - 2009/01/02
+------------------------------
+
+ * merged changes from main Miranda tree (chat API, bugfixes)
+
+ * project is now fully GCC / MingW compatible. Build files were added to
+ build tabSRMM with GCC 4.x. See docs/README.GCC for more information.
+
+ * removed minimize to tray (or floater) feature. The same functionality
+ is now available via the "hidden container" feature.
+
+
+Version 2.2.1.12 - 2008/12/30
+------------------------------
+
+ * Windows Vista only: re-enabled transparency settings when using skins for the
+ message container. Experimental, but it seems to work and none of the
+ problems I've seen under XP (very slow redraw, CPU hogging while typing)
+ does occur. NOTE: When not using the Aero desktop (e.g. Vista Home Basic),
+ transparency combined with skins may still result in slow window redrawing.
+
+ * resolved some translation disambiguities in the user preferences dialog.
+
+ * added some missing translations
+
+ * fixed bug with container creation - in some cases, container may stay hidden
+ (bug ID #468)
+
+
+
+Version 2.2.1.11 - 2008/09/26
+------------------------------
+
+ * made compile under Visual Studio 2008 (workaround for the richedit.h issue
+ in PSDK 6.0)
+
+ * per channel event filter dialog is now translatable. (issue #0000435).
+
+
+Version 2.2.1.10 - 2008/09/11
+------------------------------
+
+ + added option for setting avatar visibility to the user preferences dialog.
+
+
+Version 2.2.1.9 - 2008/07/15
+-----------------------------
+
+ ! fix for layout distortions when switching message log viewer in an active
+ tab.
+
+ * various source code cleanups and added comments (for devs only)
+
+ + added more help hyperlinks to various option dialog boxes. These link to the
+ wiki pages on the official documentation site.
+
+ ! fix for double cr/lf insertion (by Vasilich)
+
+ ! when toolbar is disabled, don't draw smiley selection window at random
+ position.
+
+ ! fixed crash/freeze with some nicknames (recursions when replacing character
+ sequences in the message window title bar). Bugtracker id: 0000223
+
+ ! status bar buttons will now check the source of the click event. Fixed
+ bug ID #0000146
+
+Version 2.2.1.8 - not public, released with Miranda 0.8 nightly #18)
+---------------------------------------------------------------------
+
+ * for devs only: Patch by ono to make the code to compile with GCC
+ w/o problems.
+
+ ! hide on close feature: small fix for distorted layout when showing
+ a container with a previouly not yet activated tab.
+
+ ! fixed minor resource leak when the display of client icons in the
+ status bar is enabled (advanced tweak).
+
+ ! more minor fixes for the hidden container feature.
+
+
+Version 2.2.1.7 - 2008/06/21
+-----------------------------
+
+ - internal, not released to public
+
+Version 2.2.1.6 - not public
+-----------------------------
+
+ ! fixed "Revert to safe defaults" bug in advanced tweaks dialog.
+
+ ! fixed possible crash in message log streaming when history
+ keeper is installed
+
+ ! minor layout changes for 120 DPI setting.
+
+ ! custom smiley patch by borkra (show custom smileys on incoming
+ messages only)
+
+ ! fixed bug with bbcode colors (introduced by font service support)
+
+ ! fixed minor drawing issue with log freeze indicator.
+
+Version 2.2.1.5 - 2008/05/08
+-----------------------------
+
+ ! bug fixes: smiley button visual glitch, group chat option tree
+ icon(s), possible crash with tool bar config, wrong background
+ colors in the message log, "load actual history" now works.
+ - some fixes for font service support.
+
+ * changed button highlight code for buttons with a "dropdown arrow".
+ Entire button is now "hovered" - the old way did look very strange
+ with some skins or visual styles.
+
+ * group chat related options were re-organized. Everything is now
+ in Message Sessions->Group chats. Options were slightly re-grouped
+ for a more logical appearance.
+
+ * popup configuration option pages are now only created when a popup
+ plugin is installed.
+
+ * small adjustments for minimum splitter position.
+
+ - removed 7bit ansi check for outgoing messages. Now obsolete, because
+ of UTF-8 database storage format.
+
+ + added support for History Events plugin by pescuma (patch submitted
+ by pescuma)
+
+ - removed useless help menu entries
+
+ + added spin controls to configure popup delay values
+
+ + allow to set -1 for each popup delay to use "infinite" delay (
+ popup will stay on screen forever).
+
+ * error popups will not timeout any longer. Instead, they must be
+ clicked to dismiss them.
+
+ + integrated "mod plus" options into Message Sessions->Advanced tweaks.
+
+ ! merged MButton patch by rainwater into TSButton control to check that
+ a button release event should be processed.
+
+ * don't close hovered popups (when mouse pointer is over a popup)
+
+ * reworked typing notify options.
+
+ - removed deprecated toolbar hiding options
+
+ + added various hyperlink controls to open online help pages to the
+ option dialogs.
+
+
+Version 2.2.1.4 - 2008/05/08
+-----------------------------
+
+ * for internal testing only (not officially released)
+
+Version 2.2.1.3 - 2008/04/XX
+-----------------------------
+
+ * for internal testing only (not officially released)
+
+Version 2.2.1.2 - 2008/04/23
+-----------------------------
+
+ * increased limit of the time based "load previous events" feature.
+ It's now 24 hours instead of the 12 it was before. So the maximum
+ value you can enter on Message Log->Load previous events less than"
+ are 1440 minutes.
+
+ * various fixes by ghazan (compile fixes for VC 2003, msg timeout
+ fix and more)
+
+ * added font service support (patch by Mad Cluster). All fonts must
+ now be set under Customize->Fonts->tabSRMM. The old font and color
+ dialog is gone.
+
+ * the menu items for invoking the message log settings dialog (both
+ global and per contact) are now working. You can find them on the
+ Menu bar (Message Log popup) or by clicking the message log options
+ button on the tool bar.
+
+ * Removed the Message Sessions->Customize node and replaced it with
+ a new dialog holding all group chat related options.
+
+Version 2.2.1.1 - 2008/04/10
+-----------------------------
+
+ * merged "MADMod" patch. This is a big contribution and adds several
+ new features like a fully customizable button bar and more. Also adds
+ old style typing notification popups (code taken from bio's old plugin),
+ support for animated .gif avatars and more.
+
+ See: http://forums.miranda-im.org/showthread.php?t=17918
+
+ * New per contact message log settings are now almost complete and
+ working. Alt-B (RTL/LTR toggle has been restored).
+
+ * bug fix for splitter position syncing
+
+ * added nova icon pack (by Angeli-Ka).
+ NOTE: icon pack format has changed slightly because of the Mad
+ mod patch. You can still use an old icon pack, but you
+ may receive a warning when doing so.
+
+
+Version 2.1.0.1 - 2008/03/26
+
+ * fixed small visual glitch when using the modern (styled) tabs
+
+ * groupchats: Fixed issue with indentation of multiline messages.
+
+ * groupchats: Implemented selective disc file logging. Under
+ Options->Message Sessions->Group chats, you will find a new option
+ tree where you can select events which should be logged to the
+ log file.
+
+Version 2.1.0.0 - 2008/02/15
+
+ * groupchats: clickable nicknames can now be colorized. Patch by theMiron
+ (h++ author).
+
+ * reworked message log settings
+ see: http://miranda.or.at/Blog:Tabsrmm_changes_2_1_0_0 for details.
+
+ * compatibility with Miranda 0.7 no longer given. 2.0.0.5 was branched
+ as stable tree for 0.7 users.
+
+ * group chats: proper handling of RTF \endash, \emdash and \bullet (patch
+ by theMiron).
+
+Version 2.0.0.5 - 2008/01/02
+
+ * increased timer for info panel tooltips to 1 sec (previously, it was set
+ to 500msec which may be too short and trigger unwanted tooltips).
+
+ * some better automatic detection for the MathMod plugin.
+
+ * changed tree controls on option pages to use simple checkboxes
+ instead of image lists.
+
+Version 2.0.0.4 - 2007/12/23
+
+ + added incremental search feature to the group chat userlist. Simply
+ type what you want to find and it will be highlighted. Using cursor keys
+ to move the selection will clear the current search string. Typing
+ something which does not exist will also clear the current seach string
+ and start over.
+ ! fixed missing checkmarks in the message log submenu of the containers
+ menu bar.
+ ! fixed untranslateable strings in the container options dialog
+ - disabled skin editor for tabsrmm (still not complete, avoid confusing
+ people :) ).
+ ! fixed minor issue with double icons in status bar (on rare occasions)
+ ! fixed skin drawing on multimonitor systems (patch by Bryan)
+
+Version 2.0.0.3 - 2007/11/29 (released with 0.8 alpha #5)
+
+ * changed per contact filter system in group chats
+ ! "revert splitter" option fixed for group chats.
+ ! "sync splitter with groupchats" option - fixed small (1px) alignment
+ bug
+ ! fixed idle time for metacontacts (may not work with older versions of
+ metacontacts plugin, so please update).
+ - removed active status message retrieval when hovering info panel.
+ tabSRMM now ONLY reads the status message from the database where it
+ should be stored by the protocol or a 3rd party status message retrieval
+ plugin.
+ ! fixed F12 hotkey (message log freeze). Will not be triggered anymore when
+ holding a modifier (alt, ctrl etc.).
+ * some internal code cleanup
+ ! #0000214 (accessibility issue with option dialogs)
+
+Version 2.0.0.2 - 2007/10/02
+
+ ! fixed a few untranslatable strings.
+ ! fixed "revert to old" splitter option (was misaligned by a few pixels).
+ (issue # 0000024)
+ * cleaned up "clickable nicks code" (groupchats, patch by ghazan).
+
+Version 2.0.0.1 - re-upload to enable updater support
+
+Version 2.0.0.0 - 2007/10/02
+
+ * compatible ONLY with Miranda 0.7
+ * UTF-8 message storage now supported
+ * many bug fixes
+ * see online changelog at http://miranda.or.at/tabsrmm/tabsrmm-changelog/
+ for more detailed history.
+
+Version 1.1.0.16 - 2007/01/20
+
+ * bugfixes
+ * 3-way message log selection added to the user preferences dialog.
+ * fixed problem with calling certain protocol services too early.
+ * fixed own nickname not showing in template editor.
+ * removed old icon loading code. IcoLib API is now required (either
+ via IcoLib plugin or new Miranda 0.7 core).
+
+Version 1.1.0.14 - 2006/12/06
+
+ * more work on clickable nicknames in group chats.
+ * draw inactive / disabled status bar icons with high transparency to make
+ them appear "dimmed". Less confusing than constantly disappearing/jumping
+ icons in the status bar.
+ * clickable nicknames in the group chat history can now be right-clicked to
+ open the user context menu (same menu as in nickname list).
+ * fixed ugly crash bug introduced in .13 (clicking on the session list/tray
+ icon).
+
+Version 1.1.0.13 - 2006/11/26
+
+ + group chat module has been converted to UNICODE (ghazan)
+ + Support for history++ as a message log viewer has been added.
+ + Support for the spell checker plugin by pescuma has been added to IM and
+ group chat sessions.
+ + codepage support for group chat windows added.
+ * various smaller enhancements and bugfixes (too many to list here).
+ + message window API support for status bar icons has been added.
+
+Version 1.1.0.10|11|12 - internal
+
+Version 1.1.0.9 - 2006/09/20
+
+ ! fix: own avatar images are now rendered properly when they have transparency
+ * enabling or disabling the integrated group chat support will now set the chat.dll
+ plugin to enabled or disabled.
+ * most temporary error messages are now translateable
+
+Version 1.1.0.8 - 2006/09/10
+
+ internal only
+
+Version 1.1.0.7 - 2006/08/20
+
+ ! disable auto-bidi mode when no RTL language is installed
+ ! workaround for a loadavatars problem (may cause disappearing avatars in
+ the message window).
+
+Version 1.1.0.6 - 2006/08/05
+
+ Mainly bugfixes from 1.0.0.0 release.
+
+ ! fixed updater support (301, invalid response).
+ ! fixed bug when re-attaching a temporary contact to a new
+ container while the option to delete temporary contacts on close
+ is enabled.
+ ! fixed minor issue with [color] bbcode
+ ! using the own UIN as fallback for own nickname, to solve the "Unknown
+ Contact" problem which can appear when the own nickname is not
+ properly set.
+ ! fixed a few issues with global splitter positioning.
+ * selecting offline sub protocol throws a warning instead of an error.
+ - removed the feature to load a background image for the message input area.
+ was causing too many troubles and people did not understand that it was an
+ experimental feature, thus sending bug reports.
+ ! fixed problem with freezing when opening a message window by clicking on a
+ typing notify popup
+ ! fixed vertiacl maximize (patch by SloMo)
+
diff --git a/plugins/TabSRMM/docs/contributors.txt b/plugins/TabSRMM/docs/contributors.txt
new file mode 100644
index 0000000000..6838692cd5
--- /dev/null
+++ b/plugins/TabSRMM/docs/contributors.txt
@@ -0,0 +1,32 @@
+
+ This is a fairly incomplete list of contributors to this project.
+ -----------------------------------------------------------------
+
+* Original SRMM code by rainwater (robert _at_ rainwater _dot_ org)
+
+* Code merged from SRMM_Mod written by kreisquadratur
+
+* theMiron sent a number of patches, mainly for group chats and
+ History++ support.
+
+* Mad Cluster (daniok _at_ yandex _dot_ ru) wrote the "MadMOD" patch,
+ adding many new features and fixes.
+
+* Angeli-Ka contributed the icons for the default proxal icon pack.
+
+* Code for advanced typing notifications written by Bio for the
+ original typing notify plugin. This was integrated by the MadMod
+ patch in 2008.
+
+* Some code of the New Event Notify plugin was merged to add internal
+ event notification functionality into tabSRMM.
+
+* Many others contributed small fixes and ideas. If I forgot something,
+ let me know.
+
+
+NOTE: If you have contributed some code and want to be listed here, contact
+ me via mail (see below).
+
+----
+Last modified: 2008/04/14, Nightwish (silvercircle _at_ gmail _dot_ com).
diff --git a/plugins/TabSRMM/docs/readme.txt b/plugins/TabSRMM/docs/readme.txt
new file mode 100644
index 0000000000..c1326b6b12
--- /dev/null
+++ b/plugins/TabSRMM/docs/readme.txt
@@ -0,0 +1,124 @@
+ tabbed SRMM plugin for Miranda IM 0.9.0
+ ----------------------------------------
+
+Online resources at: http://wiki.miranda.or.at, http://blog.miranda.or.at and
+http://forum.miranda.or.at
+
+----------------------------------------------------------
+
+Version: 3.0
+Created: August 2009
+
+1. Overview
+-----------
+
+tabSRMM is an advanced messaging module for Miranda IM (version 0.9.x or later
+required). It adds many new options and features to make instant messaging more
+enjoyable and allows you to tweak almost every aspect of the message window to
+fit your needs.
+
+2. Some features:
+-----------------
+
+* "tabbed messaging". All message dialog windows are now opened within a "container"
+ window. A simple tab bar can be used to switch between the message windows.
+ Currently, there is only one container and no way to make one or more message
+ windows "top level". You can define as many container windows as you want and
+ assign your contacts to different containers. This allows you to organize your
+ chat sessions in many different ways.
+
+ If you dislike a tabbed interface for chatting, you can also configure a "single
+ window mode" in which each session is opened in a separate window.
+
+* Lots of options to tweak the look of your message log.
+
+* Works with the external IEView plugin to give you a fully customizable message log
+ using HTML templates and CSS.
+
+* Avatar support - both contacts and own avatars can be shown in the message dialog.
+
+* message templates for the message history in the chat window. You can freely define
+ how messages will look like by using a powerful system of variables and templates.
+
+* built-in event notification system can announce messages and other events by using
+ popups, system tray tooltips or On Screen Displa (announcing via poups or on screen
+ display requires additional plugins).
+
+* WYSIWYG text editing in the message input box. Formatted text can be parsed to
+ either BBCodes or simple */_ style formatting tags.
+
+* many features which make chatting more user friendly and easier. Some examples.
+
+ * auto-select-and-copy: Selecting text in the message log history will automatically
+ copy it to the clipboard. Holding down the ctrl key while selecting text will
+ insert the selection in the edit box immediatly.
+
+ * simplified mousewheel handling. No need to change the focus if you want to scroll
+ the history log. Just move the mouse pointer over it and use the wheel.
+
+ * Many hotkeys. Almost everything can be done without using the mouse.
+
+ * option to minimize chat windows to the tray so they won't clutter your taskbar.
+ A session list is available which can be used to access chat windows which have
+ been minimized to the system tray.
+
+* A "favorite contact" list which can be used to access favorite contacts quickly.
+ (Win 2000 or later).
+
+* Remembers the last 15 active sessions in a menu (Win 2000 or later).
+
+* System tray support.
+
+* integrated group chat module, based on chat.dll but merged into tabSRMM to give
+ users a unified user interface for both IM and group chats (i.e. IRC channels).
+
+3. FAQ and general help
+-----------------------
+
+ For a lot of knowledge, please visit my forum at http://miranda.or.at/
+ There you can find a lot of useful information, articles, a small FAQ, and some
+ links telling you more about tabSRMM in general.
+
+6. Credits and thanks:
+----------------------
+
+Lots of people provided useful suggestions, feature requests and bug reports during
+the development phase. I cannot name you all here, because it's just too many.
+
+* The Miranda-IM development team and all contributors for making the best
+ IM client on this planet (and probably in the entire universe :) )
+
+* sryo (teodalton@yahoo.com) for the minimal icons.
+
+* Faith Healer for making icon packs, lots of suggestions, testing and
+ feedback.
+
+* the members on my own forum (http://www.miranda.or.at/forums/) for a lot
+ of bug reports, feature suggestions and testing every new snapshot.
+
+* Angeli-Ka for many bug reports and general feedback, especially in the
+ early phase of development when using tabSRMM could be really frustrating :)
+
+ Also, for making the final icon set which is now distributed as default icon
+ pack.
+
+* Progame - for finding even the most carefully hidden bugs :)
+
+* All other members of the Miranda community, who helped with hunting down
+ sometimes hard to find, bugs, and for suggesting features.
+
+* "Mad Cluster" for the madmod patch which added a number of useful and often
+ requested new features to the plugin.
+
+* Joergen Persson for the original MUC ("multiuser chat") module for
+ Miranda IM. Large parts of tabSRMM's multiuser chat integration are based
+ on his code.
+
+------------
+License: GPL
+------------
+
+Contact me at: mailto: silvercircle _at_ gmail _dot_ com
+ GTalk/Jabber: silvercircle _at_ gmail _dot_ com
+ ICQ: 7769309
+ MSN: silvercircle _at_ gmail _dot_ com
diff --git a/plugins/TabSRMM/icons/ICONSXP/.cvsignore b/plugins/TabSRMM/icons/ICONSXP/.cvsignore
new file mode 100644
index 0000000000..76b025ad1f
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONSXP/.cvsignore
@@ -0,0 +1,2 @@
+Debug
+Release
diff --git a/plugins/TabSRMM/icons/ICONSXP/ICONSXP.dsp b/plugins/TabSRMM/icons/ICONSXP/ICONSXP.dsp
new file mode 100644
index 0000000000..ac61cb795c
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONSXP/ICONSXP.dsp
@@ -0,0 +1,74 @@
+# Microsoft Developer Studio Project File - Name="ICONSXP" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=ICONSXP - Win32 Release
+!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "ICONSXP.mak".
+!MESSAGE
+!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "ICONSXP.mak" CFG="ICONSXP - Win32 Release"
+!MESSAGE
+!MESSAGE Für die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "ICONSXP - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /Zi /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "ICONSXP_EXPORTS" /D "_MBCS" /Yu"stdafx.h" /c
+# ADD CPP /nologo /MT /W3 /GX /Zi /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "ICONSXP_EXPORTS" /D "_MBCS" /Yu"stdafx.h" /c
+# ADD BASE MTL /nologo /win32
+# ADD MTL /nologo /win32
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:IX86 /out:"Release\tabsrmm_icons.dll" /implib:"$(OutDir)/ICONSXP.lib" /pdbtype:sept /opt:ref /opt:icf /noentry
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:IX86 /nodefaultlib /out:"Release\tabsrmm_icons.dll" /implib:"$(OutDir)/ICONSXP.lib" /pdbtype:sept /opt:ref /opt:icf /noentry
+# SUBTRACT LINK32 /debug
+# Begin Target
+
+# Name "ICONSXP - Win32 Release"
+# Begin Group "Headerdateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;inc;xsd"
+# Begin Source File
+
+SOURCE=.\resource.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+# Begin Source File
+
+SOURCE=.\ICONSXP.rc
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/plugins/TabSRMM/icons/ICONSXP/ICONSXP.mak b/plugins/TabSRMM/icons/ICONSXP/ICONSXP.mak
new file mode 100644
index 0000000000..6029d6bed0
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONSXP/ICONSXP.mak
@@ -0,0 +1,192 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on ICONSXP.dsp
+!IF "$(CFG)" == ""
+CFG=ICONSXP - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to ICONSXP - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "ICONSXP - Win32 Debug" && "$(CFG)" != "ICONSXP - Win32 Release"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "ICONSXP.mak" CFG="ICONSXP - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ICONSXP - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ICONSXP - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "ICONSXP - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+ALL : "$(OUTDIR)\ICONSXP.dll"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\ICONSXP.res"
+ -@erase "$(OUTDIR)\ICONSXP.dll"
+ -@erase "$(OUTDIR)\ICONSXP.ilk"
+ -@erase "$(OUTDIR)\ICONSXP.pdb"
+ -@erase ".\$(OutDir)\ICONSXP.exp"
+ -@erase ".\$(OutDir)\ICONSXP.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "ICONSXP_EXPORTS" /D "_MBCS" /Fp"$(INTDIR)\ICONSXP.pch" /Yu"stdafx.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /GZ /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ICONSXP.res"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\ICONSXP.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:yes /pdb:"$(OUTDIR)\ICONSXP.pdb" /debug /machine:IX86 /out:"$(OUTDIR)\ICONSXP.dll" /implib:"$(OutDir)/ICONSXP.lib" /pdbtype:sept
+LINK32_OBJS= \
+ "$(INTDIR)\ICONSXP.res"
+
+"$(OUTDIR)\ICONSXP.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "ICONSXP - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\tabsrmm_icons.dll"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\ICONSXP.res"
+ -@erase "$(OUTDIR)\tabsrmm_icons.dll"
+ -@erase ".\$(OutDir)\ICONSXP.exp"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MT /W3 /GX /Zi /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "ICONSXP_EXPORTS" /D "_MBCS" /Fp"$(INTDIR)\ICONSXP.pch" /Yu"stdafx.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ICONSXP.res"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\ICONSXP.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\tabsrmm_icons.pdb" /machine:IX86 /nodefaultlib /out:"$(OUTDIR)\tabsrmm_icons.dll" /implib:"$(OutDir)/ICONSXP.lib" /pdbtype:sept /opt:ref /opt:icf /noentry
+LINK32_OBJS= \
+ "$(INTDIR)\ICONSXP.res"
+
+"$(OUTDIR)\tabsrmm_icons.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("ICONSXP.dep")
+!INCLUDE "ICONSXP.dep"
+!ELSE
+!MESSAGE Warning: cannot find "ICONSXP.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "ICONSXP - Win32 Debug" || "$(CFG)" == "ICONSXP - Win32 Release"
+SOURCE=.\ICONSXP.rc
+
+"$(INTDIR)\ICONSXP.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) $(RSC_PROJ) $(SOURCE)
+
+
+
+!ENDIF
+
diff --git a/plugins/TabSRMM/icons/ICONSXP/ICONSXP.rc b/plugins/TabSRMM/icons/ICONSXP/ICONSXP.rc
new file mode 100644
index 0000000000..1cce21c489
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONSXP/ICONSXP.rc
@@ -0,0 +1,176 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// German (Germany) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_HISTORY ICON "../../res/proxal/history.ico"
+IDI_MSGLOGOPT ICON "../../res/proxal/options.ico"
+IDI_ADDCONTACT ICON "../../res/proxal/plus.ico"
+IDI_MULTISEND ICON "../../res/proxal/multisend.ico"
+IDI_TYPING ICON "../../res/proxal/pencil.ico"
+IDI_QUOTE ICON "../../res/proxal/quote.ico"
+IDI_SAVE ICON "../../res/proxal/file.ico"
+IDI_SEND ICON "../../res/proxal/check.ico"
+IDI_CONTACTPIC ICON "../../res/proxal/avatar.ico"
+IDI_USERMENU ICON "../../res/proxal/info.ico"
+IDI_MSGERROR ICON "../../res/proxal/block.ico"
+IDI_CLOSEMSGDLG ICON "../../res/proxal/delete.ico"
+IDI_ICONIN ICON "../../res/proxal/Incom.ico"
+IDI_ICONOUT ICON "../../res/proxal/outg.ico"
+IDI_SMILEYICON ICON "../../res/proxal/emoticon.ico"
+IDI_SELFTYPING_ON ICON "../../res/proxal/mtn.ico"
+IDI_SELFTYPING_OFF ICON "../../res/proxal/nomtn.ico"
+IDI_CONTAINER ICON "../../res/proxal/message.ico"
+IDI_SECUREIM_ENABLED ICON "../../res/proxal/secureOn.ico"
+IDI_SECUREIM_DISABLED ICON "../../res/proxal/secureOff.ico"
+IDI_STATUSCHANGE ICON "../../res/proxal/Status change.ico"
+IDI_FONTBOLD ICON "../../res/proxal/bold.ico"
+IDI_FONTITALIC ICON "../../res/proxal/italic.ico"
+IDI_FONTUNDERLINE ICON "../../res/proxal/underline.ico"
+IDI_STRIKEOUT ICON "../../res/proxal/strikethrough.ico"
+IDI_FONTFACE ICON "../../res/proxal/font.ico"
+IDI_FONTCOLOR ICON "../../res/proxal/font2.ico"
+IDI_SOUNDSON ICON "../../res/proxal/sounds_on.ico"
+IDI_SOUNDSOFF ICON "../../res/proxal/overlay_disabled.ico"
+IDI_EMPTY ICON "../../res/empty.ico"
+IDI_RESERVED10 ICON "../../res/empty.ico"
+IDI_SESSIONLIST ICON "../../res/proxal/slist.ico"
+IDI_CONFIGSIDEBAR ICON "../../res/proxal/sbaroptions.ico"
+IDI_FAVLIST ICON "../../res/proxal/favlist.ico"
+IDI_RECENTLIST ICON "../../res/proxal/recentlist.ico"
+IDI_USERPREFS ICON "../../res/proxal/userprefs.ico"
+IDI_TRAYANIM1 ICON "../../res/MessAnim/m1.ico"
+IDI_TRAYANIM2 ICON "../../res/MessAnim/m2.ico"
+IDI_TRAYANIM3 ICON "../../res/MessAnim/m3.ico"
+IDI_TRAYANIM4 ICON "../../res/MessAnim/m4.ico"
+IDI_TAG1 ICON "../../chat/Icons/tag1.ico"
+IDI_TAG2 ICON "../../chat/Icons/tag2.ico"
+IDI_TOPICBUT ICON "../../chat/Icons/topicbut.ico"
+IDI_JOIN ICON "../../chat/Icons/join.ico"
+IDI_TOPIC ICON "../../chat/Icons/topic.ico"
+IDI_ADDSTATUS ICON "../../chat/Icons/addmode.ico"
+IDI_INFO ICON "../../chat/Icons/info.ico"
+IDI_KICK ICON "../../chat/Icons/kick.ico"
+IDI_MESSAGE ICON "../../chat/Icons/message.ico"
+IDI_NICK ICON "../../chat/Icons/nick.ico"
+IDI_NOTICE ICON "../../chat/Icons/notice.ico"
+IDI_PART ICON "../../chat/Icons/part.ico"
+IDI_QUIT ICON "../../chat/Icons/quit.ico"
+IDI_REMSTATUS ICON "../../chat/Icons/removestatus.ico"
+IDI_HIGHLIGHT ICON "../../chat/Icons/highlight.ico"
+IDI_MESSAGEOUT ICON "../../chat/Icons/messageout.ico"
+IDI_ACTION ICON "../../chat/Icons/action.ico"
+IDI_BKGCOLOR ICON "../../chat/Icons/bkgcolor.ico"
+IDI_CHANMGR ICON "../../chat/Icons/window.ico"
+IDI_FILTER ICON "../../chat/Icons/filter.ico"
+IDI_BLANK ICON "../../chat/Icons/blank.ico"
+IDI_STATUS3 ICON "../../chat/Icons/4.ico"
+IDI_STATUS2 ICON "../../chat/Icons/3.ico"
+IDI_STATUS4 ICON "../../chat/Icons/5.ico"
+IDI_STATUS1 ICON "../../chat/Icons/2.ico"
+IDI_STATUS0 ICON "../../chat/Icons/blank.ico"
+IDI_STATUS5 ICON "../../chat/Icons/6.ico"
+IDI_OVERLAY ICON "../../chat/Icons/overlay.ico"
+IDI_FILTER2 ICON "../../chat/Icons/filter2.ico"
+IDI_SHOWNICKLIST ICON "../../chat/icons/nicklist_show.ico"
+IDI_HIDENICKLIST ICON "../../chat/icons/nicklist_hide.ico"
+IDI_PULLDOWNARROW ICON "../../res/pulldown.ico"
+IDI_LEFTARROW ICON "../../res/leftarrow.ico"
+IDI_PULLUPARROW ICON "../../res/pullup.ico"
+IDI_RIGHTARROW ICON "../../res/rightarrow.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_UNKNOWNAVATAR BITMAP "../../res/unknown.bmp"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // German (Germany) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// German (Austria) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEA)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_IDENTIFY "__tabSRMM_ICONPACK 3.5__"
+END
+
+#endif // German (Austria) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/plugins/TabSRMM/icons/ICONSXP/ICONSXP.vcproj b/plugins/TabSRMM/icons/ICONSXP/ICONSXP.vcproj
new file mode 100644
index 0000000000..61831c008b
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONSXP/ICONSXP.vcproj
@@ -0,0 +1,442 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ICONSXP"
+ ProjectGUID="{987C5A57-A46B-4779-BB85-077E21F7BF7F}"
+ SccProjectName=""
+ SccLocalPath=""
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release Unicode 98|Win32"
+ OutputDirectory=".\$(ConfigurationName)"
+ IntermediateDirectory=".\$(ConfigurationName)"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\$(ConfigurationName)/ICONSXP.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="4"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ICONSXP_EXPORTS"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\$(ConfigurationName)/ICONSXP.pch"
+ AssemblerListingLocation=".\$(ConfigurationName)/"
+ ObjectFile=".\$(ConfigurationName)/"
+ ProgramDataBaseFileName=".\$(ConfigurationName)/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(ConfigurationName)\tabsrmm_icons.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\$(ConfigurationName)/tabsrmm_icons.pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ResourceOnlyDLL="true"
+ ImportLibrary="$(OutDir)/ICONSXP.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\$(ConfigurationName)/ICONSXP.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/ICONSXP.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="4"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ICONSXP_EXPORTS"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\Release/ICONSXP.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="Release\tabsrmm_icons.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Release/tabsrmm_icons.pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ResourceOnlyDLL="true"
+ ImportLibrary="$(OutDir)/ICONSXP.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Release/ICONSXP.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/ICONSXP.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ICONSXP_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\Debug/ICONSXP.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="Debug\ICONSXP.dll"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="Debug\ICONSXP.pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)/ICONSXP.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Debug/ICONSXP.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Headerdateien"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ >
+ <File
+ RelativePath="resource.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Ressourcendateien"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ >
+ <File
+ RelativePath="..\..\res\angeli-icons\AddXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\button.bold.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\button.fontface.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\button.italic.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\button.textcolor.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\button.underline.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\CloseXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\delete.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\empty.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\error.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\HistoryXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="ICONSXP.rc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\Incom.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\InfoXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\Logo.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\MultiXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\OptXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\Outg.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\Pencil.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\PicXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\Quote02.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\SaveXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\secureim_off.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\secureim_on.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\Send.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\smbutton.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\statuschange.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\Typing32.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\unknown.bmp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Quelldateien"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ >
+ </Filter>
+ <File
+ RelativePath="ReadMe.txt"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/plugins/TabSRMM/icons/ICONSXP/iconsxp_8.sln b/plugins/TabSRMM/icons/ICONSXP/iconsxp_8.sln
new file mode 100644
index 0000000000..4e91730275
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONSXP/iconsxp_8.sln
@@ -0,0 +1,23 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ICONSXP", "iconsxp_8.vcproj", "{987C5A57-A46B-4779-BB85-077E21F7BF7F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release Unicode 98|Win32 = Release Unicode 98|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Debug|Win32.Build.0 = Debug|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Release Unicode 98|Win32.ActiveCfg = Release Unicode 98|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Release Unicode 98|Win32.Build.0 = Release Unicode 98|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Release|Win32.ActiveCfg = Release|Win32
+ {987C5A57-A46B-4779-BB85-077E21F7BF7F}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/plugins/TabSRMM/icons/ICONSXP/iconsxp_8.vcproj b/plugins/TabSRMM/icons/ICONSXP/iconsxp_8.vcproj
new file mode 100644
index 0000000000..a9de3892a2
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONSXP/iconsxp_8.vcproj
@@ -0,0 +1,278 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="ICONSXP"
+ ProjectGUID="{987C5A57-A46B-4779-BB85-077E21F7BF7F}"
+ RootNamespace="ICONSXP"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ICONSXP_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/ICONSXP.dll"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/ICONSXP.pdb"
+ SubSystem="2"
+ ResourceOnlyDLL="true"
+ ImportLibrary="$(OutDir)/ICONSXP.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ICONSXP_EXPORTS"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/tabsrmm_icons.dll"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ResourceOnlyDLL="true"
+ ImportLibrary="$(OutDir)/ICONSXP.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release Unicode 98|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ICONSXP_EXPORTS"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/tabsrmm_icons.dll"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ResourceOnlyDLL="true"
+ ImportLibrary="$(OutDir)/ICONSXP.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Headerdateien"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Ressourcendateien"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\ICONSXP.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/plugins/TabSRMM/icons/ICONSXP/iconsxp_8.vpj b/plugins/TabSRMM/icons/ICONSXP/iconsxp_8.vpj
new file mode 100644
index 0000000000..59c21d96f5
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONSXP/iconsxp_8.vpj
@@ -0,0 +1,251 @@
+<!DOCTYPE Project SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpj.dtd">
+<Project
+ Version="10.0"
+ VendorName="SlickEdit"
+ WorkingDir="."
+ AssociatedFile="iconsxp_8.vcproj"
+ AssociatedFileType="microsoft visual studio visual c++">
+ <Config
+ Name="Debug|Win32"
+ OutputFile=""
+ CompilerConfigName="Visual Studio 2005">
+ <Includes>
+ <Include Dir="%(INCLUDE)"/>
+ </Includes>
+ <Menu>
+ <Target
+ Name="Compile"
+ MenuCaption="&amp;Compile"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveCurrent"
+ RunFromDir="%rw">
+ <Exec CmdLine='vstudiocompile "%f"'/>
+ </Target>
+ <Target
+ Name="Build"
+ MenuCaption="&amp;Build"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /build "%bn" /project "%rm" /projectconfig "%b"'/>
+ </Target>
+ <Target
+ Name="Rebuild"
+ MenuCaption="&amp;Rebuild"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /rebuild "%bn" /project "%rm" /projectconfig "%b"'/>
+ </Target>
+ <Target
+ Name="Debug"
+ MenuCaption="&amp;Debug"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w"'/>
+ </Target>
+ <Target
+ Name="Execute"
+ MenuCaption="E&amp;xecute"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='"%o"'/>
+ </Target>
+ <Target
+ Name="Resource Editor"
+ MenuCaption="Resource Editor"
+ ShowOnMenu="HideIfNoCmdLine"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine="devenv"/>
+ </Target>
+ <Target
+ Name="Build Solution"
+ MenuCaption="Build Solution"
+ ShowOnMenu="HideIfNoCmdLine"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /build "%bn"'/>
+ </Target>
+ <Target
+ Name="Clean Solution"
+ MenuCaption="Clean Solution"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /clean "%bn"'/>
+ </Target>
+ <Target
+ Name="Clean Project"
+ MenuCaption="Clean Project"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /clean "%bn" /project "%rm" /projectconfig "%b"'/>
+ </Target>
+ </Menu>
+ </Config>
+ <Config
+ Name="Release|Win32"
+ OutputFile=""
+ CompilerConfigName="Visual Studio 2005">
+ <Includes>
+ <Include Dir="%(INCLUDE)"/>
+ </Includes>
+ <Menu>
+ <Target
+ Name="Compile"
+ MenuCaption="&amp;Compile"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveCurrent"
+ RunFromDir="%rw">
+ <Exec CmdLine='vstudiocompile "%f"'/>
+ </Target>
+ <Target
+ Name="Build"
+ MenuCaption="&amp;Build"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /build "%bn" /project "%rm" /projectconfig "%b"'/>
+ </Target>
+ <Target
+ Name="Rebuild"
+ MenuCaption="&amp;Rebuild"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /rebuild "%bn" /project "%rm" /projectconfig "%b"'/>
+ </Target>
+ <Target
+ Name="Debug"
+ MenuCaption="&amp;Debug"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w"'/>
+ </Target>
+ <Target
+ Name="Execute"
+ MenuCaption="E&amp;xecute"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='"%o"'/>
+ </Target>
+ <Target
+ Name="Resource Editor"
+ MenuCaption="Resource Editor"
+ ShowOnMenu="HideIfNoCmdLine"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine="devenv"/>
+ </Target>
+ <Target
+ Name="Build Solution"
+ MenuCaption="Build Solution"
+ ShowOnMenu="HideIfNoCmdLine"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /build "%bn"'/>
+ </Target>
+ <Target
+ Name="Clean Solution"
+ MenuCaption="Clean Solution"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /clean "%bn"'/>
+ </Target>
+ <Target
+ Name="Clean Project"
+ MenuCaption="Clean Project"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /clean "%bn" /project "%rm" /projectconfig "%b"'/>
+ </Target>
+ </Menu>
+ </Config>
+ <Config
+ Name="Release Unicode 98|Win32"
+ OutputFile=""
+ CompilerConfigName="Visual Studio 2005">
+ <Includes>
+ <Include Dir="%(INCLUDE)"/>
+ </Includes>
+ <Menu>
+ <Target
+ Name="Compile"
+ MenuCaption="&amp;Compile"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveCurrent"
+ RunFromDir="%rw">
+ <Exec CmdLine='vstudiocompile "%f"'/>
+ </Target>
+ <Target
+ Name="Build"
+ MenuCaption="&amp;Build"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /build "%bn" /project "%rm" /projectconfig "%b"'/>
+ </Target>
+ <Target
+ Name="Rebuild"
+ MenuCaption="&amp;Rebuild"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /rebuild "%bn" /project "%rm" /projectconfig "%b"'/>
+ </Target>
+ <Target
+ Name="Debug"
+ MenuCaption="&amp;Debug"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w"'/>
+ </Target>
+ <Target
+ Name="Execute"
+ MenuCaption="E&amp;xecute"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='"%o"'/>
+ </Target>
+ <Target
+ Name="Resource Editor"
+ MenuCaption="Resource Editor"
+ ShowOnMenu="HideIfNoCmdLine"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine="devenv"/>
+ </Target>
+ <Target
+ Name="Build Solution"
+ MenuCaption="Build Solution"
+ ShowOnMenu="HideIfNoCmdLine"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveWorkspaceFiles"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /build "%bn"'/>
+ </Target>
+ <Target
+ Name="Clean Solution"
+ MenuCaption="Clean Solution"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /clean "%bn"'/>
+ </Target>
+ <Target
+ Name="Clean Project"
+ MenuCaption="Clean Project"
+ CaptureOutputWith="ProcessBuffer"
+ SaveOption="SaveNone"
+ RunFromDir="%rw">
+ <Exec CmdLine='devenv "%w" /clean "%bn" /project "%rm" /projectconfig "%b"'/>
+ </Target>
+ </Menu>
+ </Config>
+</Project>
diff --git a/plugins/TabSRMM/icons/ICONSXP/iconsxp_9.vcproj b/plugins/TabSRMM/icons/ICONSXP/iconsxp_9.vcproj
new file mode 100644
index 0000000000..cd6b11ec61
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONSXP/iconsxp_9.vcproj
@@ -0,0 +1,402 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="ICONSXP"
+ ProjectGUID="{987C5A57-A46B-4779-BB85-077E21F7BF7F}"
+ RootNamespace="ICONSXP"
+ Keyword="Win32Proj"
+ SccProjectName=""
+ SccLocalPath=""
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ICONSXP_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/ICONSXP.dll"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/ICONSXP.pdb"
+ SubSystem="2"
+ ResourceOnlyDLL="true"
+ ImportLibrary="$(OutDir)/ICONSXP.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ICONSXP_EXPORTS"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/tabsrmm_icons.dll"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ResourceOnlyDLL="true"
+ ImportLibrary="$(OutDir)/ICONSXP.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release Unicode 98|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ICONSXP_EXPORTS"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/tabsrmm_icons.dll"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ResourceOnlyDLL="true"
+ ImportLibrary="$(OutDir)/ICONSXP.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Quelldateien"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ </Filter>
+ <Filter
+ Name="Headerdateien"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Ressourcendateien"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath="..\..\res\angeli-icons\AddXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\button.bold.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\button.fontface.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\button.italic.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\button.textcolor.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\button.underline.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\CloseXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\delete.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\empty.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\error.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\HistoryXP.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\ICONSXP.rc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\Incom.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\InfoXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\Logo.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\MultiXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\OptXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\Outg.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\Pencil.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\PicXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\Quote02.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\SaveXP.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\secureim_off.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\secureim_on.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\angeli-icons\Send.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\smbutton.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\statuschange.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\Typing32.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\..\res\unknown.bmp"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\ReadMe.txt"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/plugins/TabSRMM/icons/ICONSXP/resource.h b/plugins/TabSRMM/icons/ICONSXP/resource.h
new file mode 100644
index 0000000000..7e9a8f06cc
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONSXP/resource.h
@@ -0,0 +1,127 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by ICONSXP.rc
+//
+
+// standard toolbar icons
+
+#define IDI_HISTORY 1 /* history button */
+#define IDI_MSGLOGOPT 2 /* message log options */
+#define IDI_ADDCONTACT 3 /* add contact symbol (not a button anymore) */
+#define IDI_MULTISEND 4 /* multisend (not a button anymore, symbol still needed) */
+#define IDI_TYPING 5 /* typing notify icon in the statusbar */
+#define IDI_QUOTE 6 /* quote button */
+#define IDI_SAVE 7 /* close tab (with non-empty message area) */
+#define IDI_SEND 8 /* send button */
+#define IDI_CONTACTPIC 9 /* avatar button */
+#define IDI_CLOSEMSGDLG 10 /* close tab (when message area is empty) */
+#define IDI_USERMENU 11 /* user menu pulldown */
+#define IDI_CLOCK 12 /* clock for infobar */
+
+// extended toolbar icons (formatting, etc..)
+
+#define IDI_SMILEYICON 50 /* smiley button fallback */
+#define IDI_FONTBOLD 51 /* bold */
+#define IDI_FONTITALIC 52 /* italic */
+#define IDI_FONTUNDERLINE 53 /* underline */
+#define IDI_FONTFACE 54 /* font face (currently not in use) */
+#define IDI_FONTCOLOR 55 /* font color (not in use yet) */
+#define IDI_STRIKEOUT 56 /* strikedout */
+
+//Message log events
+
+#define IDI_ICONIN 110 /* incoming message icon */
+#define IDI_ICONOUT 111 /* outgoing message icon */
+#define IDI_STATUSCHANGE 112 /* status changes */
+#define IDI_MSGERROR 113 /* error message */
+
+// misc icons, status bar etc.
+
+#define IDI_SELFTYPING_ON 130 /* sending typing notify is on */
+#define IDI_SELFTYPING_OFF 131 /* sending typing notify is off */
+#define IDI_SECUREIM_ENABLED 132 /* connection is secured via secureim */
+#define IDI_SECUREIM_DISABLED 133 /* connection is not secured */
+#define IDI_SOUNDSON 134 /* msg window sounds are enabled */
+
+#define IDI_CONTAINER 136 /* static container icon */
+
+#define IDI_SESSIONLIST 137 /* session list */
+#define IDI_IMGTAG 138 /* image tag button */
+#define IDI_RECENTLIST 139 /* recent contact list */
+#define IDI_CONFIGSIDEBAR 140 /* sidebar config */
+#define IDI_USERPREFS 141 /* user preferences */
+
+/* arrows */
+
+#define IDI_PULLDOWNARROW 160
+#define IDI_LEFTARROW 161
+#define IDI_PULLUPARROW 162
+#define IDI_RIGHTARROW 163
+
+
+// reserved icons
+
+#define IDI_EMPTY 170
+#define IDI_IMAGETAG 171
+
+#define IDI_TRAYANIM1 190
+#define IDI_TRAYANIM2 191
+#define IDI_TRAYANIM3 192
+#define IDI_TRAYANIM4 193
+
+// chat misc
+
+#define IDI_TOPICBUT 200
+#define IDI_BKGCOLOR 201
+#define IDI_CHANMGR 202
+#define IDI_FILTER 203
+#define IDI_FILTER2 204
+#define IDI_OVERLAY 205
+#define IDI_STATUS3 206
+#define IDI_STATUS2 207
+#define IDI_STATUS4 208
+#define IDI_STATUS1 209
+#define IDI_STATUS0 210
+#define IDI_STATUS5 211
+#define IDI_BLANK 212
+#define IDI_SHOWNICKLIST 213
+#define IDI_HIDENICKLIST 214
+
+// chat log
+
+#define IDI_JOIN 250
+#define IDI_PART 251
+#define IDI_QUIT 252
+#define IDI_KICK 253
+#define IDI_NICK 254
+#define IDI_NOTICE 255
+#define IDI_MESSAGE 256
+#define IDI_MESSAGEOUT 257
+#define IDI_TOPIC 258
+#define IDI_INFO 259
+#define IDI_ADDSTATUS 260
+#define IDI_REMSTATUS 261
+#define IDI_ACTION 262
+#define IDI_HIGHLIGHT 263
+#define IDI_TAG1 264
+#define IDI_TAG2 265
+
+
+
+// non icon related
+//
+
+#define IDB_UNKNOWNAVATAR 100
+#define IDS_IDENTIFY 101 /* id string resource */
+
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dep b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dep
new file mode 100644
index 0000000000..17150fe02e
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dep
@@ -0,0 +1,77 @@
+# Microsoft Developer Studio Generated Dependency File, included by ICONS_NOVA.mak
+
+.\ICONS_NOVA.rc : \
+ "..\..\chat\icons\nova\2.ico"\
+ "..\..\chat\icons\nova\3.ico"\
+ "..\..\chat\icons\nova\4.ico"\
+ "..\..\chat\icons\nova\5.ico"\
+ "..\..\chat\icons\nova\6.ico"\
+ "..\..\chat\icons\nova\action.ico"\
+ "..\..\chat\icons\nova\addmode.ico"\
+ "..\..\chat\icons\nova\bkgcolor.ico"\
+ "..\..\chat\icons\nova\blank.ico"\
+ "..\..\chat\icons\nova\filter.ico"\
+ "..\..\chat\icons\nova\filter2.ico"\
+ "..\..\chat\icons\nova\highlight.ico"\
+ "..\..\chat\icons\nova\info.ico"\
+ "..\..\chat\icons\nova\join.ico"\
+ "..\..\chat\icons\nova\kick.ico"\
+ "..\..\chat\icons\nova\message.ico"\
+ "..\..\chat\icons\nova\messageout.ico"\
+ "..\..\chat\icons\nova\nick.ico"\
+ "..\..\chat\icons\nova\nicklist_hide.ico"\
+ "..\..\chat\icons\nova\nicklist_show.ico"\
+ "..\..\chat\icons\nova\notice.ico"\
+ "..\..\chat\icons\nova\overlay.ico"\
+ "..\..\chat\icons\nova\part.ico"\
+ "..\..\chat\icons\nova\quit.ico"\
+ "..\..\chat\icons\nova\removestatus.ico"\
+ "..\..\chat\icons\nova\tag1.ico"\
+ "..\..\chat\icons\nova\tag2.ico"\
+ "..\..\chat\icons\nova\topic.ico"\
+ "..\..\chat\icons\nova\topicbut.ico"\
+ "..\..\chat\icons\nova\window.ico"\
+ "..\..\res\leftarrow.ico"\
+ "..\..\res\MessAnim\m1.ico"\
+ "..\..\res\MessAnim\m2.ico"\
+ "..\..\res\MessAnim\m3.ico"\
+ "..\..\res\MessAnim\m4.ico"\
+ "..\..\res\nova\avatar.ico"\
+ "..\..\res\nova\block.ico"\
+ "..\..\res\nova\bold.ico"\
+ "..\..\res\nova\check.ico"\
+ "..\..\res\nova\clock.ico"\
+ "..\..\res\nova\delete.ico"\
+ "..\..\res\nova\emoticon.ico"\
+ "..\..\res\nova\file.ico"\
+ "..\..\res\nova\font.ico"\
+ "..\..\res\nova\font2.ico"\
+ "..\..\res\nova\history.ico"\
+ "..\..\res\nova\Incom.ico"\
+ "..\..\res\nova\info.ico"\
+ "..\..\res\nova\italic.ico"\
+ "..\..\res\nova\message.ico"\
+ "..\..\res\nova\mtn.ico"\
+ "..\..\res\nova\multisend.ico"\
+ "..\..\res\nova\nomtn.ico"\
+ "..\..\res\nova\options.ico"\
+ "..\..\res\nova\outg.ico"\
+ "..\..\res\nova\pencil.ico"\
+ "..\..\res\nova\plus.ico"\
+ "..\..\res\nova\quote.ico"\
+ "..\..\res\nova\recentlist.ico"\
+ "..\..\res\nova\sbaroptions.ico"\
+ "..\..\res\nova\secureOff.ico"\
+ "..\..\res\nova\secureOn.ico"\
+ "..\..\res\nova\slist.ico"\
+ "..\..\res\nova\sounds_on.ico"\
+ "..\..\res\nova\Status change.ico"\
+ "..\..\res\nova\strike.ico"\
+ "..\..\res\nova\underline.ico"\
+ "..\..\res\nova\userprefs.ico"\
+ "..\..\res\pulldown.ico"\
+ "..\..\res\pullup.ico"\
+ "..\..\res\rightarrow.ico"\
+ "..\..\res\unknown.bmp"\
+ "..\..\tabmodplus\icons\imgopen.ico"\
+
diff --git a/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dsp b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dsp
new file mode 100644
index 0000000000..404ea90f7a
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dsp
@@ -0,0 +1,74 @@
+# Microsoft Developer Studio Project File - Name="ICONS_NOVA" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=ICONS_NOVA - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "ICONS_NOVA.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "ICONS_NOVA.mak" CFG="ICONS_NOVA - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ICONS_NOVA - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ICONS_NOVA___Win32_Release"
+# PROP BASE Intermediate_Dir "ICONS_NOVA___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ICONS_NOVA_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /Za /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ICONS_NOVA_EXPORTS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0xc07 /d "NDEBUG"
+# ADD RSC /l 0xc07 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 /nologo /dll /pdb:none /machine:I386 /nodefaultlib /out:"..\..\..\..\bin\Release Unicode\Icons\tabsrmm_icons.dll" /noentry
+# Begin Target
+
+# Name "ICONS_NOVA - Win32 Release"
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\ICONSXP\resource.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\ICONS_NOVA.rc
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dsw b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dsw
new file mode 100644
index 0000000000..6ca6b426fb
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "ICONS_NOVA"=.\ICONS_NOVA.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.mak b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.mak
new file mode 100644
index 0000000000..ca0be712c0
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.mak
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on ICONS_NOVA.dsp
+!IF "$(CFG)" == ""
+CFG=ICONS_NOVA - Win32 Release
+!MESSAGE No configuration specified. Defaulting to ICONS_NOVA - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "ICONS_NOVA - Win32 Release"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "ICONS_NOVA.mak" CFG="ICONS_NOVA - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ICONS_NOVA - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "..\..\..\..\bin\Release Unicode\Icons\tabsrmm_icons.dll"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\ICONS_NOVA.res"
+ -@erase "$(OUTDIR)\tabsrmm_icons.exp"
+ -@erase "..\..\..\..\bin\Release Unicode\Icons\tabsrmm_icons.dll"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\ICONS_NOVA.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=/nologo /dll /pdb:none /machine:I386 /nodefaultlib /out:"..\..\..\..\bin\Release Unicode\Icons\tabsrmm_icons.dll" /implib:"$(OUTDIR)\tabsrmm_icons.lib" /noentry
+LINK32_OBJS= \
+ "$(INTDIR)\ICONS_NOVA.res"
+
+"..\..\..\..\bin\Release Unicode\Icons\tabsrmm_icons.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /ML /Za /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ICONS_NOVA_EXPORTS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+RSC_PROJ=/l 0xc07 /fo"$(INTDIR)\ICONS_NOVA.res" /d "NDEBUG"
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("ICONS_NOVA.dep")
+!INCLUDE "ICONS_NOVA.dep"
+!ELSE
+!MESSAGE Warning: cannot find "ICONS_NOVA.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "ICONS_NOVA - Win32 Release"
+SOURCE=.\ICONS_NOVA.rc
+
+"$(INTDIR)\ICONS_NOVA.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) $(RSC_PROJ) $(SOURCE)
+
+
+
+!ENDIF
+
diff --git a/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.rc b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.rc
new file mode 100644
index 0000000000..3e78602345
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.rc
@@ -0,0 +1,175 @@
+// Microsoft Visual C++ generated resource script.
+//
+
+#include "../iconsxp/resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// German (Germany) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_HISTORY ICON "../../res/nova/history.ico"
+IDI_MSGLOGOPT ICON "../../res/nova/options.ico"
+IDI_ADDCONTACT ICON "../../res/nova/plus.ico"
+IDI_MULTISEND ICON "../../res/nova/multisend.ico"
+IDI_TYPING ICON "../../res/nova/pencil.ico"
+IDI_QUOTE ICON "../../res/nova/quote.ico"
+IDI_SAVE ICON "../../res/nova/file.ico"
+IDI_SEND ICON "../../res/nova/check.ico"
+IDI_CONTACTPIC ICON "../../res/nova/avatar.ico"
+IDI_USERMENU ICON "../../res/nova/info.ico"
+IDI_MSGERROR ICON "../../res/nova/block.ico"
+IDI_CLOSEMSGDLG ICON "../../res/nova/delete.ico"
+IDI_CLOCK ICON "../../res/nova/clock.ico"
+IDI_ICONIN ICON "../../res/nova/Incom.ico"
+IDI_ICONOUT ICON "../../res/nova/outg.ico"
+IDI_SMILEYICON ICON "../../res/nova/emoticon.ico"
+IDI_SELFTYPING_ON ICON "../../res/nova/mtn.ico"
+IDI_SELFTYPING_OFF ICON "../../res/nova/nomtn.ico"
+IDI_CONTAINER ICON "../../res/nova/message.ico"
+IDI_SECUREIM_ENABLED ICON "../../res/nova/secureOn.ico"
+IDI_SECUREIM_DISABLED ICON "../../res/nova/secureOff.ico"
+IDI_STATUSCHANGE ICON "../../res/nova/Status change.ico"
+IDI_FONTBOLD ICON "../../res/nova/bold.ico"
+IDI_FONTITALIC ICON "../../res/nova/italic.ico"
+IDI_FONTUNDERLINE ICON "../../res/nova/underline.ico"
+IDI_STRIKEOUT ICON "../../res/nova/strike.ico"
+IDI_FONTFACE ICON "../../res/nova/font.ico"
+IDI_FONTCOLOR ICON "../../res/nova/font2.ico"
+IDI_SOUNDSON ICON "../../res/nova/sounds_on.ico"
+IDI_SESSIONLIST ICON "../../res/nova/slist.ico"
+IDI_CONFIGSIDEBAR ICON "../../res/nova/sbaroptions.ico"
+IDI_IMAGETAG ICON "../../tabmodplus/icons/imgopen.ico"
+IDI_RECENTLIST ICON "../../res/nova/recentlist.ico"
+IDI_USERPREFS ICON "../../res/nova/userprefs.ico"
+IDI_TRAYANIM1 ICON "../../res/MessAnim/m1.ico"
+IDI_TRAYANIM2 ICON "../../res/MessAnim/m2.ico"
+IDI_TRAYANIM3 ICON "../../res/MessAnim/m3.ico"
+IDI_TRAYANIM4 ICON "../../res/MessAnim/m4.ico"
+IDI_TAG1 ICON "../../chat/icons/nova/tag1.ico"
+IDI_TAG2 ICON "../../chat/icons/nova/tag2.ico"
+IDI_TOPICBUT ICON "../../chat/icons/nova/topicbut.ico"
+IDI_JOIN ICON "../../chat/icons/nova/join.ico"
+IDI_TOPIC ICON "../../chat/icons/nova/topic.ico"
+IDI_ADDSTATUS ICON "../../chat/icons/nova/addmode.ico"
+IDI_INFO ICON "../../chat/icons/nova/info.ico"
+IDI_KICK ICON "../../chat/icons/nova/kick.ico"
+IDI_MESSAGE ICON "../../chat/icons/nova/message.ico"
+IDI_NICK ICON "../../chat/icons/nova/nick.ico"
+IDI_NOTICE ICON "../../chat/icons/nova/notice.ico"
+IDI_PART ICON "../../chat/icons/nova/part.ico"
+IDI_QUIT ICON "../../chat/icons/nova/quit.ico"
+IDI_REMSTATUS ICON "../../chat/icons/nova/removestatus.ico"
+IDI_HIGHLIGHT ICON "../../chat/icons/nova/highlight.ico"
+IDI_MESSAGEOUT ICON "../../chat/icons/nova/messageout.ico"
+IDI_ACTION ICON "../../chat/icons/nova/action.ico"
+IDI_BKGCOLOR ICON "../../chat/icons/nova/bkgcolor.ico"
+IDI_CHANMGR ICON "../../chat/icons/nova/window.ico"
+IDI_FILTER ICON "../../chat/icons/nova/filter.ico"
+IDI_BLANK ICON "../../chat/icons/nova/blank.ico"
+IDI_STATUS3 ICON "../../chat/icons/nova/4.ico"
+IDI_STATUS2 ICON "../../chat/icons/nova/3.ico"
+IDI_STATUS4 ICON "../../chat/icons/nova/5.ico"
+IDI_STATUS1 ICON "../../chat/icons/nova/2.ico"
+IDI_STATUS0 ICON "../../chat/icons/nova/blank.ico"
+IDI_STATUS5 ICON "../../chat/icons/nova/6.ico"
+IDI_OVERLAY ICON "../../chat/icons/nova/overlay.ico"
+IDI_FILTER2 ICON "../../chat/icons/nova/filter2.ico"
+IDI_SHOWNICKLIST ICON "../../chat/icons/nova/nicklist_show.ico"
+IDI_HIDENICKLIST ICON "../../chat/icons/nova/nicklist_hide.ico"
+IDI_PULLDOWNARROW ICON "../../res/pulldown.ico"
+IDI_LEFTARROW ICON "../../res/leftarrow.ico"
+IDI_PULLUPARROW ICON "../../res/pullup.ico"
+IDI_RIGHTARROW ICON "../../res/rightarrow.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_UNKNOWNAVATAR BITMAP "../../res/unknown.bmp"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // German (Germany) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// German (Austria) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEA)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_IDENTIFY "__tabSRMM_ICONPACK 5.0__"
+END
+
+#endif // German (Austria) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.vcproj b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.vcproj
new file mode 100644
index 0000000000..67eb2d8efe
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA.vcproj
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ICONS_NOVA"
+ ProjectGUID="{F553F140-B7D3-4984-90B1-00D4831B8A6E}"
+ RootNamespace="ICONS_NOVA"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="2"
+ CharacterSet="0"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\tabsrmm_icons.dll"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ ResourceOnlyDLL="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="2"
+ CharacterSet="0"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\tabsrmm_icons.dll"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ResourceOnlyDLL="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\ICONSXP\resource.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\ICONS_NOVA.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+</VisualStudioProject>
diff --git a/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA_10.vcxproj b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA_10.vcxproj
new file mode 100644
index 0000000000..7fcc7ae668
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA_10.vcxproj
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>TabSRMM_icons</ProjectName>
+ <ProjectGuid>{F553F140-B7D3-4984-90B1-00D4831B8A6E}</ProjectGuid>
+ <RootNamespace>ICONS_NOVA</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)/Obj/$(ProjectName)\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)/Obj/$(ProjectName)\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\</IntDir>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <NoEntryPoint>true</NoEntryPoint>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <NoEntryPoint>true</NoEntryPoint>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <NoEntryPoint>true</NoEntryPoint>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <NoEntryPoint>true</NoEntryPoint>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="..\ICONSXP\resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="ICONS_NOVA.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA_10.vcxproj.filters b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA_10.vcxproj.filters
new file mode 100644
index 0000000000..3eb80668f3
--- /dev/null
+++ b/plugins/TabSRMM/icons/ICONS_NOVA/ICONS_NOVA_10.vcxproj.filters
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\ICONSXP\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="ICONS_NOVA.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/plugins/TabSRMM/include/ImageDataObject.h b/plugins/TabSRMM/include/ImageDataObject.h
new file mode 100644
index 0000000000..0e2c112827
--- /dev/null
+++ b/plugins/TabSRMM/include/ImageDataObject.h
@@ -0,0 +1,136 @@
+/*
+Miranda SmileyAdd Plugin
+Copyright (C) 2004 Rein-Peter de Boer (peacow)
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+//code taken partly from public example on the internet, source unknown.
+
+//make sure <richedit.h> is include before this file
+#include <richedit.h>
+#include <richole.h>
+#include <ole2.h>
+
+class CImageDataObject : IDataObject
+{
+public:
+ // returns true on success, false on failure
+ static bool InsertBitmap(IRichEditOle* pRichEditOle, HBITMAP hBitmap);
+ // returns true on success, false on failure
+ //static bool InsertIcon(IRichEditOle* pRichEditOle, HICON hIcon,
+ //COLORREF backgroundColor, int sizeX = 0, int sizeY = 0);
+
+private:
+ ULONG m_ulRefCnt;
+ BOOL m_bRelease;
+
+ STGMEDIUM m_stgmed;
+ FORMATETC m_format;
+
+public:
+ CImageDataObject() : m_ulRefCnt(0)
+ {
+ m_bRelease = FALSE;
+ }
+
+ ~CImageDataObject()
+ {
+ if (m_bRelease)
+ ::ReleaseStgMedium(&m_stgmed);
+ }
+
+ // IUnknown interface
+ STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
+ {
+ if (iid == IID_IUnknown || iid == IID_IDataObject)
+ {
+ *ppvObject = this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ return E_NOINTERFACE;
+ }
+
+ STDMETHOD_(ULONG, AddRef)(void)
+ {
+ m_ulRefCnt++;
+ return m_ulRefCnt;
+ }
+
+ STDMETHOD_(ULONG, Release)(void)
+ {
+ m_ulRefCnt--;
+ if (m_ulRefCnt == 0)
+ delete this;
+ return m_ulRefCnt;
+ }
+
+ // IDataObject Interface
+ STDMETHOD(GetData)(FORMATETC *pformatetcIn, STGMEDIUM *pmedium) {
+ HANDLE hDst;
+ hDst = ::OleDuplicateData(m_stgmed.hBitmap, CF_BITMAP, 0);
+ if (hDst == NULL)
+ return E_HANDLE;
+
+ pmedium->tymed = TYMED_GDI;
+ pmedium->hBitmap = (HBITMAP)hDst;
+ pmedium->pUnkForRelease = NULL;
+
+ return S_OK;
+ }
+
+ STDMETHOD(GetDataHere)(FORMATETC* pformatetc, STGMEDIUM* pmedium ) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(QueryGetData)(FORMATETC* pformatetc ) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(GetCanonicalFormatEtc)(FORMATETC* pformatectIn ,FORMATETC* pformatetcOut ) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(SetData)(FORMATETC* pformatetc , STGMEDIUM* pmedium , BOOL fRelease ) {
+ m_format = *pformatetc;
+ m_stgmed = *pmedium;
+
+ return S_OK;
+ }
+
+ STDMETHOD(EnumFormatEtc)(DWORD dwDirection , IEnumFORMATETC** ppenumFormatEtc ) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(DAdvise)(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink,
+ DWORD *pdwConnection) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(DUnadvise)(DWORD dwConnection) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise) {
+ return E_NOTIMPL;
+ }
+
+ // Other
+ void SetBitmap(HBITMAP hBitmap);
+ IOleObject *GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage);
+};
+
diff --git a/plugins/TabSRMM/include/contactcache.h b/plugins/TabSRMM/include/contactcache.h
new file mode 100644
index 0000000000..4d1543ec0d
--- /dev/null
+++ b/plugins/TabSRMM/include/contactcache.h
@@ -0,0 +1,167 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: contactcache.h 12846 2010-10-01 03:26:02Z silvercircle $
+ *
+ * the contact cache
+ *
+ */
+
+#ifndef __CONTACTCACHE_H
+#define __CONTACTCACHE_H
+
+#define C_INVALID_PROTO "<proto error>"
+#define C_INVALID_ACCOUNT _T("<account error>")
+#define C_INVALID_PROTO_T _T("<proto error>")
+#define HISTORY_INITIAL_ALLOCSIZE 300
+
+
+struct TInputHistory {
+ TCHAR* szText;
+ size_t lLen;
+};
+
+struct TSessionStats {
+ enum {
+ BYTES_RECEIVED = 1,
+ BYTES_SENT = 2,
+ FAILURE = 3,
+ UPDATE_WITH_LAST_RCV= 4,
+ SET_LAST_RCV = 5,
+ INIT_TIMER = 6,
+ };
+
+ time_t started;
+ unsigned int iSent, iReceived, iSentBytes, iReceivedBytes;
+ unsigned int messageCount;
+ unsigned int iFailures;
+ unsigned int lastReceivedChars;
+ BOOL bWritten;
+};
+
+class CContactCache {
+public:
+
+ CContactCache () {}
+ CContactCache (const HANDLE hContact);
+ ~CContactCache ()
+ {
+ releaseAlloced();
+ }
+ void inc () { m_accessCount++; }
+ const bool isValid () const { return(m_Valid); }
+ const WORD getStatus () const { return(m_wStatus); }
+ const WORD getMetaStatus () const { return(m_wMetaStatus); }
+ const WORD getActiveStatus () const { return(m_isMeta ? m_wMetaStatus : m_wStatus); }
+ const WORD getOldStatus () const { return(m_wOldStatus); }
+ const TCHAR* getNick () const { return(m_szNick); }
+ const HANDLE getContact () const { return(m_hContact); }
+ const HANDLE getActiveContact () const { return(m_isMeta ? (m_hSubContact ? m_hSubContact : m_hContact) : m_hContact); }
+ const DWORD getIdleTS () const { return(m_idleTS); }
+ const char* getProto () const { return(m_szProto); }
+ const TCHAR* getProtoT () const { return(m_tszProto); }
+ const char* getMetaProto () const { return(m_szMetaProto ? m_szMetaProto : C_INVALID_PROTO); }
+ const TCHAR* getMetaProtoT () const { return(m_szMetaProto ? m_tszMetaProto : C_INVALID_PROTO_T); }
+ const char* getActiveProto () const { return(m_isMeta ? (m_szMetaProto ? m_szMetaProto : m_szProto) : m_szProto); }
+ const TCHAR* getActiveProtoT () const { return(m_isMeta ? (m_szMetaProto ? m_tszMetaProto : m_tszProto) : m_tszProto); }
+ bool isMeta () const { return(m_isMeta); }
+ bool isSubContact () const { return(m_isSubcontact); }
+ bool isFavorite () const { return(m_isFavorite); }
+ bool isRecent () const { return(m_isRecent); }
+ const TCHAR* getRealAccount () const { return(m_szAccount ? m_szAccount : C_INVALID_ACCOUNT); }
+ const TCHAR* getUIN () const { return(m_szUIN); }
+ const TCHAR* getStatusMsg () const { return(m_szStatusMsg); }
+ const TCHAR* getXStatusMsg () const { return(m_xStatusMsg); }
+ const TCHAR* getListeningInfo () const { return(m_ListeningInfo); }
+ BYTE getXStatusId () const { return(m_xStatus); }
+ const HWND getWindowData (TWindowData*& dat) const { dat = m_dat; return(m_hwnd); }
+ const HWND getHwnd () const { return(m_hwnd); }
+ int getMaxMessageLength ();
+
+ TWindowData* getDat () const { return(m_dat); }
+
+ void updateStats (int iType, size_t value = 0);
+ const DWORD getSessionStart () const { return(m_stats->started); }
+ const int getSessionMsgCount () const { return((int)m_stats->messageCount) ; }
+ void updateState ();
+ bool updateStatus ();
+ bool updateNick ();
+ void updateMeta (bool fForce = false);
+ bool updateUIN ();
+ void updateStatusMsg (const char *szKey = 0);
+ void setWindowData (const HWND hwnd = 0, TWindowData *dat = 0);
+ void resetMeta ();
+ void closeWindow ();
+ void deletedHandler ();
+ void updateFavorite ();
+ TCHAR* getNormalizedStatusMsg (const TCHAR *src, bool fStripAll = false);
+ HICON getIcon (int& iSize) const;
+
+ /*
+ * input history
+ */
+ void saveHistory (WPARAM wParam, LPARAM lParam);
+ void inputHistoryEvent (WPARAM wParam);
+
+ HANDLE m_hContact;
+ CContactCache* m_next;
+
+ static CContactCache* m_cCache;
+ static CContactCache* getContactCache(const HANDLE hContact);
+
+private:
+ void allocStats ();
+ void initPhaseTwo ();
+ void allocHistory ();
+ void releaseAlloced ();
+
+private:
+ size_t m_accessCount;
+ HANDLE m_hSubContact;
+ WORD m_wStatus, m_wMetaStatus;
+ WORD m_wOldStatus;
+ char* m_szProto, *m_szMetaProto;
+ TCHAR* m_tszProto, m_tszMetaProto[40];
+ TCHAR* m_szAccount;
+ TCHAR m_szNick[80], m_szUIN[80];
+ TCHAR* m_szStatusMsg, *m_xStatusMsg, *m_ListeningInfo;
+ BYTE m_xStatus;
+ DWORD m_idleTS;
+ bool m_isMeta, m_isSubcontact;
+ bool m_Valid;
+ bool m_isFavorite;
+ bool m_isRecent;
+ HWND m_hwnd;
+ int m_nMax;
+ int m_iHistoryCurrent, m_iHistoryTop, m_iHistorySize;
+ TWindowData* m_dat;
+ TSessionStats* m_stats;
+ TInputHistory* m_history;
+};
+
+#endif /* __CONTACTCACHE_H */
diff --git a/plugins/TabSRMM/include/controls.h b/plugins/TabSRMM/include/controls.h
new file mode 100644
index 0000000000..f20dbf076a
--- /dev/null
+++ b/plugins/TabSRMM/include/controls.h
@@ -0,0 +1,136 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: controls.h 11635 2010-04-26 07:17:39Z silvercircle $
+ *
+ * menu bar and status bar classes for the container window.
+ *
+ */
+
+#ifndef __CONTROLS_H
+#define __CONTROLS_H
+
+extern LONG_PTR CALLBACK StatusBarSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+class CMenuBar
+{
+public:
+ enum {
+ NR_BUTTONS = 8
+ };
+
+ CMenuBar(HWND hwndParent, const TContainerData *pContainer);
+ ~CMenuBar();
+
+ const RECT& TSAPI getClientRect();
+ void TSAPI Resize(WORD wWidth, WORD wHeight, BOOL redraw) const
+ {
+ ::SetWindowPos(m_hwndToolbar, 0, 4, 0, wWidth, m_size_y, SWP_NOZORDER | SWP_NOACTIVATE |
+ SWP_NOCOPYBITS|SWP_NOREDRAW);
+
+ }
+ LONG TSAPI getHeight() const;
+ void TSAPI Show(int showCmd) const
+ {
+ ::ShowWindow(m_hwndToolbar, showCmd);
+ }
+ LONG_PTR TSAPI Handle(const NMTOOLBAR *nmtb);
+ void TSAPI Cancel();
+ LONG_PTR TSAPI processMsg(const UINT msg, const WPARAM wParam, const LPARAM lParam);
+ bool TSAPI isContactMenu() const { return(m_isContactMenu); }
+ bool TSAPI isMainMenu() const { return(m_isMainMenu); }
+ void TSAPI configureMenu(void) const;
+ void TSAPI setActive(HMENU hMenu)
+ {
+ m_activeSubMenu = hMenu;
+ }
+ void setAero(bool fState) { m_isAero = fState; }
+ const bool getAero(void) const { return(m_isAero); }
+
+ const LRESULT processAccelerator(TCHAR a, UINT& ctlId) const
+ {
+ UINT _ctlId;
+
+ const LRESULT result = ::SendMessage(m_hwndToolbar, TB_MAPACCELERATOR, (WPARAM)a, (LPARAM)&_ctlId);
+ ctlId = _ctlId;
+
+ return(result);
+ }
+ void TSAPI autoShow(const int showcmd = 1);
+
+ const int idToIndex(const int id) const
+ {
+ for(int i = 0; i < NR_BUTTONS; i++) {
+ if(m_TbButtons[i].idCommand == id )
+ return(i);
+ }
+ return(-1);
+ }
+public:
+ static HHOOK m_hHook;
+ static HBITMAP m_MimIcon;
+
+private:
+ HWND m_hwndToolbar;
+ RECT m_rcClient;
+ TContainerData *m_pContainer;
+ HMENU m_activeMenu, m_activeSubMenu;;
+ int m_activeID;
+ bool m_fTracking;
+ bool m_isContactMenu;
+ bool m_isMainMenu;
+ bool m_isAero;
+ bool m_mustAutoHide;
+ LONG m_size_y;
+ WNDPROC m_oldWndProc;
+ /*
+ * for custom drawing
+ */
+ RECT m_rcItem;
+ HDC m_hdcDraw;
+ HBITMAP m_hbmDraw, m_hbmOld;
+ HANDLE m_hTheme;
+ HFONT m_hOldFont;
+
+ static TBBUTTON m_TbButtons[8];
+ static bool m_buttonsInit;
+ static CMenuBar *m_Owner;
+ static int m_MimIconRefCount;
+private:
+ LONG_PTR TSAPI customDrawWorker(NMCUSTOMDRAW *nm);
+ void TSAPI updateState(const HMENU hMenu) const;
+ void TSAPI invoke(const int id);
+ void TSAPI cancel(const int id);
+ void TSAPI obtainHook();
+ void TSAPI releaseHook();
+
+ static LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // subclassing for the toolbar control
+ static LRESULT CALLBACK MessageHook(int nCode, WPARAM wParam, LPARAM lParam); // message hook (only active when modal menus are active)
+};
+
+#endif /* __CONTROLS_H */
diff --git a/plugins/TabSRMM/include/functions.h b/plugins/TabSRMM/include/functions.h
new file mode 100644
index 0000000000..a08d922f01
--- /dev/null
+++ b/plugins/TabSRMM/include/functions.h
@@ -0,0 +1,199 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: functions.h 11636 2010-04-27 22:08:16Z silvercircle $
+ *
+ * Global function prototypes
+ *
+ */
+
+#ifndef _TABSRMM_FUNCTIONS_H
+#define _TABSRMM_FUNCTIONS_H
+
+int Chat_PreShutdown ();
+int Chat_ModulesLoaded (WPARAM wp, LPARAM lp);
+int AvatarChanged (WPARAM wParam, LPARAM lParam);
+int MyAvatarChanged (WPARAM wParam, LPARAM lParam);
+int IcoLibIconsChanged (WPARAM wParam, LPARAM lParam);
+int FontServiceFontsChanged (WPARAM wParam, LPARAM lParam);
+int SmileyAddOptionsChanged (WPARAM wParam, LPARAM lParam);
+int IEViewOptionsChanged (WPARAM wParam, LPARAM lParam);
+void RegisterFontServiceFonts ();
+int ModPlus_PreShutdown (WPARAM wparam, LPARAM lparam);
+int ModPlus_Init (WPARAM wparam, LPARAM lparam);
+LONG_PTR CALLBACK HotkeyHandlerDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+/*
+ * nen / event popup stuff
+ */
+
+int TSAPI NEN_ReadOptions (NEN_OPTIONS *options);
+int TSAPI NEN_WriteOptions (NEN_OPTIONS *options);
+int TSAPI UpdateTrayMenu (const TWindowData *dat, WORD wStatus, const char *szProto,
+ const TCHAR *szStatus, HANDLE hContact, DWORD fromEvent);
+static int TSAPI PopupPreview (NEN_OPTIONS *pluginOptions);
+void TSAPI DeletePopupsForContact (HANDLE hContact, DWORD dwMask);
+
+/*
+ * tray stuff
+ */
+
+void TSAPI CreateSystrayIcon (int create);
+void TSAPI FlashTrayIcon (HICON hIcon);
+void TSAPI UpdateTrayMenuState (TWindowData *dat, BOOL bForced);
+void TSAPI LoadFavoritesAndRecent ();
+void TSAPI AddContactToFavorites (HANDLE hContact, const TCHAR *szNickname, const char *szProto, TCHAR *szStatus,
+ WORD wStatus, HICON hIcon, BOOL mode, HMENU hMenu);
+void TSAPI CreateTrayMenus (int mode);
+void TSAPI HandleMenuEntryFromhContact (int iSelection);
+
+/*
+ * gneric msgwindow functions (creation, container management etc.)
+ */
+
+BOOL TSAPI IsUtfSendAvailable (HANDLE hContact);
+HWND TSAPI CreateNewTabForContact (TContainerData *pContainer, HANDLE hContact, int isSend,
+ const char *pszInitialText, BOOL bActivateTAb, BOOL bPopupContainer, BOOL bWantPopup, HANDLE hdbEvent);
+int TSAPI ActivateTabFromHWND (HWND hwndTab, HWND hwnd);
+void TSAPI FlashContainer (TContainerData *pContainer, int iMode, int iNum);
+void TSAPI CreateImageList (BOOL bInitial);
+TContainerData* TSAPI FindMatchingContainer(const TCHAR *szName, HANDLE hContact);
+TContainerData* TSAPI CreateContainer (const TCHAR *name, int iTemp, HANDLE hContactFrom);
+TContainerData* TSAPI FindContainerByName (const TCHAR *name);
+int TSAPI GetTabIndexFromHWND (HWND hwndTab, HWND hwnd);
+int TSAPI GetTabItemFromMouse (HWND hwndTab, POINT *pt);
+int TSAPI ActivateTabFromHWND (HWND hwndTab, HWND hwnd);
+void TSAPI AdjustTabClientRect (TContainerData *pContainer, RECT *rc);
+void TSAPI ReflashContainer (TContainerData *pContainer);
+HMENU TSAPI BuildMCProtocolMenu (HWND hwndDlg);
+
+TContainerData* TSAPI AppendToContainerList(TContainerData *pContainer);
+TContainerData* TSAPI RemoveContainerFromList(TContainerData *pContainer);
+
+void TSAPI DeleteContainer (int iIndex);
+void TSAPI RenameContainer (int iIndex, const TCHAR *newName);
+int TSAPI GetContainerNameForContact (HANDLE hContact, TCHAR *szName, int iNameLen);
+HMENU TSAPI BuildContainerMenu ();
+void TSAPI BuildCodePageList ();
+void TSAPI PreTranslateDates ();
+void TSAPI ApplyContainerSetting (TContainerData *pContainer, DWORD flags, UINT mode, bool fForceResize);
+void TSAPI BroadCastContainer (const TContainerData *pContainer, UINT message, WPARAM wParam, LPARAM lParam, BYTE iType = 0);
+void TSAPI GetDefaultContainerTitleFormat();
+INT_PTR MessageWindowOpened(WPARAM wParam, LPARAM lParam);
+void TSAPI SetAeroMargins (TContainerData *pContainer);
+int TABSRMM_FireEvent (HANDLE hContact, HWND hwnd, unsigned int type, unsigned int subType);
+
+LRESULT CALLBACK IEViewSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK HPPKFSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+/*
+ * skinning engine
+ */
+void TSAPI DrawAlpha (HDC hdcwnd, PRECT rc, DWORD basecolor, int alpha, DWORD basecolor2,
+ BYTE transparent, BYTE FLG_GRADIENT, BYTE FLG_CORNER, DWORD BORDERSTYLE, CImageItem *imageItem);
+// the cached message log icons
+
+void TSAPI CacheMsgLogIcons ();
+void TSAPI CacheLogFonts ();
+void TSAPI InitAPI ();
+void TSAPI LoadIconTheme ();
+int TSAPI LoadFromIconLib ();
+int TSAPI SetupIconLibConfig ();
+void TSAPI RTF_CTableInit ();
+
+INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+int TSAPI InitOptions (void);
+INT_PTR CALLBACK DlgProcContainer (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+int TSAPI DbEventIsShown (TWindowData *dat, DBEVENTINFO *dbei);
+void TSAPI StreamInEvents (HWND hwndDlg,HANDLE hDbEventFirst,int count,int fAppend, DBEVENTINFO *dbei_s);
+void TSAPI LoadLogfont (int i,LOGFONTA *lf,COLORREF *colour, char *szModule);
+
+
+// custom tab control
+
+void TSAPI ReloadTabConfig ();
+void TSAPI FreeTabConfig ();
+int TSAPI RegisterTabCtrlClass (void);
+
+// buttons
+
+int TSAPI LoadTSButtonModule (void);
+int TSAPI UnloadTSButtonModule ();
+
+
+/*
+ * debugging support
+ */
+
+int _DebugTraceW(const wchar_t *fmt, ...);
+int _DebugTraceA(const char *fmt, ...);
+int _DebugPopup(HANDLE hContact, const TCHAR *fmt, ...);
+int _DebugMessage(HWND hwndDlg, struct TWindowData *dat, const char *fmt, ...);
+
+// themes
+
+const TCHAR* TSAPI GetThemeFileName (int iMode);
+void TSAPI LoadLogfontFromINI (int i, char *szKey, LOGFONTA *lf, COLORREF *colour, const char *szIniFilename);
+int TSAPI CheckThemeVersion (const TCHAR *szIniFilename);
+void TSAPI WriteThemeToINI (const TCHAR *szIniFilename, TWindowData *dat);
+void TSAPI ReadThemeFromINI (const TCHAR *szIniFilename, TContainerData *dat, int noAdvanced, DWORD dwFlags);
+
+// compatibility
+
+// user prefs
+
+int TSAPI LoadLocalFlags (HWND hwnd, TWindowData *dat);
+
+//TypingNotify
+int TN_ModuleInit ();
+int TN_OptionsInitialize (WPARAM wParam, LPARAM lParam);
+int TN_ModuleDeInit ();
+int TN_TypingMessage (WPARAM wParam, LPARAM lParam);
+
+// mod plus
+
+int ChangeClientIconInStatusBar (const TWindowData *dat);
+
+// hotkeys
+
+LRESULT ProcessHotkeysByMsgFilter (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR ctrlId);
+
+void TSAPI DrawMenuItem (DRAWITEMSTRUCT *dis, HICON hIcon, DWORD dwIdle);
+
+/*
+ * dialog procedures
+ */
+
+INT_PTR CALLBACK SelectContainerDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcContainerOptions (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcAbout (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+#endif /* _TABSRMM_FUNCTIONS_H */
diff --git a/plugins/TabSRMM/include/generic_msghandlers.h b/plugins/TabSRMM/include/generic_msghandlers.h
new file mode 100644
index 0000000000..2139bdbeb0
--- /dev/null
+++ b/plugins/TabSRMM/include/generic_msghandlers.h
@@ -0,0 +1,67 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: generic_msghandlers.h 12058 2010-06-24 15:26:10Z silvercircle $
+ *
+ * prototypes from generic_msghandlers.c
+ *
+ */
+
+void TSAPI DM_SetDBButtonStates (HWND hwndChild, struct TWindowData *dat);
+int TSAPI BTN_GetStockItem (ButtonItem *item, const TCHAR *szName);
+HWND TSAPI DM_CreateClist (TWindowData *dat);
+
+void TSAPI DM_OptionsApplied (TWindowData *dat, WPARAM wParam, LPARAM lParam);
+void TSAPI DM_UpdateTitle (TWindowData *dat, WPARAM wParam, LPARAM lParam);
+LRESULT TSAPI DM_ScrollToBottom (TWindowData *dat, WPARAM wParam, LPARAM lParam);
+LRESULT TSAPI DM_LoadLocale (TWindowData *dat);
+LRESULT TSAPI DM_SaveLocale (TWindowData *dat, WPARAM wParam, LPARAM lParam);
+LRESULT TSAPI DM_UpdateLastMessage (const TWindowData *dat);
+LRESULT __stdcall DM_RecalcPictureSize (TWindowData *dat);
+LRESULT TSAPI DM_WMCopyHandler (HWND hwnd, WNDPROC oldWndProc, WPARAM wParam, LPARAM lParam);
+LRESULT TSAPI DM_MouseWheelHandler (HWND hwnd, HWND hwndParent, struct TWindowData *mwdat, WPARAM wParam, LPARAM lParam);
+LRESULT TSAPI DM_ThemeChanged (TWindowData *dat);
+void TSAPI DM_Typing (TWindowData *dat, bool fForceOff = false);
+void TSAPI DM_FreeTheme (TWindowData *dat);
+void TSAPI DM_NotifyTyping (TWindowData *dat, int mode);
+int TSAPI DM_SplitterGlobalEvent (TWindowData *dat, WPARAM wParam, LPARAM lParam);
+void TSAPI BB_InitDlgButtons (TWindowData *dat);
+
+BOOL TSAPI BB_SetButtonsPos (TWindowData *dat);
+void TSAPI BB_RedrawButtons (TWindowData *dat);
+void TSAPI BB_CustomButtonClick (TWindowData *dat,DWORD idFrom ,HWND hwndFrom, BOOL code) ;
+void TSAPI DM_EventAdded (TWindowData *dat, WPARAM wParam, LPARAM lParam);
+void TSAPI DM_InitRichEdit (TWindowData *dat);
+LRESULT TSAPI DM_ContainerCmdHandler (TContainerData *pContainer, UINT cmd, WPARAM wParam, LPARAM lParam);
+LRESULT TSAPI DM_MsgWindowCmdHandler (HWND hwndDlg, TContainerData *pContainer, TWindowData *dat, UINT cmd, WPARAM wParam, LPARAM lParam);
+LRESULT TSAPI DM_GenericHotkeysCheck (MSG *message, TWindowData *dat);
+void TSAPI DM_DismissTip (TWindowData *dat, const POINT& pt);
+void TSAPI DM_InitTip (TWindowData *dat);
+void TSAPI DM_HandleAutoSizeRequest(TWindowData *dat, REQRESIZE* rr);
+void TSAPI DM_SaveLogAsRTF (const TWindowData* dat);
+void TSAPI DM_CheckAutoHide (const TWindowData* dat, WPARAM wParam, LPARAM lParam);
diff --git a/plugins/TabSRMM/include/globals.h b/plugins/TabSRMM/include/globals.h
new file mode 100644
index 0000000000..f399fbe359
--- /dev/null
+++ b/plugins/TabSRMM/include/globals.h
@@ -0,0 +1,246 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: globals.h 13046 2010-10-28 10:02:50Z silvercircle $
+ *
+ * Plugin configuration variables and functions. Implemented as a class
+ * though there will always be only a single instance.
+ *
+ */
+
+#ifndef __GLOBALS_H
+#define __GLOBALS_H
+
+struct TSplitterBroadCast {
+ TContainerData *pSrcContainer;
+ TWindowData *pSrcDat;
+ LONG pos, pos_chat;
+ LONG off_chat, off_im;
+ LPARAM lParam;
+ BYTE bSync;
+};
+
+typedef BOOL (WINAPI *pfnSetMenuInfo )( HMENU hmenu, LPCMENUINFO lpcmi );
+
+class CRTException : public std::runtime_error
+{
+public:
+ CRTException(const char *szMsg, const TCHAR *szParam);
+ ~CRTException() {}
+
+ void display() const;
+
+private:
+ TCHAR m_szParam[MAX_PATH];
+};
+
+
+class CGlobals
+{
+public:
+ enum {
+ H_MS_MSG_SENDMESSAGE = 0,
+ H_MS_MSG_SENDMESSAGEW = 1,
+ H_MS_MSG_FORWARDMESSAGE = 2,
+ H_MS_MSG_GETWINDOWAPI = 3,
+ H_MS_MSG_GETWINDOWCLASS = 4,
+ H_MS_MSG_GETWINDOWDATA = 5,
+ H_MS_MSG_READMESSAGE = 6,
+ H_MS_MSG_TYPINGMESSAGE = 7,
+ H_MS_MSG_MOD_MESSAGEDIALOGOPENED = 8,
+ H_MS_TABMSG_SETUSERPREFS = 9,
+ H_MS_TABMSG_TRAYSUPPORT = 10,
+ H_MSG_MOD_GETWINDOWFLAGS = 11,
+ H_MS_TABMSG_SLQMGR = 12,
+ SERVICE_LAST = 13
+ };
+
+ CGlobals()
+ {
+ ::ZeroMemory(this, sizeof(CGlobals));
+ m_TypingSoundAdded = false;
+ }
+
+ ~CGlobals()
+ {
+ if(m_MenuBar)
+ ::DestroyMenu(m_MenuBar);
+
+ CContactCache* c = CContactCache::m_cCache, *cTemp;
+ while(c) {
+ cTemp = c->m_next;
+ delete c;
+ c = cTemp;
+ }
+ }
+ void reloadAdv();
+ void reloadSystemStartup();
+ void reloadSystemModulesChanged();
+ void reloadSettings(bool fReloadSkins = true);
+
+ void hookSystemEvents();
+ bool haveAutoSwitch();
+
+ const HMENU getMenuBar();
+
+ HWND g_hwndHotkeyHandler;
+ HICON g_iconIn, g_iconOut, g_iconErr, g_iconContainer, g_iconStatus;
+ HICON g_iconOverlayDisabled, g_iconOverlayEnabled, g_iconClock;
+ HCURSOR hCurSplitNS, hCurSplitWE, hCurHyperlinkHand;
+ HBITMAP g_hbmUnknown;
+ int g_MetaContactsAvail, g_SmileyAddAvail, g_WantIEView, g_PopupAvail, g_PopupWAvail, g_WantHPP;
+ int g_FlashAvatarAvail;
+ HIMAGELIST g_hImageList;
+ HICON g_IconMsgEvent, g_IconTypingEvent, g_IconFileEvent, g_IconSend;
+ HICON g_IconMsgEventBig, g_IconTypingEventBig;
+ HICON g_IconFolder, g_IconChecked, g_IconUnchecked;
+ HMENU g_hMenuContext, g_hMenuContainer, g_hMenuEncoding, g_hMenuTrayUnread;
+ HMENU g_hMenuFavorites, g_hMenuRecent, g_hMenuTrayContext;
+ HICON g_buttonBarIcons[NR_BUTTONBARICONS];
+ HICON g_sideBarIcons[NR_SIDEBARICONS];
+ HANDLE g_buttonBarIconHandles[23];
+ // dynamic options, need reload when options change
+ int m_SendOnShiftEnter;
+ int m_SendOnEnter;
+ int m_SendOnDblEnter;
+ int m_AutoLocaleSupport;
+ int m_AutoSwitchTabs;
+ int m_CutContactNameOnTabs;
+ int m_CutContactNameTo;
+ int m_StatusOnTabs;
+ int m_LogStatusChanges;
+ int m_UseDividers;
+ int m_DividersUsePopupConfig;
+ int m_MsgTimeout;
+ int m_EscapeCloses;
+ int m_FlashOnClist;
+ int m_AlwaysFullToolbarWidth;
+ int m_LimitStaticAvatarHeight;
+ int m_SendFormat;
+ int m_FormatWholeWordsOnly;
+ int m_RTLDefault;
+ int m_MathModAvail;
+ TCHAR m_MathModStartDelimiter[40];
+ int m_UnreadInTray;
+ int m_TrayFlashes;
+ int m_TrayFlashState;
+ BOOL m_SuperQuiet;
+ HANDLE m_UserMenuItem;
+ double g_DPIscaleX;
+ double g_DPIscaleY;
+ BOOL m_HideOnClose;
+ BOOL g_bSoundOnTyping;
+ BOOL m_AllowTab;
+ BYTE m_AllowOfflineMultisend;
+ BOOL g_bDisableAniAvatars;
+ HBITMAP m_hbmMsgArea;
+ BYTE g_iButtonsBarGap;
+ BYTE m_WinVerMajor;
+ BYTE m_WinVerMinor;
+ bool m_bIsXP, m_bIsVista, m_bIsWin7;
+ HWND m_hwndClist;
+ int m_TabAppearance;
+ struct myTabCtrl tabConfig;
+ int m_panelHeight, m_MUCpanelHeight;
+ WINDOWPLACEMENT m_GlobalContainerWpos;
+ int m_IdleDetect;
+ int m_smcxicon, m_smcyicon;
+ int m_PasteAndSend;
+ TCHAR *m_szNoStatus;
+ COLORREF crIncoming, crOutgoing, crOldIncoming, crOldOutgoing, crStatus;
+ BOOL bUnicodeBuild;
+ HFONT hFontCaption;
+ DWORD m_LangPackCP;
+ BYTE m_SmileyButtonOverride;
+ NONCLIENTMETRICS m_ncm;
+ HICON m_AnimTrayIcons[4];
+ BOOL m_visualMessageSizeIndicator;
+ BOOL m_autoSplit;
+ BOOL m_FlashOnMTN;
+ DWORD dwThreadID;
+ char szMetaName[256];
+ BYTE bMetaEnabled;
+ HANDLE m_hMessageWindowList, hUserPrefsWindowList;
+ bool m_chat_enabled;
+ HMENU m_MenuBar;
+ COLORREF m_ipBackgroundGradient;
+ COLORREF m_ipBackgroundGradientHigh;
+ COLORREF m_tbBackgroundHigh, m_tbBackgroundLow, m_fillColor, m_cRichBorders, m_genericTxtColor;
+ BYTE g_bClientInStatusBar;
+ BYTE m_dontUseDefaultKbd;
+ HANDLE hSvc[SERVICE_LAST];
+ HANDLE m_event_MsgWin, m_event_MsgPopup;
+ HANDLE m_hMenuItem;
+ BYTE m_useAeroPeek;
+
+ TSplitterBroadCast lastSPlitterPos;
+ TContainerSettings globalContainerSettings;
+
+ static HANDLE m_event_FoldersChanged;
+ static TCHAR* m_default_container_name;
+ static void cacheUpdateMetaChanged();
+ static void logStatusChange(WPARAM wParam, const CContactCache *c);
+
+ static void Ex_CopyEditToClipboard(HWND hWnd);
+ static void Ex_Handler();
+ static int Ex_ShowDialog(EXCEPTION_POINTERS *ep, const char *szFile, int line, wchar_t* szReason, bool fAllowContinue);
+ static INT_PTR CALLBACK Ex_DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+private:
+ bool m_TypingSoundAdded;
+ static HANDLE m_event_ModulesLoaded, m_event_PrebuildMenu, m_event_SettingChanged;
+ static HANDLE m_event_ContactDeleted, m_event_Dispatch, m_event_EventAdded;
+ static HANDLE m_event_IconsChanged, m_event_TypingEvent, m_event_ProtoAck, m_event_PreShutdown, m_event_OkToExit;
+ static HANDLE m_event_IcoLibChanged, m_event_AvatarChanged, m_event_MyAvatarChanged, m_event_FontsChanged;
+ static HANDLE m_event_SmileyAdd, m_event_IEView;
+ static HANDLE m_event_ME_MC_SUBCONTACTSCHANGED, m_event_ME_MC_FORCESEND, m_event_ME_MC_UNFORCESEND;
+
+ static EXCEPTION_RECORD m_exRecord;
+ static CONTEXT m_exCtx;
+ static LRESULT m_exLastResult;
+ static char m_exSzFile[MAX_PATH];
+ static wchar_t m_exReason[256];
+ static int m_exLine;
+ static bool m_exAllowContinue;
+private:
+ static int ModulesLoaded(WPARAM wParam, LPARAM lParam);
+ static int DBSettingChanged(WPARAM wParam, LPARAM lParam);
+ static int DBContactDeleted(WPARAM wParam, LPARAM lParam);
+ static int PreshutdownSendRecv(WPARAM wParam, LPARAM lParam);
+ static int MetaContactEvent(WPARAM wParam, LPARAM lParam);
+ static int OkToExit(WPARAM wParam, LPARAM lParam);
+ static void RestoreUnreadMessageAlerts(void);
+ static void RegisterWithUpdater();
+};
+
+extern CGlobals PluginConfig;
+extern CGlobals *pConfig;
+
+#define DPISCALEY_S(argY) ((int) ((double)(argY) * PluginConfig.g_DPIscaleY))
+#define DPISCALEX_S(argX) ((int) ((double)(argX) * PluginConfig.g_DPIscaleX))
+
+#endif /* __GLOBALS_H */
diff --git a/plugins/TabSRMM/include/infopanel.h b/plugins/TabSRMM/include/infopanel.h
new file mode 100644
index 0000000000..47e7345f53
--- /dev/null
+++ b/plugins/TabSRMM/include/infopanel.h
@@ -0,0 +1,220 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: infopanel.h 12396 2010-08-22 17:17:05Z silvercircle $
+ *
+ * the info area for both im and chat sessions
+ */
+
+#ifndef __INFOPANEL_H
+#define __INFOPANEL_H
+
+/*
+ * configuration data for the info panel (fonts, colors)
+ * this is global for all panels
+ */
+
+#define IPFONTCOUNT 6 // # of fonts needed for the info panel
+
+/*
+ * command ids for the info panel contextual menus
+ */
+
+#define CMD_IP_USERDETAILS 20000
+#define CMD_IP_USERPREFS 20001
+#define CMD_IP_ROOMPREFS 20002
+#define CMD_IP_HISTORY 20003
+#define CMD_IP_COPY 21000
+
+struct TInfoPanelConfig {
+ HFONT hFonts[IPFONTCOUNT];
+ COLORREF clrs[IPFONTCOUNT];
+ UINT height1, height2;
+};
+
+extern TCHAR *xStatusDescr[];
+
+/**
+ * a simple tooltip class using a richedit control to display its content. Allows
+ * for formatted text and clickable hyperlinks
+ *
+ * Used by: Info panel to display status messages, topics etc.
+ */
+class CTip
+{
+public:
+ enum {
+ TOP_BORDER = 25,
+ LEFT_BORDER = 2,
+ RIGHT_BORDER = 2,
+ BOTTOM_BORDER = 1,
+ LEFT_BAR_WIDTH = 20
+ };
+
+ CTip (const HWND hwndParent, const HANDLE hContact, const TCHAR *pszText = 0, const CInfoPanel *panel = 0);
+ ~CTip()
+ {
+ if(m_pszText)
+ mir_free(m_pszText);
+ }
+ void show (const RECT& rc, POINT& pt, const HICON hIcon = 0, const TCHAR *szTitle = 0);
+ const HWND getHwnd () const { return(m_hwnd); }
+
+ static void registerClass ();
+private:
+
+ INT_PTR CALLBACK WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ static INT_PTR CALLBACK WndProcStub (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ static INT_PTR CALLBACK RichEditProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+ HWND m_hwnd; // our window handle
+ HWND m_hRich; // handle of the rich edit child
+ HWND m_hwndParent; // parent window (used for position calculations and to send notifications)
+ HANDLE m_hContact; // contact handle
+ char* m_pszText; // the richedit text
+ SIZE m_szRich; // size of the richedit control (height auto-calculated to make it fit the text)
+ RECT m_rcRich; // adjusted rectangle for the richedit control (client coordinates)
+ const CInfoPanel* m_panel; // the info panel parent (if any)
+ HICON m_hIcon; // optional icon to show in the title line
+ const TCHAR* m_szTitle; // optional text to show in the title
+ int m_leftWidth;
+
+private:
+ static WNDPROC m_OldMessageEditProc; // stores original richedit wnd proc
+
+};
+
+/**
+ * the info panel class definition. The panel itself is not a real window class - it
+ * is implemented as a drawing canvas on the message window background.
+ *
+ * Each message session has its own info panel object
+ */
+class CInfoPanel
+{
+public:
+ enum {
+ DEGRADE_THRESHOLD = 37, // defines the height at which the infopanel will do the transition from 1 to 2 lines
+ LEFT_OFFSET_LOGO = 3
+ };
+ enum {
+ HOVER_NICK = 1,
+ HOVER_STATUS = 2,
+ HOVER_UIN = 4
+ };
+ enum {
+ HTNICK = 1,
+ HTUIN = 2,
+ HTSTATUS = 3,
+ HTNIRVANA = 0
+ };
+ CInfoPanel(TWindowData *dat)
+ {
+ if(dat) {
+ m_dat = dat;
+ m_isChat = dat->bType == SESSIONTYPE_CHAT ? true : false;
+ }
+ m_defaultHeight = PluginConfig.m_panelHeight;
+ m_defaultMUCHeight = PluginConfig.m_MUCpanelHeight;
+ m_hwndConfig = 0;
+ m_hoverFlags = 0;
+ m_tip = 0;
+ }
+
+ ~CInfoPanel()
+ {
+ if(m_hwndConfig)
+ ::DestroyWindow(m_hwndConfig);
+ saveHeight(true);
+ }
+
+ const LONG getHeight () const { return(m_height); }
+ void setHeight (LONG newHeight, bool fBroadcast = false);
+ bool isActive () const { return(m_active); }
+ bool isPrivateHeight () const { return(m_fPrivateHeight); }
+ DWORD isHovered () const { return(m_active ? m_hoverFlags : 0); }
+ const TWindowData* getDat () const { return(m_dat); }
+ void setActive (const int newActive);
+ void loadHeight ();
+ void saveHeight (bool fFlush = false);
+
+ void Configure () const;
+ void showHide () const;
+ bool getVisibility ();
+ void renderBG (const HDC hdc, RECT& rc, CSkinItem *item, bool fAero, bool fAutoCalc = true) const;
+ void renderContent (const HDC hdcMem);
+ void Invalidate (BOOL fErase = FALSE) const;
+ void trackMouse (POINT& pt);
+ int hitTest (POINT pt);
+ void handleClick (const POINT& pt);
+ void showTip (UINT ctrlId, const LPARAM lParam);
+ void hideTip (const HWND hWndNew);
+ int invokeConfigDialog (const POINT& pt);
+ void dismissConfig (bool fForced = false);
+
+public:
+ static TInfoPanelConfig m_ipConfig;
+ static int setPanelHandler (TWindowData *dat, WPARAM wParam, LPARAM lParam);
+ static INT_PTR CALLBACK avatarParentSubclass (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+private:
+ void mapRealRect (const RECT& rcSrc, RECT& rcDest, const SIZE& sz);
+ HFONT setUnderlinedFont (const HDC hdc, HFONT hFontOrig);
+ void RenderIPNickname (const HDC hdc, RECT& rc);
+ void RenderIPUIN (const HDC hdc, RECT& rcItem);
+ void RenderIPStatus (const HDC hdc, RECT& rcItem);
+ void Chat_RenderIPNickname (const HDC hdc, RECT& rcItem);
+ void Chat_RenderIPSecondLine (const HDC hdc, RECT& rcItem);
+ LRESULT cmdHandler (UINT cmd);
+ HMENU constructContextualMenu () const;
+ INT_PTR CALLBACK ConfigDlgProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ static INT_PTR CALLBACK ConfigDlgProcStub (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+private:
+ bool m_isChat; // is MUC session
+ bool m_active; // panel active and visible
+ bool m_fPrivateHeight;
+ bool m_fDialogCreated;
+ TWindowData* m_dat; // this one OWNS us...
+ LONG m_height; // height (determined by position of IDC_PANELSPLITTER)
+ LONG m_defaultHeight, m_defaultMUCHeight; // global values for the info bar height
+ HWND m_hwndConfig; // window handle of the config dialog window
+ HFONT m_configDlgFont, m_configDlgBoldFont;
+ SIZE m_szNick; // rectangle where the nick has been rendered,
+ /*
+ * these are used to store rectangles important to mouse tracking.
+ */
+ RECT m_rcNick;
+ RECT m_rcUIN;
+ RECT m_rcStatus;
+ DWORD m_hoverFlags;
+ CTip* m_tip;
+};
+
+#endif /* __INFOPANEL_H */
+
diff --git a/plugins/TabSRMM/include/mim.h b/plugins/TabSRMM/include/mim.h
new file mode 100644
index 0000000000..35783b1ec2
--- /dev/null
+++ b/plugins/TabSRMM/include/mim.h
@@ -0,0 +1,319 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: mim.h 12272 2010-08-04 08:24:08Z silvercircle $
+ *
+ * wraps some parts of Miranda API
+ * Also, OS dependent stuff (visual styles api etc.)
+ *
+ */
+
+#ifndef __MIM_H
+#define __MIM_H
+
+
+extern FI_INTERFACE *FIF;
+
+/*
+ * Win32 API definitions of functions dynamically obtained via GetProcAddress()
+ * - uxtheme
+ * - dwmapi
+ * - some GDI functions (AlphaBlend()..)
+ */
+typedef BOOL (WINAPI *SMI)( HMENU hmenu, LPCMENUINFO lpcmi );
+typedef HRESULT (WINAPI *DEFICA)(HWND hwnd, const MARGINS *margins);
+typedef HRESULT (WINAPI *DICE)(BOOL *);
+typedef DWORD (WINAPI *PSLWA)(HWND, DWORD, BYTE, DWORD);
+typedef BOOL (WINAPI *PULW)(HWND, HDC, POINT *, SIZE *, HDC, POINT *, COLORREF, BLENDFUNCTION *, DWORD);
+typedef BOOL (WINAPI *PFWEX)(FLASHWINFO *);
+typedef BOOL (WINAPI *PAB)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION);
+typedef BOOL (WINAPI *PGF)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG);
+
+typedef BOOL (WINAPI *PITA)();
+typedef HANDLE (WINAPI *POTD)(HWND, LPCWSTR);
+typedef UINT (WINAPI *PDTB)(HANDLE, HDC, int, int, RECT *, RECT *);
+typedef UINT (WINAPI *PCTD)(HANDLE);
+typedef UINT (WINAPI *PDTT)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, DWORD, RECT *);
+typedef UINT (WINAPI *PDTTE)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, RECT *, const DTTOPTS *);
+typedef BOOL (WINAPI *PITBPT)(HANDLE, int, int);
+typedef HRESULT (WINAPI *PDTPB)(HWND, HDC, RECT *);
+typedef HRESULT (WINAPI *PGTBCR)(HANDLE, HDC, int, int, const RECT *, const RECT *);
+
+typedef HMONITOR(WINAPI *MMFW)(HWND, DWORD);
+typedef BOOL (WINAPI *GMIA)(HMONITOR, LPMONITORINFO);
+typedef HRESULT (WINAPI *DRT)(HWND, HWND, PHTHUMBNAIL);
+typedef BOOL (WINAPI *ETDT)(HANDLE, DWORD);
+typedef HANDLE (WINAPI *BBP)(HDC, RECT *, BP_BUFFERFORMAT, BP_PAINTPARAMS *, HDC *);
+typedef HRESULT (WINAPI *EBP)(HANDLE, BOOL);
+typedef HRESULT (WINAPI *BPI)(void);
+typedef HRESULT (WINAPI *BPU)(void);
+typedef HRESULT (WINAPI *BBW)(HWND, DWM_BLURBEHIND *);
+typedef HRESULT (WINAPI *DGC)(DWORD *, BOOL *);
+typedef HRESULT (WINAPI *BPSA)(HANDLE, const RECT *, BYTE);
+typedef int (WINAPI *GLIX)(LPCWSTR, LCTYPE, LPCWSTR, int);
+typedef HRESULT (WINAPI *DWMSWA)(HWND, DWORD, LPCVOID, DWORD);
+typedef HRESULT (WINAPI *DWMIIB)(HWND);
+typedef HRESULT (WINAPI *DWMUT)(HTHUMBNAIL, DWM_THUMBNAIL_PROPERTIES *);
+typedef HRESULT (WINAPI *DURT)(HTHUMBNAIL);
+typedef HRESULT (WINAPI *DSIT)(HWND, HBITMAP, DWORD);
+typedef HRESULT (WINAPI *DSILP)(HWND, HBITMAP, POINT *, DWORD);
+
+/*
+ * used to encapsulate some parts of the Miranda API
+ * constructor does early time initialization - do NOT put anything
+ * here, except thngs that deal with the core and database API.
+ *
+ * it is UNSAFE to assume that any plugin provided services are available
+ * when the object is instantiated.
+ */
+
+class CMimAPI
+{
+public:
+ CMimAPI()
+ {
+ GetUTFI();
+ InitPaths();
+ InitAPI();
+ getAeroState();
+
+ LRESULT fi_version = CallService(MS_IMG_GETIFVERSION, 0, 0);
+ CallService(MS_IMG_GETINTERFACE, fi_version, (LPARAM)&FIF);
+
+ ::QueryPerformanceFrequency((LARGE_INTEGER *)&m_tFreq);
+ m_dFreq = (double)(1.0f / m_tFreq);
+ m_hChatLogLock = INVALID_HANDLE_VALUE;
+ }
+
+ ~CMimAPI() {
+ if (m_hUxTheme != 0)
+ FreeLibrary(m_hUxTheme);
+ if (m_hDwmApi != 0)
+ FreeLibrary(m_hDwmApi);
+ if (m_haveBufferedPaint)
+ m_pfnBufferedPaintUninit();
+
+ if(m_hChatLogLock != INVALID_HANDLE_VALUE)
+ CloseHandle(m_hChatLogLock);
+ }
+
+ /*
+ * database functions
+ */
+
+ DWORD FASTCALL GetDword (const HANDLE hContact, const char *szModule, const char *szSetting, DWORD uDefault) const;
+
+ DWORD FASTCALL GetDword (const char *szModule, const char *szSetting, DWORD uDefault) const;
+ DWORD FASTCALL GetDword (const char *szSetting, DWORD uDefault) const;
+ DWORD FASTCALL GetDword (const HANDLE hContact, const char *szSetting, DWORD uDefault) const;
+
+ int FASTCALL GetByte (const HANDLE hContact, const char *szModule, const char *szSetting, int uDefault) const;
+ int FASTCALL GetByte (const char *szModule, const char *szSetting, int uDefault) const;
+ int FASTCALL GetByte (const char *szSetting, int uDefault) const;
+ int FASTCALL GetByte (const HANDLE hContact, const char *szSetting, int uDefault) const;
+
+ INT_PTR FASTCALL GetTString (const HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) const;
+ INT_PTR FASTCALL GetString (const HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) const;
+
+ INT_PTR FASTCALL WriteDword (const HANDLE hContact, const char *szModule, const char *szSetting, DWORD value) const;
+ INT_PTR FASTCALL WriteDword (const char *szModule, const char *szSetting, DWORD value) const;
+
+ INT_PTR FASTCALL WriteByte (const HANDLE hContact, const char *szModule, const char *szSetting, BYTE value) const;
+ INT_PTR FASTCALL WriteByte (const char *szModule, const char *szSetting, BYTE value) const;
+
+ INT_PTR FASTCALL WriteTString (const HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *st) const;
+
+ /*
+ * utf helpers
+ */
+
+ char* FASTCALL utf8_decode (char* str, wchar_t** ucs2) const;
+ char* FASTCALL utf8_decodecp (char* str, int codepage, wchar_t** ucs2) const;
+ char* FASTCALL utf8_encode (const char* src) const;
+ char* FASTCALL utf8_encodecp (const char* src, int codepage) const;
+ char* FASTCALL utf8_encodeW (const wchar_t* src) const;
+ char* FASTCALL utf8_encodeT (const TCHAR* src) const;
+ TCHAR* FASTCALL utf8_decodeT (const char* src) const;
+ wchar_t* FASTCALL utf8_decodeW (const char* str) const;
+
+ /*
+ * path utilities
+ */
+
+ int pathIsAbsolute (const TCHAR *path) const;
+ size_t pathToAbsolute (const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase = 0) const;
+ size_t pathToRelative (const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase = 0) const;
+
+ const TCHAR* getDataPath() const { return(m_szProfilePath); }
+ const TCHAR* getSkinPath() const { return(m_szSkinsPath); }
+ const TCHAR* getSavedAvatarPath() const { return(m_szSavedAvatarsPath); }
+ const TCHAR* getChatLogPath() const { return(m_szChatLogsPath); }
+ const bool haveFoldersPlugin() const { return(m_haveFolders); }
+
+ const TCHAR* getUserDir();
+ void configureCustomFolders();
+ INT_PTR foldersPathChanged();
+
+ void startTimer();
+ void stopTimer (const char *szMsg = 0);
+ void timerMsg (const char *szMsg);
+ __int64 getTimerStart() const { return(m_tStart); }
+ __int64 getTimerStop() const { return(m_tStop); }
+ __int64 getTicks() const { return(m_tStop - m_tStart); }
+ double getFreq() const { return(m_dFreq); }
+ double getMsec() const { return(1000 * ((double)(m_tStop - m_tStart) * m_dFreq)); }
+
+ /*
+ * os dependant stuff (aero, visual styles etc.)
+ */
+
+ const bool isVSAPIState() const { return m_VsAPI; }
+ /**
+ * return status of Vista Aero
+ *
+ * @return bool: true if aero active, false otherwise
+ */
+ const bool isAero() const { return(m_isAero); }
+ const bool isDwmActive() const { return(m_DwmActive); }
+
+ /**
+ * Refresh Aero status.
+ * Called on:
+ * * plugin init
+ * * WM_DWMCOMPOSITIONCHANGED message received
+ *
+ * @return
+ */
+ bool getAeroState();
+ /**
+ * return status of visual styles theming engine (Windows XP+)
+ *
+ * @return bool: themes are enabled
+ */
+ bool isVSThemed()
+ {
+ return(m_isVsThemed);
+ }
+ /*
+ * window lists
+ */
+
+ void BroadcastMessage (UINT msg, WPARAM wParam, LPARAM lParam);
+ void BroadcastMessageAsync (UINT msg, WPARAM wParam, LPARAM lParam);
+ INT_PTR AddWindow (HWND hWnd, HANDLE h);
+ INT_PTR RemoveWindow (HWND hWnd);
+ HWND FindWindow (HANDLE h) const;
+
+ static int FoldersPathChanged(WPARAM wParam, LPARAM lParam); // hook subscriber for folders plugin
+ static const TCHAR* TSAPI StriStr(const TCHAR *szString, const TCHAR *szSearchFor);
+ static int TypingMessage(WPARAM wParam, LPARAM lParam);
+ static int ProtoAck(WPARAM wParam, LPARAM lParam);
+ static int PrebuildContactMenu(WPARAM wParam, LPARAM lParam);
+ static int DispatchNewEvent(WPARAM wParam, LPARAM lParam);
+ static int MessageEventAdded(WPARAM wParam, LPARAM lParam);
+public:
+ HANDLE m_hMessageWindowList;
+ /*
+ various function pointers
+ */
+ static PITA m_pfnIsThemeActive;
+ static POTD m_pfnOpenThemeData;
+ static PDTB m_pfnDrawThemeBackground;
+ static PCTD m_pfnCloseThemeData;
+ static PDTT m_pfnDrawThemeText;
+ static PDTTE m_pfnDrawThemeTextEx;
+ static PITBPT m_pfnIsThemeBackgroundPartiallyTransparent;
+ static PDTPB m_pfnDrawThemeParentBackground;
+ static PGTBCR m_pfnGetThemeBackgroundContentRect;
+ static ETDT m_pfnEnableThemeDialogTexture;
+ static PSLWA m_pSetLayeredWindowAttributes;
+ static PFWEX m_MyFlashWindowEx;
+ static PAB m_MyAlphaBlend;
+ static PGF m_MyGradientFill;
+ static DEFICA m_pfnDwmExtendFrameIntoClientArea;
+ static DICE m_pfnDwmIsCompositionEnabled;
+ static MMFW m_pfnMonitorFromWindow;
+ static GMIA m_pfnGetMonitorInfoA;
+ static DRT m_pfnDwmRegisterThumbnail;
+ static BPI m_pfnBufferedPaintInit;
+ static BPU m_pfnBufferedPaintUninit;
+ static BBP m_pfnBeginBufferedPaint;
+ static EBP m_pfnEndBufferedPaint;
+ static BBW m_pfnDwmBlurBehindWindow;
+ static DGC m_pfnDwmGetColorizationColor;
+ static BPSA m_pfnBufferedPaintSetAlpha;
+ static GLIX m_pfnGetLocaleInfoEx;
+ static DWMSWA m_pfnDwmSetWindowAttribute;
+ static DWMIIB m_pfnDwmInvalidateIconicBitmaps;
+ static DWMUT m_pfnDwmUpdateThumbnailProperties;
+ static DURT m_pfnDwmUnregisterThumbnail;
+ static DSIT m_pfnDwmSetIconicThumbnail;
+ static DSILP m_pfnDwmSetIconicLivePreviewBitmap;
+ static bool m_shutDown, m_haveBufferedPaint;
+
+ static DWORD m_MimVersion;
+
+private:
+ UTF8_INTERFACE m_utfi;
+ TCHAR m_szProfilePath[MAX_PATH + 2], m_szSkinsPath[MAX_PATH + 2], m_szSavedAvatarsPath[MAX_PATH + 2], m_szChatLogsPath[MAX_PATH + 2];
+ HMODULE m_hUxTheme, m_hDwmApi;
+ bool m_VsAPI;
+ bool m_isAero;
+ bool m_DwmActive;
+ bool m_isVsThemed;
+ HANDLE m_hDataPath, m_hSkinsPath, m_hAvatarsPath, m_hChatLogsPath;
+ __int64 m_tStart, m_tStop, m_tFreq;
+ double m_dFreq;
+ char m_timerMsg[256];
+ bool m_haveFolders;
+ HANDLE m_hChatLogLock;
+
+ void InitAPI();
+ void GetUTFI();
+ void InitPaths();
+
+private:
+ static TCHAR m_userDir[MAX_PATH + 2];
+};
+
+inline void CMimAPI::startTimer()
+{
+ ::QueryPerformanceCounter((LARGE_INTEGER *)&m_tStart);
+}
+
+inline void CMimAPI::stopTimer(const char *szMsg)
+{
+ ::QueryPerformanceCounter((LARGE_INTEGER *)&m_tStop);
+
+ if(szMsg)
+ timerMsg(szMsg);
+}
+
+extern CMimAPI *M;
+
+#endif /* __MIM_H */
diff --git a/plugins/TabSRMM/include/msgdlgutils.h b/plugins/TabSRMM/include/msgdlgutils.h
new file mode 100644
index 0000000000..d882e00fb0
--- /dev/null
+++ b/plugins/TabSRMM/include/msgdlgutils.h
@@ -0,0 +1,103 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: msgdlgutils.h 12833 2010-09-27 23:45:55Z silvercircle $
+ *
+ *
+ */
+
+#ifndef _MSGDLGUTILS_H
+#define _MSGDLGUTILS_H
+
+#define WANT_IEVIEW_LOG 1
+#define WANT_HPP_LOG 2
+
+void TSAPI CalcDynamicAvatarSize (TWindowData *dat, BITMAP *bminfo);
+char* TSAPI GetCurrentMetaContactProto (TWindowData *dat);
+void TSAPI WriteStatsOnClose (TWindowData *dat);
+int TSAPI MsgWindowUpdateMenu (TWindowData *dat, HMENU submenu, int menuID);
+int TSAPI MsgWindowMenuHandler (TWindowData *dat, int selection, int menuId);
+int TSAPI GetAvatarVisibility (HWND hwndDlg, TWindowData *dat);
+void TSAPI UpdateStatusBar (const TWindowData *dat);
+int TSAPI CheckValidSmileyPack (const char *szProto, HANDLE hContact);
+TCHAR* TSAPI QuoteText (const TCHAR *text, int charsPerLine, int removeExistingQuotes);
+void TSAPI UpdateReadChars (const TWindowData *dat);
+void TSAPI ShowPicture (TWindowData *dat, BOOL showNewPic);
+void TSAPI AdjustBottomAvatarDisplay (TWindowData *dat);
+void TSAPI SetDialogToType (HWND hwndDlg);
+void TSAPI FlashOnClist (HWND hwndDlg, TWindowData *dat, HANDLE hEvent, DBEVENTINFO *dbei);
+char* TSAPI Message_GetFromStream (HWND hwndDlg, const TWindowData* dat, DWORD dwPassedFlags);
+BOOL TSAPI DoRtfToTags (TCHAR * pszText, const TWindowData *dat);
+void TSAPI DoTrimMessage (TCHAR *msg);
+void TSAPI GetMYUIN (TWindowData *dat);
+void TSAPI SetMessageLog (TWindowData *dat);
+void TSAPI SwitchMessageLog (TWindowData *dat, int iMode);
+UINT TSAPI GetIEViewMode (HWND hwndDlg, HANDLE hContact);
+void TSAPI FindFirstEvent (TWindowData *dat);
+void TSAPI SaveSplitter (TWindowData *dat);
+void TSAPI LoadSplitter (TWindowData *dat);
+void TSAPI PlayIncomingSound (const TWindowData *dat);
+void TSAPI GetSendFormat (TWindowData *dat, int mode);
+void TSAPI GetLocaleID (TWindowData *dat, const TCHAR *szKLName);
+void TSAPI LoadOwnAvatar (TWindowData *dat);
+void TSAPI LoadContactAvatar (TWindowData *dat);
+void TSAPI LoadTimeZone (TWindowData *dat);
+void TSAPI HandlePasteAndSend (const TWindowData *dat);
+int TSAPI MsgWindowDrawHandler (WPARAM wParam, LPARAM lParam, TWindowData *dat);
+void TSAPI LoadOverrideTheme (TContainerData *pContainer);
+void TSAPI LoadThemeDefaults (TContainerData *pContainer);
+void TSAPI ConfigureSmileyButton (TWindowData *dat);
+int TSAPI CutContactName (const TCHAR *szold, TCHAR *sznew, unsigned int size);
+void TSAPI SendNudge (const TWindowData *dat);
+void TSAPI EnableSendButton (const TWindowData *dat, int iMode);
+LRESULT TSAPI GetSendButtonState (HWND hwnd);
+HICON TSAPI GetXStatusIcon (const TWindowData *dat);
+void TSAPI FlashTab (TWindowData *dat, HWND hwndTab, int iTabindex, BOOL *bState, BOOL mode, HICON origImage);
+void TSAPI GetClientIcon (TWindowData *dat);
+void TSAPI RearrangeTab (HWND hwndDlg, const TWindowData *dat, int iMode, BOOL fSavePos);
+void TSAPI GetCachedStatusMsg (TWindowData *dat);
+BOOL TSAPI IsStatusEvent (int eventType);
+void TSAPI GetMyNick (TWindowData *dat);
+HICON TSAPI MY_GetContactIcon (const TWindowData *dat);
+void TSAPI CheckAndDestroyIEView (TWindowData *dat);
+void TSAPI KbdState (TWindowData *dat, BOOL& isShift, BOOL& isControl, BOOL& isAlt);
+void TSAPI ClearLog (TWindowData *dat);
+bool TSAPI IsAutoSplitEnabled (const TWindowData* dat);
+LONG TSAPI GetDefaultMinimumInputHeight (const TWindowData* dat);
+void TSAPI DetermineMinHeight (TWindowData* dat);
+// mathmod
+
+void TSAPI MTH_updateMathWindow (const TWindowData *dat);
+
+void TSAPI CleanTempFiles ();
+void TSAPI SendHBitmapAsFile (const TWindowData* dat, HBITMAP hbmp);
+
+extern INT_PTR CALLBACK SelectContainerDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+extern INT_PTR CALLBACK DlgProcContainerOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+#endif
diff --git a/plugins/TabSRMM/include/msgs.h b/plugins/TabSRMM/include/msgs.h
new file mode 100644
index 0000000000..51c59a1561
--- /dev/null
+++ b/plugins/TabSRMM/include/msgs.h
@@ -0,0 +1,1062 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: msgs.h 13587 2011-04-12 13:54:26Z george.hazan $
+ *
+ *
+ */
+
+#ifndef _MSGS_H
+#define _MSGS_H
+
+#ifdef _MSC_VER
+#if _MSC_VER < 1400
+#define uintptr_t UINT_PTR
+#define _localtime32 localtime
+#define __time32_t time_t
+#endif
+#endif
+/*
+ * required for MingW32 compatibility
+ */
+
+#define CF_TEXTT CF_UNICODETEXT
+
+#include <richedit.h>
+#include <richole.h>
+#include "m_avatars.h"
+#include "m_message.h"
+
+#define MSGERROR_CANCEL 0
+#define MSGERROR_RETRY 1
+#define MSGERROR_SENDLATER 2
+
+#define CONTAINER_NAMELEN 25
+#define TITLE_FORMATLEN 30
+
+#define MWF_SAVEBTN_SAV 2
+
+#define MWF_DEFERREDSCROLL 4
+#define MWF_NEEDHISTORYSAVE 8
+#define MWF_WASBACKGROUNDCREATE 16
+//#define MWF_MOUSEDOWN 32
+#define MWF_ERRORSTATE 128
+#define MWF_DEFERREDREMAKELOG 256
+
+#define MWF_LOG_NORMALTEMPLATES 512
+#define MWF_LOG_SHOWTIME 1024
+#define MWF_LOG_SHOWSECONDS 2048
+#define MWF_LOG_SHOWDATES 4096
+
+#define MWF_LOG_INDENT 16384
+#define MWF_LOG_RTL 32768
+
+//MAD: ieview still mistakenly uses these...
+#define MWF_LOG_NEWLINE 8192
+#define MWF_LOG_UNDERLINE 65536
+#define MWF_LOG_SWAPNICK 131072
+//
+//#define MWF_LOG_BBCODE 65536
+//#define MWF_LOG_STATUSCHANGES 131072
+//#define MWF_LOG_LOCALTIME 8192
+#define MWF_LOG_BBCODE 1
+#define MWF_LOG_STATUSCHANGES 32
+#define MWF_LOG_LOCALTIME 64
+
+#define MWF_LOG_SHOWICONS 262144
+#define MWF_LOG_SYMBOLS 0x200000
+#define MWF_INITMODE 0x400000
+#define MWF_NEEDCHECKSIZE 0x800000
+#define MWF_DIVIDERSET 0x1000000
+#define MWF_LOG_TEXTFORMAT 0x2000000
+#define MWF_LOG_GRID 0x4000000
+// #define MWF_LOG_INDIVIDUALBKG 0x8000000 * FREE *
+#define MWF_LOG_INOUTICONS 0x10000000
+#define MWF_SMBUTTONSELECTED 0x20000000
+#define MWF_DIVIDERWANTED 0x40000000
+#define MWF_LOG_GROUPMODE 0x80000000
+
+#define MWF_SHOW_URLEVENTS 1
+#define MWF_SHOW_FILEEVENTS 2
+//#define MWF_SHOW_PRIVATETHEME 4
+//#define MWF_SHOW_EMPTYLINEFIX 8
+//#define MWF_SHOW_MICROLF 16
+//#define MWF_SHOW_MARKFOLLOWUPTS 32
+#define MWF_SHOW_FLASHCLIST 64
+#define MWF_SHOW_SPLITTEROVERRIDE 128
+#define MWF_SHOW_SCROLLINGDISABLED 256
+//#define MWF_SHOW_INFONOTES ** FREE **
+#define MWF_SHOW_ISIDLE 4096
+#define MWF_SHOW_AWAYMSGTIMER 8192
+#define MWF_EX_DELAYEDSPLITTER 32768
+#define MWF_EX_AVATARCHANGED 65536
+#define MWF_EX_WARNCLOSE 0x20000
+
+#define SMODE_DEFAULT 0
+#define SMODE_MULTIPLE 1
+#define SMODE_CONTAINER 2
+#define SMODE_FORCEANSI 4
+#define SMODE_SENDLATER 8
+#define SMODE_NOACK 16
+
+#define SENDFORMAT_BBCODE 1
+#define SENDFORMAT_NONE 0
+
+#define AVATARMODE_DYNAMIC 0
+
+#define MSGDLGFONTCOUNT 22
+#define CHATFONTCOUNT 19
+
+#define TMPL_MSGIN 0
+#define TMPL_MSGOUT 1
+#define TMPL_GRPSTARTIN 2
+#define TMPL_GRPSTARTOUT 3
+#define TMPL_GRPINNERIN 4
+#define TMPL_GRPINNEROUT 5
+#define TMPL_STATUSCHG 6
+#define TMPL_ERRMSG 7
+
+#define TEMPLATE_LENGTH 150
+#define CUSTOM_COLORS 5
+
+struct TTemplateSet {
+ BOOL valid; // all templates populated (may still contain crap.. so it's only half-assed safety :)
+ TCHAR szTemplates[TMPL_ERRMSG + 1][TEMPLATE_LENGTH]; // the template strings
+ char szSetName[20]; // everything in this world needs a name. so does this poor template set.
+};
+
+struct TitleBtn {
+ BOOL isHot;
+ BOOL isPressed;
+};
+
+#define BTN_MIN 0
+#define BTN_MAX 1
+#define BTN_CLOSE 2
+
+#define NR_LOGICONS 8
+#define NR_BUTTONBARICONS 37//MaD: 29
+#define NR_SIDEBARICONS 2
+
+class CTaskbarInteract;
+class CMenuBar;
+class CInfoPanel;
+class CSideBar;
+class CContactCache;
+class CProxyWindow;
+
+#define STICK_ICON_MSG 10
+struct TLogTheme {
+ COLORREF inbg, outbg, bg, oldinbg, oldoutbg, statbg, inputbg;
+ COLORREF hgrid;
+ COLORREF custom_colors[5];
+ DWORD dwFlags;
+ DWORD left_indent, right_indent;
+ LOGFONTA* logFonts;
+ COLORREF* fontColors;
+ char* rtfFonts;
+ bool isPrivate;
+};
+
+struct TContainerSettings {
+ bool fPrivate;
+ DWORD dwFlags;
+ DWORD dwFlagsEx;
+ DWORD dwTransparency;
+ DWORD panelheight;
+ DWORD splitterPos;
+ TCHAR szTitleFormat[TITLE_FORMATLEN + 2];
+ WORD avatarMode;
+ WORD ownAvatarMode;
+ WORD autoCloseSeconds;
+ BYTE reserved[10];
+};
+
+struct TContainerData {
+ TContainerData *pNextContainer;
+ TCHAR szName[CONTAINER_NAMELEN + 4]; // container name
+ HWND hwndActive; // active message window
+ HWND hwnd; // the container handle
+ int iTabIndex; // next tab id
+ int iChilds;
+ int iContainerIndex;
+ bool fHidden;
+ HMENU hMenuContext;
+ HWND hwndTip; // tab - tooltips...
+ BOOL bDontSmartClose; // if set, do not search and select the next possible tab after closing one.
+ DWORD dwFlags;
+ DWORD dwFlagsEx;
+ LONG uChildMinHeight;
+ int tBorder;
+ int tBorder_outer_left, tBorder_outer_right, tBorder_outer_top, tBorder_outer_bottom;
+ HANDLE hContactFrom;
+ BOOL isCloned;
+ HWND hwndStatus;
+ int statusBarHeight;
+ DWORD dwLastActivity;
+ int hIcon; // current window icon stick indicator
+ HICON hIconTaskbarOverlay; // contains a "sticky" taskbar overlay (e.g. new message icon)
+ DWORD dwFlashingStarted;
+ HWND hWndOptions;
+ BOOL bSizingLoop;
+ TCHAR szRelThemeFile[MAX_PATH], szAbsThemeFile[MAX_PATH];
+ TTemplateSet *ltr_templates, *rtl_templates;
+ HDC cachedDC;
+ HBITMAP cachedHBM, oldHBM;
+ SIZE oldDCSize;
+ RECT rcClose, rcMin, rcMax;
+ struct TitleBtn buttons[3];
+ struct TitleBtn oldbuttons[3];
+ int ncActive;
+ HWND hwndSaved;
+ ButtonItem *buttonItems;
+ RECT rcSaved, rcLogSaved;
+ POINT ptLogSaved;
+ DWORD exFlags;
+ BOOL fPrivateThemeChanged;
+ MARGINS mOld;
+ HDC cachedToolbarDC;
+ HBITMAP hbmToolbarBG, oldhbmToolbarBG;
+ SIZE szOldToolbarSize;
+ SIZE oldSize, preSIZE;
+ WORD avatarMode, ownAvatarMode;
+ BYTE bTBRenderingMode;
+ TLogTheme theme;
+ TContainerSettings* settings;
+ CTaskbarInteract* TaskBar;
+ CMenuBar* MenuBar;
+ CSideBar* SideBar;
+};
+
+struct SESSIONINFO_TYPE;
+
+struct TWindowData {
+ UINT cbSize;
+ BYTE bType;
+ struct TContainerData *pContainer; // parent container description structure
+ HWND hwnd;
+ DWORD dwFlags;
+ DWORD dwFlagsEx;
+ HANDLE hContact;
+ char *szProto;
+ TCHAR szMyNickname[130];
+ TCHAR szStatusBar[100];
+ TCHAR newtitle[130]; // tab title...
+ TCHAR szStatus[50];
+ WORD wStatus;
+ char *sendBuffer;
+ int iSendBufferSize;
+ int iSendLength; // message length in utf-8 octets
+ HICON hTabIcon, hTabStatusIcon, hXStatusIcon, hClientIcon, hTaskbarIcon;
+ HICON iFlashIcon;
+ BOOL mayFlashTab;
+ BOOL bTabFlash;
+ HWND hwndIEView, hwndFlash, hwndIWebBrowserControl, hwndHPP;
+ HWND hwndContactPic, hwndPanelPic, hwndPanelPicParent;
+ UINT bbLSideWidth; //MAD
+ UINT bbRSideWidth; //MAD
+ BYTE kstate[256];
+ struct TStatusBarIconNode *pSINod;
+ SESSIONINFO_TYPE* si;
+
+ RECT rcNick, rcUIN, rcStatus, rcPic;
+ HANDLE hDbEventFirst, hDbEventLast;
+ int sendMode;
+ int splitterY, originalSplitterY, dynaSplitter, savedSplitter, savedSplitY, savedDynaSplit;
+ int multiSplitterX;
+ SIZE minEditBoxSize;
+ int showUIElements;
+ int nTypeSecs;
+ int nTypeMode;
+ DWORD nLastTyping;
+ int showTyping;
+ DWORD lastMessage;
+ int iTabID;
+ HKL hkl; // keyboard layout identifier
+ DWORD dwTickLastEvent, dwUnread;
+ HBITMAP hOwnPic;
+ SIZE pic;
+ int showPic, showInfoPic;
+ BOOL fMustOffset;
+ BOOL isHistory;
+ int doSmileys;
+ UINT codePage;
+ HICON hSmileyIcon;
+ int iLastEventType;
+ time_t lastEventTime;
+ int iRealAvatarHeight;
+ int iButtonBarReallyNeeds;
+ DWORD dwLastActivity;
+ int iOpenJobs;
+ int iCurrentQueueError;
+ BOOL bIsMeta;
+ HANDLE hFlashingEvent;
+ TCHAR myUin[80];
+ BOOL bNotOnList;
+ int SendFormat;
+ HANDLE *hQueuedEvents;
+ int iNextQueuedEvent;
+#define EVENT_QUEUE_SIZE 10
+ int iEventQueueSize;
+ LCID lcid;
+ TCHAR lcID[10];
+ int panelWidth;
+ DWORD idle;
+ HWND hwndTip;
+ TOOLINFO ti;
+ HANDLE hTimeZone;
+ DWORD panelStatusCX;
+ COLORREF inputbg;
+ struct avatarCacheEntry *ace, *ownAce;
+ HANDLE *hHistoryEvents;
+ int maxHistory, curHistory;
+ HANDLE hTheme, hThemeIP, hThemeToolbar;
+ char szMicroLf[128];
+ DWORD isAutoRTL;
+ int nMax; // max message size
+ int textLen; // current text len
+ LONG ipFieldHeight;
+ WNDPROC oldIEViewProc;
+ BOOL clr_added;
+ BOOL fIsReattach;
+ WPARAM wParam; // used for "delayed" actions like moved splitters in minimized windows
+ LPARAM lParam;
+ int iHaveRTLLang;
+ BOOL fInsertMode;
+ bool fkeyProcessed;
+ bool fEditNotesActive;
+ CInfoPanel *Panel;
+ CContactCache *cache;
+ CProxyWindow *pWnd; // proxy window object (win7+, for taskbar support).
+ // ALWAYS check this pointer before using it, it is not guaranteed to exist.
+ DWORD iSplitterSaved;
+ BYTE bWasDeleted;
+ BOOL bActualHistory;
+ POINT ptTipActivation;
+ LONG iInputAreaHeight;
+ bool fIsAutosizingInput;
+ bool fLimitedUpdate;
+};
+
+#define MESSAGE_WINDOW_DATA_SIZE offsetof(_MessageWindowData, hdbEventFirst);
+
+typedef struct _recentinfo {
+ DWORD dwFirst, dwMostRecent; // timestamps
+ int iFirstIndex, iMostRecent; // tab indices
+ HWND hwndFirst, hwndMostRecent; // client window handles
+} RECENTINFO;
+
+/*
+ * configuration data for custom tab ctrl
+ */
+
+struct myTabCtrl {
+ HPEN m_hPenShadow, m_hPenItemShadow, m_hPenLight;
+ HFONT m_hMenuFont;
+ COLORREF colors[10];
+ HBRUSH m_brushes[4];
+ DWORD m_fixedwidth;
+ int m_bottomAdjust;
+};
+
+struct TIconDesc {
+ char *szName;
+ char *szDesc;
+ HICON *phIcon; // where the handle is saved...
+ INT_PTR uId; // icon ID
+ BOOL bForceSmall; // true: force 16x16
+};
+
+struct TIconDescW {
+ TCHAR *szName;
+ TCHAR *szDesc;
+ HICON *phIcon; // where the handle is saved...
+ INT_PTR uId; // icon ID
+ BOOL bForceSmall; // true: force 16x16
+};
+
+// menu IDS
+
+#define MENU_LOGMENU 1
+#define MENU_PICMENU 2
+#define MENU_TABCONTEXT 3
+#define MENU_PANELPICMENU 4
+
+#define TABSRMM_SMILEYADD_BKGCOLORMODE 0x10000000
+#define ADDEDEVENTSQUEUESIZE 100
+
+/*
+ * tab config flags
+ */
+
+#define TCF_FLAT 1
+//#define TCF_STYLED 2
+#define TCF_CLOSEBUTTON 4
+#define TCF_FLASHICON 8
+#define TCF_FLASHLABEL 16
+#define TCF_SINGLEROWTABCONTROL 32
+//#define TCF_LABELUSEWINCOLORS 64
+//#define TCF_BKGUSEWINCOLORS 128
+#define TCF_SBARLEFT 256
+#define TCF_SBARRIGHT 512
+
+#define TCF_DEFAULT (TCF_FLASHICON)
+
+#define MIN_PANELHEIGHT 20
+
+struct TNewWindowData {
+ HANDLE hContact;
+ int isWchar;
+ const char* szInitialText;
+ int iTabID;
+ int iTabImage;
+ int iActivate;
+ TCITEM item;
+ TContainerData* pContainer;
+ BOOL bWantPopup;
+ HANDLE hdbEvent;
+ HKL hkl;
+};
+
+// flags for the container dwFlags
+#define CNT_MOUSEDOWN 1
+#define CNT_NOTITLE 2
+#define CNT_HIDETABS 4
+#define CNT_SIDEBAR 8
+#define CNT_NOFLASH 0x10
+#define CNT_STICKY 0x20
+#define CNT_DONTREPORT 0x40
+#define CNT_FLASHALWAYS 0x80
+#define CNT_TRANSPARENCY 0x100
+#define CNT_AUTOHIDE 0x200
+#define CNT_DONTREPORTFOCUSED 0x400
+//#define CNT_GLOBALSETTINGS 0x400
+#define CNT_GLOBALSIZE 0x800
+#define CNT_INFOPANEL 0x1000
+#define CNT_NOSOUND 0x2000
+#define CNT_AUTOSPLITTER 0x4000
+#define CNT_DEFERREDCONFIGURE 0x8000
+#define CNT_CREATE_MINIMIZED 0x10000
+#define CNT_NEED_UPDATETITLE 0x20000
+#define CNT_DEFERREDSIZEREQUEST 0x40000
+#define CNT_DONTREPORTUNFOCUSED 0x80000
+#define CNT_DONTREPORTFOCUSED 0x400
+#define CNT_ALWAYSREPORTINACTIVE 0x100000
+#define CNT_NEWCONTAINERFLAGS 0x200000
+#define CNT_DEFERREDTABSELECT 0x400000
+#define CNT_CREATE_CLONED 0x800000
+#define CNT_NOSTATUSBAR 0x1000000
+#define CNT_NOMENUBAR 0x2000000
+#define CNT_TABSBOTTOM 0x4000000
+#define CNT_AVATARSONTASKBAR 0x200
+#define CNT_BOTTOMTOOLBAR 0x10000000
+#define CNT_HIDETOOLBAR 0x20000000
+#define CNT_UINSTATUSBAR 0x40000000
+#define CNT_VERTICALMAX 0x80000000
+
+#define CNT_EX_SOUNDS_MINIMIZED 1024
+#define CNT_EX_SOUNDS_UNFOCUSED 2048
+#define CNT_EX_SOUNDS_INACTIVETABS 4096
+#define CNT_EX_SOUNDS_FOCUSED 8192
+
+#define CNT_FLAGS_DEFAULT (CNT_DONTREPORT | CNT_DONTREPORTUNFOCUSED | CNT_ALWAYSREPORTINACTIVE | CNT_HIDETABS | CNT_NEWCONTAINERFLAGS | CNT_NOMENUBAR | CNT_INFOPANEL)
+#define CNT_TRANS_DEFAULT 0x00ff00ff
+
+#define CNT_FLAGSEX_DEFAULT (TCF_FLASHICON | CNT_EX_SOUNDS_MINIMIZED | CNT_EX_SOUNDS_UNFOCUSED | CNT_EX_SOUNDS_INACTIVETABS | CNT_EX_SOUNDS_FOCUSED)
+
+#define CNT_CREATEFLAG_CLONED 1
+#define CNT_CREATEFLAG_MINIMIZED 2
+
+#define CNT_EX_CLOSEWARN 1
+
+#define MWF_LOG_ALL (MWF_LOG_NORMALTEMPLATES | MWF_LOG_SHOWTIME | MWF_LOG_SHOWSECONDS | \
+ MWF_LOG_SHOWDATES | MWF_LOG_INDENT | MWF_LOG_TEXTFORMAT | MWF_LOG_SYMBOLS | MWF_LOG_INOUTICONS | \
+ MWF_LOG_SHOWICONS | MWF_LOG_GRID | MWF_LOG_GROUPMODE | \
+ MWF_LOG_RTL | MWF_LOG_BBCODE | MWF_LOG_LOCALTIME/*MAD:*/ | \
+ MWF_LOG_STATUSCHANGES|MWF_LOG_NEWLINE|MWF_LOG_UNDERLINE|MWF_LOG_SWAPNICK /*_MAD*/)
+
+#define MWF_LOG_DEFAULT (MWF_LOG_SHOWTIME | MWF_LOG_NORMALTEMPLATES | MWF_LOG_SHOWDATES | MWF_LOG_SYMBOLS | MWF_LOG_GRID | MWF_LOG_STATUSCHANGES | MWF_LOG_INOUTICONS)
+
+/*
+ * custom dialog window messages
+ */
+#define EM_SUBCLASSED (WM_USER+0x101)
+#define EM_SEARCHSCROLLER (WM_USER+0x103)
+#define EM_VALIDATEBOTTOM (WM_USER+0x104)
+#define EM_THEMECHANGED (WM_USER+0x105)
+#define EM_UNSUBCLASSED (WM_USER+0x106)
+#define EM_REFRESHWITHOUTCLIP (WM_USER+0x107)
+
+#define HM_EVENTSENT (WM_USER+10)
+#define DM_REMAKELOG (WM_USER+11)
+#define HM_DBEVENTADDED (WM_USER+12)
+#define DM_SETINFOPANEL (WM_USER+13)
+#define DM_OPTIONSAPPLIED (WM_USER+14)
+#define DM_SPLITTERMOVED (WM_USER+15)
+#define DM_UPDATETITLE (WM_USER+16)
+#define DM_APPENDTOLOG (WM_USER+17)
+#define DM_ERRORDECIDED (WM_USER+18)
+#define DM_SPLITSENDACK (WM_USER+19)
+#define DM_TYPING (WM_USER+20)
+#define DM_UPDATEWINICON (WM_USER+21)
+#define DM_UPDATELASTMESSAGE (WM_USER+22)
+
+#define DM_SELECTTAB (WM_USER+23)
+#define DM_CLOSETABATMOUSE (WM_USER+24)
+#define DM_STATUSICONCHANGE (WM_USER+25)
+#define DM_SETLOCALE (WM_USER+26)
+#define DM_SESSIONLIST (WM_USER+27)
+#define DM_QUERYLASTUNREAD (WM_USER+28)
+#define DM_QUERYPENDING (WM_USER+29)
+#define DM_UPDATEPICLAYOUT (WM_USER+30)
+#define DM_QUERYCONTAINER (WM_USER+31)
+#define DM_MUCFLASHWORKER (WM_USER+32)
+#define DM_INVALIDATEPANEL (WM_USER+33)
+//#define DM_REPORTMINHEIGHT (WM_USER+34) // msg dialog reports its minimum height to the container
+#define DM_CHECKINFOTIP (WM_USER+35)
+#define DM_SAVESIZE (WM_USER+36)
+#define DM_CHECKSIZE (WM_USER+37)
+#define DM_FORCEREDRAW (WM_USER+38)
+#define DM_CONTAINERSELECTED (WM_USER+39)
+#define DM_CONFIGURECONTAINER (WM_USER+40)
+#define DM_QUERYHCONTACT (WM_USER+41)
+#define DM_DEFERREDREMAKELOG (WM_USER+42)
+#define DM_RESTOREWINDOWPOS (WM_USER+43)
+#define DM_FORCESCROLL (WM_USER+44)
+#define DM_QUERYCLIENTAREA (WM_USER+45)
+#define DM_QUERYRECENT (WM_USER+47)
+#define DM_ACTIVATEME (WM_USER+46)
+// #define DM_REMOVEFROMSENDLATER (WM_USER+48)
+#define DM_SENDLATER_RESEND (WM_USER+49)
+#define DM_ADDDIVIDER (WM_USER+50)
+#define DM_STATUSMASKSET (WM_USER+51)
+#define DM_CONTACTSETTINGCHANGED (WM_USER+52)
+#define DM_UPDATESTATUSMSG (WM_USER+53)
+#define DM_PROTOACK (WM_USER+54)
+#define DM_OWNNICKCHANGED (WM_USER+55)
+#define DM_CONFIGURETOOLBAR (WM_USER+56)
+#define DM_LOADBUTTONBARICONS (WM_USER+57)
+#define DM_ACTIVATETOOLTIP (WM_USER+58)
+#define DM_UINTOCLIPBOARD (WM_USER+59)
+//#define DM_SPLITTEREMERGENCY (WM_USER+60)
+#define DM_SENDMESSAGECOMMAND (WM_USER+61)
+#define DM_FORCEDREMAKELOG (WM_USER+62)
+//#define DM_QUERYFLAGS (WM_USER+63)
+#define DM_STATUSBARCHANGED (WM_USER+64)
+#define DM_SAVEMESSAGELOG (WM_USER+65)
+#define DM_CHECKAUTOCLOSE (WM_USER+66)
+#define DM_UPDATEMETACONTACTINFO (WM_USER+67)
+#define DM_SETICON (WM_USER+68)
+#define DM_CLOSEIFMETA (WM_USER+69)
+#define DM_CHECKQUEUEFORCLOSE (WM_USER+70)
+#define DM_CHECKAUTOHIDE (WM_USER+71)
+#define DM_SETPARENTDIALOG (WM_USER+72)
+#define DM_HANDLECLISTEVENT (WM_USER+73)
+#define DM_TRAYICONNOTIFY (WM_USER+74)
+#define DM_REMOVECLISTEVENT (WM_USER+75)
+#define DM_GETWINDOWSTATE (WM_USER+76)
+#define DM_DOCREATETAB (WM_USER+77)
+#define DM_DELAYEDSCROLL (WM_USER+78)
+#define DM_REPLAYQUEUE (WM_USER+79)
+#define DM_REFRESHTABINDEX (WM_USER+83)
+#define DM_PROTOAVATARCHANGED (WM_USER+84)
+#define DM_SMILEYOPTIONSCHANGED (WM_USER+85)
+#define DM_MYAVATARCHANGED (WM_USER+86)
+#define DM_PRINTCLIENT (WM_USER+87)
+#define DM_IEVIEWOPTIONSCHANGED (WM_USER+88)
+#define DM_SPLITTERGLOBALEVENT (WM_USER + 89)
+#define DM_DOCREATETAB_CHAT (WM_USER+90)
+#define DM_CLIENTCHANGED (WM_USER+91)
+#define DM_PLAYINCOMINGSOUND (WM_USER+92)
+#define DM_SENDMESSAGECOMMANDW (WM_USER+93)
+#define DM_REMOVEPOPUPS (WM_USER+94)
+#define DM_BBNEEDUPDATE (WM_USER+96)
+#define DM_CBDESTROY (WM_USER+97)
+#define DM_LOGSTATUSCHANGE (WM_USER+98)
+//#define DM_SPLITTERMOVEDGLOBAL_NOSYNC_IM (WM_USER+99)
+#define DM_SC_BUILDLIST (WM_USER+100)
+#define DM_SC_INITDIALOG (WM_USER+101)
+#define DM_SC_CONFIG (WM_USER+104)
+#define DM_SCROLLIEVIEW (WM_USER+102)
+#define DM_UPDATEUIN (WM_USER+103)
+
+#define MINSPLITTERY 42
+#define MINLOGHEIGHT 30
+#define ERRORPANEL_HEIGHT 51
+
+// wParam values for DM_SELECTTAB
+
+#define DM_SELECT_NEXT 1
+#define DM_SELECT_PREV 2
+
+#define DM_SELECT_BY_HWND 3 // lParam specifies hwnd
+#define DM_SELECT_BY_INDEX 4 // lParam specifies tab index
+
+#define DM_QUERY_NEXT 1
+#define DM_QUERY_MOSTRECENT 2
+
+/*
+ * implement a callback for the rich edit. Without it, no bitmaps
+ * can be added to the richedit control.
+ * this class has to implement the GetNewStorage() method
+ */
+
+class REOLECallback : IRichEditOleCallback
+{
+
+public:
+
+ REOLECallback()
+ {
+ mRefCounter = 0;
+ }
+
+ ~REOLECallback()
+ {}
+
+ STDMETHOD_(ULONG, AddRef)(void)
+ {
+ mRefCounter++;
+ return (mRefCounter);
+ }
+
+ STDMETHOD_(ULONG, Release)(void)
+ {
+ --mRefCounter;
+ //if(--mRefCounter == 0)
+ // delete this;
+ return (mRefCounter);
+ }
+
+ STDMETHOD(QueryInterface)(REFIID iid, void** ppvObject)
+ {
+ if ( iid == IID_IUnknown || iid == IID_IRichEditOleCallback ) {
+ *ppvObject = this; AddRef(); return (S_OK);
+ }
+ else
+ return (E_NOINTERFACE);
+ }
+
+ STDMETHOD(ContextSensitiveHelp) (BOOL fEnterMode) { return (E_NOTIMPL);}
+ STDMETHOD(DeleteObject) (LPOLEOBJECT lpoleobj) { return (E_NOTIMPL);}
+ STDMETHOD(GetClipboardData) (CHARRANGE FAR *lpchrg, DWORD reco, LPDATAOBJECT FAR *lplpdataobj) { return (E_NOTIMPL);}
+ STDMETHOD(GetContextMenu) (WORD seltype, LPOLEOBJECT lpoleobj, CHARRANGE FAR *lpchrg, HMENU FAR *lphmenu) { return (E_NOTIMPL);}
+ STDMETHOD(GetDragDropEffect) (BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect) { return (E_NOTIMPL);}
+ STDMETHOD(GetInPlaceContext) (LPOLEINPLACEFRAME FAR *lplpFrame, LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo) { return (E_NOTIMPL);}
+ STDMETHOD(GetNewStorage) (LPSTORAGE FAR *lplpstg);
+ STDMETHOD(QueryAcceptData) (LPDATAOBJECT lpdataobj, CLIPFORMAT FAR *lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict) { return (E_NOTIMPL);}
+ STDMETHOD(QueryInsertObject) (LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp) { return (S_OK);}
+ STDMETHOD(ShowContainerUI) (BOOL fShow) { return (E_NOTIMPL);}
+private:
+ UINT mRefCounter;
+};
+
+#define MSGFONTID_MYMSG 0
+#define MSGFONTID_MYMISC 1
+#define MSGFONTID_YOURMSG 2
+#define MSGFONTID_YOURMISC 3
+#define MSGFONTID_MYNAME 4
+#define MSGFONTID_MYTIME 5
+#define MSGFONTID_YOURNAME 6
+#define MSGFONTID_YOURTIME 7
+#define H_MSGFONTID_MYMSG 8
+#define H_MSGFONTID_MYMISC 9
+#define H_MSGFONTID_YOURMSG 10
+#define H_MSGFONTID_YOURMISC 11
+#define H_MSGFONTID_MYNAME 12
+#define H_MSGFONTID_MYTIME 13
+#define H_MSGFONTID_YOURNAME 14
+#define H_MSGFONTID_YOURTIME 15
+#define MSGFONTID_MESSAGEAREA 16
+#define H_MSGFONTID_STATUSCHANGES 17
+#define H_MSGFONTID_DIVIDERS 18
+#define MSGFONTID_ERROR 19
+#define MSGFONTID_SYMBOLS_IN 20
+#define MSGFONTID_SYMBOLS_OUT 21
+
+#define IPFONTID_NICK 0
+#define IPFONTID_UIN 1
+#define IPFONTID_STATUS 2
+#define IPFONTID_PROTO 3
+#define IPFONTID_TIME 4
+
+extern const int msgDlgFontCount;
+
+#define LOADHISTORY_UNREAD 0
+#define LOADHISTORY_COUNT 1
+#define LOADHISTORY_TIME 2
+
+#define SRMSGSET_AUTOPOPUP "AutoPopup"
+#define SRMSGDEFSET_AUTOPOPUP 0
+#define SRMSGSET_AUTOMIN "AutoMin"
+#define SRMSGDEFSET_AUTOMIN 0
+#define SRMSGSET_SENDONENTER "SendOnEnter"
+#define SRMSGDEFSET_SENDONENTER 0
+#define SRMSGSET_MSGTIMEOUT "MessageTimeout"
+#define SRMSGDEFSET_MSGTIMEOUT 60000
+#define SRMSGSET_MSGTIMEOUT_MIN 30000 // minimum value (30 seconds)
+
+#define SRMSGSET_LOADHISTORY "LoadHistory"
+#define SRMSGDEFSET_LOADHISTORY LOADHISTORY_COUNT
+#define SRMSGSET_LOADCOUNT "LoadCount"
+#define SRMSGDEFSET_LOADCOUNT 10
+#define SRMSGSET_LOADTIME "LoadTime"
+#define SRMSGDEFSET_LOADTIME 10
+
+#define SRMSGSET_SHOWURLS "ShowURLs"
+#define SRMSGDEFSET_SHOWURLS 1
+#define SRMSGSET_SHOWFILES "ShowFiles"
+#define SRMSGDEFSET_SHOWFILES 1
+#define SRMSGSET_BKGCOLOUR "BkgColour"
+#define SRMSGSET_BKGCOLOUR_MUC "BkgColourMUC"
+
+#define SRMSGDEFSET_BKGCOLOUR RGB(250,250,250)
+//#define SRMSGDEFSET_BKGCOLOUR GetSysColor(COLOR_WINDOW)
+#define SRMSGDEFSET_BKGINCOLOUR RGB(245,255,245)
+#define SRMSGDEFSET_BKGOUTCOLOUR RGB(245,245,255)
+
+#define SRMSGSET_TYPING "SupportTyping"
+#define SRMSGSET_TYPINGNEW "DefaultTyping"
+#define SRMSGDEFSET_TYPINGNEW 1
+
+#define SRMSGSET_TYPINGUNKNOWN "UnknownTyping"
+#define SRMSGDEFSET_TYPINGUNKNOWN 0
+
+#define SRMSGSET_SHOWTYPING "ShowTyping"
+#define SRMSGDEFSET_SHOWTYPING 1
+
+#define SRMSGSET_SHOWTYPINGWINFLASH "ShowTypingWinFlash"
+#define SRMSGDEFSET_SHOWTYPINGWINFLASH 1
+
+#define SRMSGSET_SHOWTYPINGNOWINOPEN "ShowTypingNoWinOpen"
+
+#define SRMSGSET_SHOWTYPINGWINOPEN "ShowTypingWinOpen"
+
+#define SRMSGSET_SHOWTYPINGCLIST "ShowTypingClist"
+#define SRMSGDEFSET_SHOWTYPINGCLIST 1
+
+// rtl support
+#define SRMSGDEFSET_MOD_RTL 0
+
+#define TIMERID_FLASHWND 1
+#define TIMEOUT_FLASHWND 900
+#define TIMERID_HEARTBEAT 2
+#define TIMEOUT_HEARTBEAT 20000
+#define TIMERID_HOVER 10
+#define TIMERID_HOVER_T 11
+
+#define SRMSGMOD "SRMsg"
+#define SRMSGMOD_T "Tab_SRMsg"
+#define FONTMODULE "TabSRMM_Fonts"
+#define CHAT_FONTMODULE "TabSRMM_chat_Fonts"
+
+#define IDM_STAYONTOP (WM_USER + 1)
+#define IDM_NOTITLE (WM_USER + 2)
+#define IDM_MOREOPTIONS (WM_USER +4)
+
+// constants for the container management functions
+
+#define CNT_ENUM_DELETE 1 // delete the target container...
+#define CNT_ENUM_RENAME 2
+#define CNT_ENUM_WRITEFLAGS 4
+
+#define IDM_CONTAINERMENU 50500
+
+#define EVENTTYPE_STATUSCHANGE 25368
+#define EVENTTYPE_DIVIDER 25367
+#define EVENTTYPE_ERRMSG 25366
+
+// hotkey modifiers...
+
+#define HOTKEY_MODIFIERS_CTRLSHIFT 0
+#define HOTKEY_MODIFIERS_CTRLALT 1
+#define HOTKEY_MODIFIERS_ALTSHIFT 2
+
+struct TLogIcon {
+ HBITMAP hBmp, hoBmp;
+ HDC hdc, hdcMem;
+ HBRUSH hBkgBrush;
+};
+
+#include "../icons/iconsxp/resource.h" // icon pack values
+
+struct TCpTable {
+ UINT cpId;
+ TCHAR *cpName;
+};
+
+#define LOI_TYPE_FLAG 1
+#define LOI_TYPE_SETTING 2
+
+struct TOptionListGroup {
+ LRESULT handle;
+ TCHAR *szName;
+};
+
+struct TOptionListItem {
+ LRESULT handle;
+ TCHAR *szName;
+ UINT id;
+ UINT uType;
+ UINT_PTR lParam;
+ UINT uGroup;
+};
+
+// sidebar button flags
+
+#define SBI_TOP 1
+#define SBI_BOTTOM 2
+#define SBI_HIDDEN 4
+#define SBI_DISABLED 8
+#define SBI_TOGGLE 16
+#define SBI_HANDLEBYCLIENT 32
+
+// fixed stock button identifiers
+
+#define IDC_SBAR_SLIST 1111
+#define IDC_SBAR_FAVORITES 1112
+#define IDC_SBAR_RECENT 1113
+#define IDC_SBAR_SETUP 1114
+#define IDC_SBAR_USERPREFS 1115
+#define IDC_SBAR_TOGGLEFORMAT 1117
+#define IDC_SBAR_CANCEL 1118
+
+struct SIDEBARITEM {
+ UINT uId;
+ DWORD dwFlags;
+ HICON *hIcon, *hIconPressed, *hIconHover;
+ TCHAR *szName;
+ void (*pfnAction)(ButtonItem *item, HWND hwndDlg, struct TWindowData *dat, HWND hwndItem);
+ void (*pfnCallback)(ButtonItem *item, HWND hwndDlg, struct TWindowData *dat, HWND hwndItem);
+ TCHAR *tszTip;
+};
+
+#define FONTF_BOLD 1
+#define FONTF_ITALIC 2
+#define FONTF_UNDERLINE 4
+#define FONTF_STRIKEOUT 8
+
+#define RTFCACHELINESIZE 128
+
+#define ID_EXTBKCONTAINER 0
+#define ID_EXTBKBUTTONBAR 1
+#define ID_EXTBKBUTTONSPRESSED 2
+#define ID_EXTBKBUTTONSNPRESSED 3
+#define ID_EXTBKBUTTONSMOUSEOVER 4
+#define ID_EXTBKINFOPANEL 5
+#define ID_EXTBKTITLEBUTTON 6
+#define ID_EXTBKTITLEBUTTONMOUSEOVER 7
+#define ID_EXTBKTITLEBUTTONPRESSED 8
+#define ID_EXTBKTABPAGE 9
+#define ID_EXTBKTABITEM 10
+#define ID_EXTBKTABITEMACTIVE 11
+#define ID_EXTBKTABITEMBOTTOM 12
+#define ID_EXTBKTABITEMACTIVEBOTTOM 13
+#define ID_EXTBKFRAME 14
+#define ID_EXTBKHISTORY 15
+#define ID_EXTBKINPUTAREA 16
+#define ID_EXTBKFRAMEINACTIVE 17
+#define ID_EXTBKTABITEMHOTTRACK 18
+#define ID_EXTBKTABITEMHOTTRACKBOTTOM 19
+#define ID_EXTBKSTATUSBARPANEL 20
+#define ID_EXTBKSTATUSBAR 21
+#define ID_EXTBKUSERLIST 22
+#define ID_EXTBKINFOPANELBG 23
+#define ID_EXTBKSIDEBARBG 24
+#define ID_EXTBK_LAST 24
+
+#define SESSIONTYPE_ANY 0
+#define SESSIONTYPE_IM 1
+#define SESSIONTYPE_CHAT 2
+
+#define DEFAULT_SIDEBARWIDTH 30
+
+#define THEME_READ_FONTS 1
+#define THEME_READ_TEMPLATES 2
+#define THEME_READ_ALL (THEME_READ_FONTS | THEME_READ_TEMPLATES)
+
+#define IDC_TBFIRSTUID 10000 // first uId for custom buttons
+
+#include "templates.h"
+
+struct TStatusBarIconNode {
+ TStatusBarIconNode* next;
+ StatusIconData sid;
+};
+
+struct TABSRMM_SessionInfo {
+ unsigned int cbSize;
+ unsigned short evtCode;
+ HWND hwnd; // handle of the message dialog (tab)
+ HWND hwndContainer; // handle of the parent container
+ HWND hwndInput; // handle of the input area (rich edit)
+ UINT extraFlags;
+ UINT extraFlagsEX;
+ void *local;
+};
+
+typedef struct {
+ int cbSize;
+ HANDLE hContact;
+ int uFlags; // should be same as input data unless 0, then it will be the actual type
+ HWND hwndWindow; //top level window for the contact or NULL if no window exists
+ int uState; // see window states
+ void *local; // used to store pointer to custom data
+} MessageWindowOutputData;
+
+#define MS_MSG_GETWINDOWDATA "MessageAPI/GetWindowData"
+//wparam=(MessageWindowInputData*)
+//lparam=(MessageWindowData*)
+//returns 0 on success and returns non-zero (1) on error or if no window data exists for that hcontact
+
+// callback for the user menu entry
+
+#define MS_TABMSG_SETUSERPREFS "SRMsg_MOD/SetUserPrefs"
+#define MS_TABMSG_SLQMGR "SRMsg_MOD/InvokeQmgr"
+
+// show one of the tray menus
+// wParam = 0 -> session list
+// wParam = 1 -> tray menu
+// lParam must be 0
+#define MS_TABMSG_TRAYSUPPORT "SRMsg_MOD/Show_TrayMenu"
+
+/*
+ * the service which processes globally registered hotkeys
+ */
+#define MS_TABMSG_HOTKEYPROCESS "SRMsg_MOD/ProcessHotkey"
+
+#define MBF_DISABLED 0x01
+
+#define TEMPLATES_MODULE "tabSRMM_Templates"
+#define RTLTEMPLATES_MODULE "tabSRMM_RTLTemplates"
+
+//Checks if there is a message window opened
+//wParam=(LPARAM)(HANDLE)hContact - handle of the contact for which the window is searched. ignored if lParam
+//is not zero.
+//lParam=(LPARAM)(HWND)hwnd - a window handle - SET THIS TO 0 if you want to obtain the window handle
+//from the hContact.
+#define MS_MSG_MOD_MESSAGEDIALOGOPENED "SRMsg_MOD/MessageDialogOpened"
+
+//obtain the message window flags
+//wParam = hContact - ignored if lParam is given.
+//lParam = hwnd
+//returns struct MessageWindowData *dat, 0 if no window is found
+#define MS_MSG_MOD_GETWINDOWFLAGS "SRMsg_MOD/GetWindowFlags"
+
+// custom tabSRMM events
+
+#define tabMSG_WINDOW_EVT_CUSTOM_BEFORESEND 1
+
+
+/* temporary HPP API for emulating message log */
+
+#define MS_HPP_EG_WINDOW "History++/ExtGrid/NewWindow"
+#define MS_HPP_EG_EVENT "History++/ExtGrid/Event"
+#define MS_HPP_EG_UTILS "History++/ExtGrid/Utils"
+#define MS_HPP_EG_OPTIONSCHANGED "History++/ExtGrid/OptionsChanged"
+#define MS_HPP_EG_NOTIFICATION "History++/ExtGrid/Notification"
+
+#define SB_CHAR_WIDTH 45 // default width for status bar panel #2
+#define DEFAULT_CONTAINER_POS 0x00400040 // default container position and size
+#define DEFAULT_CONTAINER_SIZE 0x019001f4
+
+/*
+ * core hotkey service ids
+ */
+
+#define TABSRMM_HK_LASTUNREAD 2
+#define TABSRMM_HK_LASTRECENT 4
+#define TABSRMM_HK_PASTEANDSEND 8
+#define TABSRMM_HK_SETUSERPREFS 9
+#define TABSRMM_HK_CONTAINEROPTIONS 10
+#define TABSRMM_HK_NUDGE 11
+#define TABSRMM_HK_SENDFILE 12
+#define TABSRMM_HK_QUOTEMSG 13
+#define TABSRMM_HK_SEND 14
+#define TABSRMM_HK_EMOTICONS 15
+#define TABARMM_HK_TOGGLEINFOPANEL 16
+#define TABSRMM_HK_HISTORY 17
+#define TABSRMM_HK_TOGGLETOOLBAR 18
+#define TABSRMM_HK_TOGGLEMULTISEND 19
+#define TABSRMM_HK_TOGGLERTL 20
+#define TABSRMM_HK_USERMENU 21
+#define TABSRMM_HK_USERDETAILS 22
+#define TABSRMM_HK_TOGGLEINFOPANEL 23
+#define TABSRMM_HK_CLEARLOG 24
+#define TABSRMM_HK_EDITNOTES 25
+#define TABSRMM_HK_TOGGLESENDLATER 26
+#define TABSRMM_HK_TOGGLESIDEBAR 27
+#define TABSRMM_HK_CHANNELMGR 28
+#define TABSRMM_HK_FILTERTOGGLE 29
+#define TABSRMM_HK_LISTTOGGLE 30
+#define TABSRMM_HK_MUC_SHOWSERVER 31
+
+#define TABSRMM_HK_SECTION_IM "Message windows - IM"
+#define TABSRMM_HK_SECTION_GENERIC "Message windows - all"
+#define TABSRMM_HK_SECTION_GC "Message windows - groupchats"
+
+/*
+ * encryption status bar indicator
+ */
+
+// extern HANDLE hHookIconPressedEvt;
+extern int status_icon_list_size;
+
+int SI_InitStatusIcons();
+int SI_DeinitStatusIcons();
+
+int GetStatusIconsCount();
+void DrawStatusIcons(struct TWindowData *dat, HDC hdc, RECT r, int gap);
+void SI_CheckStatusIconClick(struct TWindowData *dat, HWND hwndFrom, POINT pt, RECT rc, int gap, int code);
+
+typedef struct _tagSKINDesc {
+ ULONG ulID; // resource id
+ TCHAR tszName[30];
+} SKINDESC;
+
+#define SKIN_NR_ELEMENTS 6
+#define SKIN_VERSION 2
+
+/*
+ * icon defintions (index into g_buttonBarIcons)
+ */
+
+#define ICON_DEFAULT_SOUNDS 22
+#define ICON_DEFAULT_PULLDOWN 16
+#define ICON_DEFAULT_LEFT 25
+#define ICON_DEFAULT_RIGHT 28
+#define ICON_DEFAULT_UP 26
+#define ICON_DEFAULT_TYPING 5
+
+#define ICON_BUTTON_ADD 0
+#define ICON_BUTTON_CANCEL 6
+#define ICON_BUTTON_SAVE 7
+
+#endif /* _MSGS_H */
+
+
diff --git a/plugins/TabSRMM/include/nen.h b/plugins/TabSRMM/include/nen.h
new file mode 100644
index 0000000000..d3a8fa8bdd
--- /dev/null
+++ b/plugins/TabSRMM/include/nen.h
@@ -0,0 +1,169 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: nen.h 13750 2011-08-03 20:10:43Z george.hazan $
+ *
+ * This implements the event notification module for tabSRMM. The code
+ * is largely based on the NewEventNotify plugin for Miranda IM. See
+ * notices below for original copyright
+ *
+ * Name: NewEventNotify - Plugin for Miranda ICQ
+ * Description: Notifies you when you receive a message
+ * Author: icebreaker, <icebreaker@newmail.net>
+ * Date: 18.07.02 13:59 / Update: 16.09.02 17:45
+ * Copyright: (C) 2002 Starzinger Michael
+ *
+ */
+
+#ifndef _NEN_H_
+#define _NEN_H_
+
+//#include "m_popup.h"
+//#include "m_popupw.h"
+
+#define MODULE "tabSRMM_NEN"
+
+int tabSRMM_ShowPopup(WPARAM wParam, LPARAM lParam, WORD eventType, int windowOpen, struct TContainerData *pContainer, HWND hwndChild, const char *szProto, struct TWindowData *dat);
+
+
+#define DEFAULT_COLBACK RGB(255,255,128)
+#define DEFAULT_COLTEXT RGB(0,0,0)
+#define DEFAULT_MASKNOTIFY (MASK_MESSAGE|MASK_URL|MASK_FILE|MASK_OTHER)
+#define DEFAULT_MASKACTL (MASK_OPEN|MASK_DISMISS)
+#define DEFAULT_MASKACTR (MASK_DISMISS)
+#define DEFAULT_DELAY -1
+
+#define MASK_MESSAGE 0x0001
+#define MASK_URL 0x0002
+#define MASK_FILE 0x0004
+#define MASK_OTHER 0x0008
+
+#define MASK_DISMISS 0x0001
+#define MASK_OPEN 0x0002
+#define MASK_REMOVE 0x0004
+
+#define PU_REMOVE_ON_FOCUS 1
+#define PU_REMOVE_ON_TYPE 2
+#define PU_REMOVE_ON_SEND 4
+
+#define SETTING_LIFETIME_MIN 1
+#define SETTING_LIFETIME_MAX 60
+#define SETTING_LIFETIME_DEFAULT 4
+
+//Entrys in the database, don't translate
+#define OPT_PREVIEW "Preview"
+#define OPT_COLDEFAULT_MESSAGE "DefaultColorMsg"
+#define OPT_COLBACK_MESSAGE "ColorBackMsg"
+#define OPT_COLTEXT_MESSAGE "ColorTextMsg"
+#define OPT_COLDEFAULT_OTHERS "DefaultColorOthers"
+#define OPT_COLDEFAULT_ERR "DefaultColorErr"
+#define OPT_COLBACK_OTHERS "ColorBackOthers"
+#define OPT_COLTEXT_OTHERS "ColorTextOthers"
+#define OPT_COLBACK_ERR "ColorBackErr"
+#define OPT_COLTEXT_ERR "ColorTextErr"
+#define OPT_MASKNOTIFY "Notify"
+#define OPT_MASKACTL "ActionLeft"
+#define OPT_MASKACTR "ActionRight"
+#define OPT_MASKACTTE "ActionTimeExpires"
+#define OPT_MERGEPOPUP "MergePopup"
+#define OPT_DELAY_MESSAGE "DelayMessage"
+#define OPT_DELAY_OTHERS "DelayOthers"
+#define OPT_DELAY_ERR "DelayErr"
+#define OPT_SHOW_HEADERS "ShowHeaders"
+#define OPT_NORSS "NoRSSAnnounces"
+#define OPT_DISABLE "Disabled"
+#define OPT_MUCDISABLE "MUCDisabled"
+#define OPT_WINDOWCHECK "WindowCheck"
+#define OPT_LIMITPREVIEW "LimitPreview"
+#define OPT_REMOVEMASK "removemask"
+
+struct NEN_OPTIONS {
+ BOOL bPreview;
+ BOOL bDefaultColorMsg;
+ BOOL bDefaultColorOthers;
+ BOOL bDefaultColorErr;
+ BOOL bDisableNonMessage;
+ COLORREF colBackMsg;
+ COLORREF colTextMsg;
+ COLORREF colBackOthers;
+ COLORREF colTextOthers;
+ COLORREF colBackErr;
+ COLORREF colTextErr;
+ UINT maskActL;
+ UINT maskActR;
+ UINT maskActTE;
+ int iDelayMsg;
+ int iDelayOthers;
+ int iDelayErr;
+ int iDelayDefault;
+ BOOL bMergePopup;
+ BOOL bShowHeaders;
+ BOOL bNoRSS;
+ int iDisable;
+ int iMUCDisable;
+ int dwStatusMask;
+ BOOL bTraySupport;
+ BOOL bTrayExist;
+ BOOL iNoSounds;
+ BOOL iNoAutoPopup;
+ BOOL bWindowCheck;
+ int iLimitPreview;
+ WORD wMaxRecent;
+ WORD wMaxFavorites;
+ DWORD dwRemoveMask;
+};
+
+typedef struct {
+ HANDLE hEvent;
+ TCHAR szText[MAX_SECONDLINE + 2];
+ DWORD timestamp;
+} EVENT_DATAT;
+
+typedef struct {
+ UINT eventType;
+ HANDLE hContact;
+ NEN_OPTIONS *pluginOptions;
+ POPUPDATAT_V2* pud;
+ HWND hWnd;
+ long iSeconds;
+ TCHAR szHeader[256];
+ int nrMerged;
+ EVENT_DATAT *eventData;
+ int nrEventsAlloced;
+ int iActionTaken;
+ HWND hContainer;
+} PLUGIN_DATAT;
+
+#define NR_MERGED 5
+
+#define TIMER_TO_ACTION 50685
+
+#define MAX_DATASIZE 50
+#define MAX_POPUPS 20
+
+#endif
diff --git a/plugins/TabSRMM/include/resource.h b/plugins/TabSRMM/include/resource.h
new file mode 100644
index 0000000000..0ae02e554e
--- /dev/null
+++ b/plugins/TabSRMM/include/resource.h
@@ -0,0 +1,797 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by C:\tabsrmm\trunk\miranda\plugins\tabsrmm\resource.rc
+//
+#define IDD_TEMPLATEEDIT 1
+#define IDD_USERPREFS 2
+#define IDOK2 2
+#define IDD_USERPREFS1 3
+#define IDD_TABCONFIG 4
+#define IDD_ABOUT 7
+#define IDD_INFOPANEL 8
+#define IDC_TESTVALUE 10
+#define IDB_BITMAP1 10
+#define IDB_LOGO 10
+#define IDD_USERPREFS_FRAME 11
+#define IDR_SKIN1 13
+#define IDR_SKIN_AERO 14
+#define IDR_SKIN_AERO_GLOW 15
+#define IDD_SENDLATER_QMGR 15
+#define IDR_SKIN_AERO_SWITCHBAR 16
+#define IDD_WARNING 16
+#define IDR_SKIN_LOGO 20
+#define IDI_IMGOPEN 102
+#define IDI_IMGCLOSE 103
+#define IDI_FEATURE_DISABLED 104
+#define IDI_FEATURE_ENABLED 105
+#define IDR_CONTEXT 180
+#define IDM_PASTEFORMATTED 181
+#define IDM_CUT 182
+#define IDM_PASTE 183
+#define IDD_MSGSPLITNEW 184
+#define IDM_QUOTE 185
+#define IDM_COPY 186
+#define IDM_COPYALL 187
+#define IDM_SELECTALL 188
+#define IDM_CLEAR 189
+#define IDM_OPENNEW 190
+#define IDM_OPENEXISTING 191
+#define IDM_COPYLINK 192
+#define IDM_STICKY 193
+#define IDM_REPORTALWAY 194
+#define IDM_REPORTNEVER 195
+#define IDM_DONTREPORTMINIMIZED 196
+#define IDD_OPT_MSGDLG 243
+#define IDD_OPT_MSGLOG 245
+#define IDD_OPT_MSGTYPE 275
+#define IDD_MSGCONTAINER 276
+#define IDD_OPT_TABBEDMSG 277
+#define IDD_POPUP_OPT 278
+#define IDR_ACCEL 283
+#define IDR_TABCONTEXT 286
+#define IDD_MODERNOPTS 288
+#define IDD_SELECTCONTAINER 299
+#define IDD_CONTAINEROPTIONS 300
+#define IDD_OPT_CONTAINERS 301
+#define IDD_OPT_TOOLBAR 304
+#define IDR_MENUBAR 308
+#define IDD_CHOOSESTATUSMODES 310
+#define IDD_SKINTABDIALOG 312
+#define IDD_OPT_SKIN 313
+#define IDD_OPTIONS_PLUS 333
+#define IDD_EXCEPTION 400
+#define IDC_QMGR_REMOVE 1000
+#define IDC_EXCEPTION_DETAILS 1000
+#define IDC_UNLOAD 1000
+#define IDC_READNEXT 1000
+#define IDC_MINIMIZE 1000
+#define IDC_COPY_EXCEPTION 1001
+#define IDC_RELOADSKIN 1001
+#define IDC_APPLY 1001
+#define IDC_MAXIMIZE 1001
+#define IDC_SKINFILE 1002
+#define IDC_MESSAGE 1002
+#define IDC_THEMEEXPORT 1002
+#define IDC_HYPERLINKHAND 1003
+#define IDC_THEMEEXPORT2 1003
+#define IDC_THEMEIMPORT 1003
+#define IDC_EXPORT 1005
+#define IDC_IMPORT 1006
+#define IDC_PREVIEW 1006
+#define IDC_LOG 1006
+#define IDC_CHKNOTIFY_MESSAGE 1007
+#define IDC_FASTGRADIENT 1008
+#define IDC_CHKNOTIFY_URL 1009
+#define IDC_USESKIN 1011
+#define IDC_AUTOCLOSE 1012
+#define IDC_CHKNOTIFY_OTHER 1013
+#define IDC_AUTOMIN 1014
+#define IDC_CHKMENUITEM 1015
+#define IDC_TIME 1016
+#define IDC_CHKDISABLE 1017
+#define IDC_SENDMENU 1018
+#define IDC_CHKACTL_DISMISS 1019
+#define IDC_QUOTE 1020
+#define IDC_CHKACTL_OPEN 1021
+#define IDC_NAME 1022
+#define IDC_CHKACTL_REMOVE 1023
+#define IDC_INFOPANELMENU 1023
+#define IDC_CLOSE 1024
+#define IDC_SAVE 1025
+#define IDC_CHKACTR_DISMISS 1026
+#define IDC_CHKACTR_OPEN 1028
+#define IDC_CONTACTPIC 1029
+#define IDC_ST_ENTERMSG 1031
+#define IDC_PANELNICK 1032
+#define IDC_CHKWINDOWCHECK 1032
+#define IDC_PANELUIN 1033
+#define IDC_CHKPREVIEW 1034
+#define IDC_CHKINFINITE 1035
+#define IDC_PANELSTATUS 1036
+#define IDC_SPLITTER 1037
+#define IDC_CHKDEFAULTCOL_MESSAGE 1038
+#define IDC_CHKDEFAULTCOL_MUC 1039
+#define IDC_CHKDEFAULTCOL_ERR 1040
+#define IDC_COLBACK_MESSAGE 1041
+#define IDC_COLTEXT_MESSAGE 1042
+#define IDC_COLTEXT_MUC 1043
+#define IDC_COLBACK_MUC 1044
+#define IDC_COLTEXT_ERR 1045
+#define IDC_COLBACK_ERR 1046
+#define IDC_SHOWNAMES 1047
+#define IDC_CHKDEFAULTCOL_OTHERS 1050
+#define IDC_COLBACK_OTHERS 1051
+#define IDC_CLOSEONREPLY 1052
+#define IDC_COLTEXT_OTHERS 1053
+#define IDC_SHOWFILES 1054
+#define IDC_MERGEPOPUP 1056
+#define IDC_CHKINFINITE_MESSAGE 1057
+#define IDC_CHKMERGEPOPUP 1058
+#define IDC_IMGTAG 1058
+#define IDC_SHOWURLS 1059
+#define IDC_ANIAVATAR 1059
+#define IDC_DELAY_MESSAGE 1060
+#define IDC_SCROLLFIX 1060
+#define IDC_CLIENTINSTATBAR 1061
+#define IDC_TYPINGSOUNDS 1062
+#define IDC_OFFLINEMULTI 1063
+#define IDC_CLIENTINSTATBAR2 1063
+#define IDC_ICONWARNINGS 1063
+#define IDC_AUTOCLOSEV2 1064
+#define IDC_RESTART 1065
+#define IDC_DELAY_OTHERS 1066
+#define IDC_CLIST 1067
+#define IDC_DELAY_MUC 1067
+#define IDC_NUMBERMSG 1068
+#define IDC_MULTISPLITTER 1069
+#define IDC_CHKSHOWDATE 1070
+#define IDC_SAVEPERCONTACT 1071
+#define IDC_CHKSHOWTIME 1072
+#define IDC_CHKSHOWHEADERS 1073
+#define IDC_LOADCOUNTN 1074
+#define IDC_RDNEW 1075
+#define IDC_LOADCOUNTSPIN 1076
+#define IDC_RDOLD 1077
+#define IDC_SHOWINFOLINE 1078
+#define IDC_LBNUMBERMSG 1079
+#define IDC_SHOWBUTTONLINE 1080
+#define IDC_CHKINFINITE_URL 1081
+#define IDC_LOADUNREAD 1082
+#define IDC_SENDONENTER 1083
+#define IDC_CHKINFINITE_FILE 1084
+#define IDC_LOADCOUNT 1085
+#define IDC_SENDONDBLENTER 1086
+#define IDC_CHKINFINITE_OTHERS 1087
+#define IDC_LOADTIMEN 1088
+#define IDC_LOADTIMESPIN 1089
+#define IDC_LOADTIME 1090
+#define IDC_CMDEDITHEADERS 1091
+#define IDC_TRIM 1091
+#define IDC_FONTLIST 1092
+#define IDC_TRIMSPIN 1092
+#define IDC_USEOSD 1093
+#define IDC_CHOOSEFONT 1094
+#define IDC_CHKACTTE_DISMISS 1095
+#define IDC_CHKACTTE_OPEN 1096
+#define IDC_STMINSOLD 1097
+#define IDC_CHKACTTE_REMOVE 1098
+#define IDC_NORSS 1099
+#define IDC_DETAILS 1100
+#define IDC_ADD 1101
+#define IDC_DELAY_ERR 1102
+#define IDC_RTL 1103
+#define IDC_PIC 1104
+#define IDC_SMILEYBTN 1105
+#define IDC_FONTBOLD 1106
+#define IDC_FONTITALIC 1107
+#define IDC_FONTUNDERLINE 1108
+#define IDC_FONTFACE 1110
+#define IDC_HISTORY 1111
+#define IDC_CANCELADD 1112
+#define IDC_FONTSTRIKEOUT 1113
+#define IDC_MATH_BKGCOLOUR 1124
+#define IDC_FONTCOLOR 1127
+#define IDC_LOGFROZENTEXT 1128
+#define IDC_FONTCOLOUR 1128
+#define IDC_STSIZETEXT 1135
+#define IDC_STCOLOURTEXT 1136
+#define IDC_PRESETSPLIT 1137
+#define IDC_PRESETSINGLE 1138
+#define IDC_STMSGLOGGROUP 1139
+#define IDC_PROTOCOL 1140
+#define IDC_STMSGLOGGROUP2 1140
+#define IDC_STMSGLOGGROUP3 1141
+#define IDC_PROTOMENU 1141
+#define IDC_TYPING 1143
+#define IDC_TOGGLETOOLBAR 1144
+#define IDC_ERRORTEXT 1145
+#define IDC_SHOWNOTIFY 1146
+#define IDC_STATUSWIN 1147
+#define IDC_TYPEFLASHWIN 1148
+#define IDC_CHARCOUNT 1149
+#define IDC_TYPENOWIN 1150
+#define IDC_TYPEWIN 1151
+#define IDC_CASCADE 1151
+#define IDC_SECONDS 1152
+#define IDC_NOTIFYTRAY 1153
+#define IDC_NOTIFYBALLOON 1154
+#define IDC_NOTIFYBALLOON2 1155
+#define IDC_NOTIFYPOPUP 1155
+#define IDC_MathSubst 1156
+#define IDC_INDENT 1157
+#define IDC_INDENTAMOUNT 1158
+#define IDC_MSGTABS 1159
+#define IDC_SIDEBARUP 1160
+#define IDC_SIDEBARDOWN 1161
+#define IDC_WARNONCLOSE 1162
+#define IDC_CUT_TABTITLE 1163
+#define IDC_CUT_TITLEMAX 1164
+#define IDC_SHOWTABTIP 1165
+#define IDC_SHOWSTATUSONTAB 1166
+#define IDC_SWAPTIMESTAMP 1167
+#define IDC_AUTOCREATETABS 1168
+#define IDC_LOCALTIME 1169
+#define IDC_O_HIDETITLE 1170
+#define IDC_STICKY 1171
+#define IDC_LOGSTATUS 1172
+#define IDC_DEBUGPOPUPS 1173
+#define IDC_CONTAINERGROUPMODE 1174
+#define IDC_SELFTYPING 1175
+#define IDC_LOGHOTKEYS 1176
+#define IDC_NOTITLE 1177
+#define IDC_TABPADDING 1178
+#define IDC_PADSPIN 1179
+#define IDC_HTABPADDING 1179
+#define IDC_BOTTOMTABADJUST 1180
+#define IDC_POPUPCONTAINER 1181
+#define IDC_TABWIDTH 1181
+#define IDC_PRIVATESPLITTER 1182
+#define IDC_CNTPRIVATE 1182
+#define IDC_NEWSPLITLAYOUT 1183
+#define IDC_O_NOTABS 1184
+#define IDC_DONTREPORTUNFOCUSED 1185
+#define IDC_ESC_MINIMIZE 1186
+#define IDC_USEDIVIDERS 1187
+#define IDC_DRAWGRID 1188
+#define IDC_LIMITTABS 1189
+#define IDC_WANTVERTICALGRID 1190
+#define IDC_LIMITPREVIEW 1191
+#define IDC_AUTOLOCALE 1192
+#define IDC_MUC_LOGCOLORS 1192
+#define IDC_DONTREPORTUNFOCUSED2 1193
+#define IDC_GCHECK 1194
+#define IDC_HIDETAB 1195
+#define IDC_O_DONTREPORT 1196
+#define IDC_USEDEFERRED 1197
+#define IDC_AUTOSWITCHTABS 1198
+#define IDC_USEINDIVIDUALBKG 1199
+#define IDC_SINGLEWINDOWMODE 1200
+#define IDC_FLATBUTTONS 1201
+#define IDC_O_STICKY 1202
+#define IDC_DIVIDERSUSEPOPUPCONFIG 1203
+#define IDC_FLASHFOREVER 1205
+#define IDC_DONTFLASH 1206
+#define IDC_O_FLASHDEFAULT 1208
+#define IDC_FLASHDEFAULT 1209
+#define IDC_DEFAULTCONTAINERMODE 1210
+#define IDC_ALWAYS 1211
+#define IDC_DONTREPORTFOCUSED2 1212
+#define IDC_TRANSPARENCY 1215
+#define IDC_PANELSPLITTER 1216
+#define IDC_AUTOCREATECONTAINER 1216
+#define IDC_LIMITAVATARS 1217
+#define IDC_DONTREPORT 1219
+#define IDC_SPIN1 1220
+#define IDC_CNTLIST 1221
+#define IDC_SPIN3 1221
+#define IDC_NEWCONTAINER 1222
+#define IDC_TABWIDTHSPIN 1222
+#define IDC_UPDATEPREVIEW 1223
+#define IDC_MODIFY 1223
+#define IDC_SAVESIZEASGLOBAL 1223
+#define IDC_REVERTGLOBAL 1223
+#define IDC_CREATENEW 1224
+#define IDC_RTLMODIFY 1224
+#define IDC_RESETALLTEMPLATES 1224
+#define IDC_SENDLATER 1226
+#define IDC_RETRY 1227
+#define IDC_SETUPAUTOCREATEMODES 1228
+#define IDC_POPUPSTATUSMODES 1229
+#define IDC_DELETECONTAINER 1230
+#define IDC_CANCELSEND 1231
+#define IDC_O_FLASHALWAYS 1232
+#define IDC_RENAMECONTAINER 1233
+#define IDC_RETRY2 1234
+#define IDC_MSGSENDLATER 1235
+#define IDC_O_FLASHNEVER 1236
+#define IDC_NEWCONTAINERNAME 1237
+#define IDC_O_TITLENEVER 1238
+#define IDC_O_TITLEFRONT 1239
+#define IDC_O_TITLESUFFIX 1240
+#define IDC_TRANSPARENCY_ACTIVE 1241
+#define IDC_TRANSPARENCY_INACTIVE 1242
+#define IDC_INDENTSPIN 1250
+#define IDC_TABBORDER 1251
+#define IDC_SPIN2 1252
+#define IDC_TABBORDERSPIN 1253
+#define IDC_FLASHINTERVALSPIN 1254
+#define IDC_HIDESBAR 1255
+#define IDC_TABBORDEROUTER 1256
+#define IDC_TABBORDEROUTERRIGHT 1257
+#define IDC_TABBORDERSPINOUTER 1258
+#define IDC_ALWAYSPOPUPSINACTIVE 1259
+#define IDC_TABBORDERSPINOUTER2 1259
+#define IDC_BOTTOMTABADJUSTSPIN 1259
+#define IDC_HISTORYSIZE 1260
+#define IDC_TABBORDERSPINOUTERRIGHT 1260
+#define IDC_HISTORYSIZESPIN 1261
+#define IDC_TABBORDEROUTERTOP 1261
+#define IDC_HOTKEYSAREGLOBAL 1262
+#define IDC_TABBORDERSPINOUTERTOP 1262
+#define IDC_SINGLEROWTAB 1263
+#define IDC_STREAMTHREADING 1264
+#define IDC_TABBORDEROUTERBOTTOM 1264
+#define IDC_IEVIEWMODE 1265
+#define IDC_TABBORDERSPINOUTERBOTTOM 1265
+#define IDC_TEXTFORMATTING 1266
+#define IDC_AVATARMODE 1267
+#define IDC_CODEPAGES 1268
+#define IDC_OWNAVATARMODE 1268
+#define IDC_EMPTYLINEFIX 1272
+#define IDC_SPLITTERSTATICEDGES 1273
+#define IDC_MAXAVATARHEIGHT 1275
+#define IDC_TABLIMIT 1276
+#define IDC_RIGHTINDENT 1277
+#define IDC_AVATARSPIN 1278
+#define IDC_TABLIMITSPIN 1279
+#define IDC_SHOWFORMATTING 1280
+#define IDC_AGGRESSIVEUPDATE 1283
+#define IDC_THINSEPARATORS 1284
+#define IDC_RINDENTSPIN 1285
+#define IDC_STATICERRORICON 1286
+#define IDC_STATICTEXT 1287
+#define IDC_GROUPMODE 1288
+#define IDC_ANIMATED 1289
+#define IDC_ISFAVORITE 1289
+#define IDC_ALWAYSTRIM 1289
+#define IDC_SKIN_LOADFONTS 1289
+#define IDC_PRESERVEAVATARSIZE 1289
+#define IDC_UPREFS_SHOWICONS 1289
+#define IDC_ALWAYSTRIM2 1290
+#define IDC_SKIN_LOADTEMPLATES 1290
+#define IDC_UPREFS_SHOWSYMBOLS 1290
+#define IDC_SKIN_LOADTEMPLATES2 1291
+#define IDC_UPREFS_INOUTICONS 1291
+#define IDC_AVADYNAMIC 1292
+#define IDC_UPREFS_SHOWTIMESTAMP 1292
+#define IDC_USESNAPPING 1293
+#define IDC_UPREFS_SHOWSECONDS 1293
+#define IDC_UPREFS_SHOWICONS3 1294
+#define IDC_UPREFS_SHOWDATES 1294
+#define IDC_SENDFORMAT 1295
+#define IDC_UPREFS_LOCALTIME 1295
+#define IDC_FLATMSGLOG 1296
+#define IDC_UPREFS_INDENT 1296
+#define IDC_UPREFS_GRID 1297
+#define IDC_UPREFS_GROUPING 1298
+#define IDC_TOGGLESIDEBAR 1299
+#define IDC_CNTNOSTATUSBAR 1299
+#define IDC_UPREFS_BBCODE 1299
+#define IDC_SECTIONTREE 1300
+#define IDC_UPREFS_RTL 1301
+#define IDC_CHECKICONDLL 1302
+#define IDC_UPREFS_LOGSTATUS 1302
+#define IDC_ENABLETRAYSUPPORT 1303
+#define IDC_UPREFS_LOGSTATUS2 1303
+#define IDC_UPREFS_NORMALTEMPLATES 1303
+#define IDC_HEADERSHADING 1304
+#define IDC_HIDEMENUBAR 1305
+#define IDC_STATICCONTROL 1307
+#define IDC_AUTOCLOSETABTIME 1308
+#define IDC_AUTOCLOSETABSPIN 1309
+#define IDC_SENDONSHIFTENTER 1310
+#define IDC_USEGLOBALSIZE 1311
+#define IDC_LOADONLYACTUAL 1311
+#define IDC_MICROLF 1312
+#define IDC_EVENTAPI 1313
+#define IDC_MINIMIZETOTRAY 1316
+#define IDC_DELETETEMP 1318
+#define IDC_FORMATTING 1319
+#define IDC_AUTOSELECTCOPY 1319
+#define IDC_HIDETOOLBAR 1320
+#define IDC_FLASHCLIST 1322
+#define IDC_MSGLOGPLUGIN 1323
+#define IDC_UIDSTATUSBAR 1324
+#define IDC_NRFLASH 1325
+#define IDC_NRFLASHSPIN 1326
+#define IDC_FLASHINTERVAL 1327
+#define IDC_USEKBDHOOK 1328
+#define IDC_STATIC111 1329
+#define IDC_TAB1 1330
+#define IDC_ALWAYSFULLWIDTHTOOLBAR 1335
+#define IDC_FORMATWHOLEWORDSONLY 1337
+#define IDC_STATUSGROUP 1338
+#define IDC_ALLOWSENDBUTTONHIDE 1340
+#define IDC_VERTICALMAX 1341
+#define IDC_AUTOSPLITTER 1342
+#define IDC_ICONDLLNAME 1343
+#define IDC_SAVETEMPLATE 1344
+#define IDC_SELECTICONDLL 1345
+#define IDC_RTLDEFAULT 1346
+#define IDC_MATHMODSUPPORT 1348
+#define IDC_MESSAGEPREVIEWLIMIT 1349
+#define IDC_MESSAGEPREVIEWLIMITSPIN 1350
+#define IDC_DELAY_MESSAGE_SPIN 1351
+#define IDC_DELAY_MESSAGE_MUC_SPIN 1352
+#define IDC_DELAY_ERR_SPIN 1353
+#define IDC_MESSAGEPREVIEWLIMITSPIN2 1354
+#define IDC_DELAY_OTHERS_SPIN 1354
+#define IDC_TEMPLATELIST 1361
+#define IDC_EDITTEMPLATE 1362
+#define IDC_REVERT 1363
+#define IDC_FORGET 1364
+#define IDC_COLOR1 1366
+#define IDC_COLOR2 1367
+#define IDC_COLOR3 1368
+#define IDC_COLOR4 1369
+#define IDC_COLOR5 1370
+#define IDC_FORCEANSI 1371
+#define IDC_TEMPLOVERRIDE 1372
+#define IDC_IGNORETIMEOUTS 1372
+#define IDC_RTLTEMPLOVERRIDE 1373
+#define IDC_SELECTTHEME 1376
+#define IDC_RELOAD 1376
+#define IDC_LOGOPTIONS 1377
+#define IDC_WINDOWOPTIONS 1378
+#define IDC_TRAYCONTAINER 1379
+#define IDC_EVENTOPTIONS 1380
+#define IDC_VARIABLESHELP 1381
+#define IDC_TABMSGOPTIONS 1384
+#define IDC_HELPTEXT 1392
+#define IDC_TITLEFORMAT 1393
+#define IDC_THEME 1394
+#define IDC_INFOPANEL 1395
+#define IDC_SUPPORT 1396
+#define IDC_SHOWAVATAR 1396
+#define IDC_NOPOPUPAVAIL 1398
+#define IDC_QHTM 1399
+#define IDC_TSLABEL_ACTIVE 1400
+#define IDC_TSLABEL_INACTIVE 1401
+#define IDC_TITLEBOX 1402
+#define IDC_DESC 1404
+#define IDC_LABEL_PRIVATETHEME 1405
+#define IDC_MSGLOGDIDSPLAY 1407
+#define IDC_IMCHECK 1410
+#define IDC_CHATCHECK 1411
+#define IDC_CANBEHIDDEN 1412
+#define IDC_BBRESET 1413
+#define IDC_BOTTOMTOOLBAR 1414
+#define IDC_BUTTON1 1415
+#define IDC_SEPARATOR 1415
+#define IDC_PLUS_REVERT 1415
+#define IDC_SIZECOMPACT 1415
+#define IDC_RESCANSKIN 1415
+#define IDC_RESETWARNINGS 1415
+#define IDC_TIMEOUTSPIN 1416
+#define IDC_SIZENORMAL 1416
+#define IDC_SIZELARGE 1417
+#define IDC_MTN_POPUPMODE 1418
+#define IDC_MTN_HELP 1419
+#define IDC_CUT_TITLEMAXSPIN 1420
+#define IDC_HELP_CONTAINERS 1421
+#define IDC_HELP_GENERAL 1422
+#define IDC_CLOSEONESC 1423
+#define IDC_ALWAYSPOPUP 1424
+#define IDC_AEROEFFECT 1424
+#define IDC_CREATEMIN 1425
+#define IDC_ESCMODE 1425
+#define IDC_CHECK5 1426
+#define IDC_TABMODE 1426
+#define IDC_SENDSHIFTENTER 1427
+#define IDC_O_TABMODE 1427
+#define IDC_SENDENTER 1428
+#define IDC_O_SBARLAYOUT 1428
+#define IDC_PANELVISIBILITY 1428
+#define IDC_SENDDBLENTER 1429
+#define IDC_SBARLAYOUT 1429
+#define IDC_PANELSIZE 1429
+#define IDC_MINSEND 1430
+#define IDC_IPCONFIG_TITLE 1430
+#define IDC_SENDCTRLENTER 1431
+#define IDC_NOSYNC 1431
+#define IDC_USETABS 1432
+#define IDC_IPCONFIG_FOOTER 1432
+#define IDC_NOOPENPOPUP 1433
+#define IDC_NOOPENNOTIFY 1433
+#define IDC_GROUP_SCOPE 1433
+#define IDC_CREATENOACTIVATE 1434
+#define IDC_GROUP_SIZE 1434
+#define IDC_NOTIFYMSG 1435
+#define IDC_GROUP_OTHER 1435
+#define IDC_POPUPONCREATE 1436
+#define IDC_SIZE_TIP 1436
+#define IDC_IPCONFIG_PRIVATECONTAINER 1437
+#define IDC_EXPLAINMSGLOGSETTINGS 1437
+#define IDC_NOTIFYFILE 1438
+#define IDC_PANELPICTUREVIS 1438
+#define IDC_SKINNAME 1438
+#define IDC_NOTIFYURL 1439
+#define IDC_SKINROOTFOLDER 1439
+#define IDC_NOTIFYOTHER 1440
+#define IDC_SKIN_WARN 1440
+#define IDC_QMGR_LIST 1441
+#define IDC_QMGR_FILTER 1442
+#define IDC_TOOLBARTREE 1444
+#define IDC_QMGR_HELP 1444
+#define IDC_QMGR_ERRORPOPUPS 1445
+#define IDC_QMGR_ERRORPOPUPS2 1446
+#define IDC_QMGR_SUCCESSPOPUPS 1446
+#define IDC_BUTTON2 1446
+#define IDC_SKIN_CLOSENOW 1446
+#define IDC_CHECK1 1447
+#define IDC_DONTSHOWAGAIN 1447
+#define IDC_CAPTION 1448
+#define IDC_WARNTEXT 1449
+#define IDC_WARNICON 1450
+#define IDC_WARNGROUP 1451
+#define IDC_EX_REASON 1452
+#define IDC_FLASHICON 1489
+#define IDC_FLASHLABEL 1490
+#define IDC_STATIC_VISIBILTY 1491
+#define IDC_BUTTONTABS 1492
+#define IDC_CLOSEBUTTONONTABS 1493
+#define IDC_O_STATIC_AVATAR 1501
+#define IDC_O_STATIC_OWNAVATAR 1502
+#define IDC_USEAERO 1531
+#define IDC_USEAEROPEEK 1532
+#define IDC_TXT_TITLE1 1617
+#define IDC_TXT_TITLE2 1618
+#define IDC_TXT_TITLE4 1620
+#define IDC_TXT_TITLE5 1622
+#define IDC_TXT_TITLE3 1623
+#define IDC_O_EXPLAINGLOBALNOTIFY 1624
+#define IDC_O_AUTOHIDE 1625
+#define IDC_O_AUTOHIDESECONDS 1626
+#define IDC_O_ENABLESOUNDS 1701
+#define IDC_O_SOUNDSMINIMIZED 1702
+#define IDC_O_SOUNDSUNFOCUSED 1703
+#define IDC_O_SOUNDSINACTIVE 1704
+#define IDC_O_SOUNDSFOCUSED 1705
+#define IDC_O_TITLEBARFORMAT 1706
+#define IDC_EDIT1 1720
+#define IDC_O_CNTPRIVATE 1901
+#define IDC_PLUS_CHECKTREE 2000
+#define IDC_COPYRIGHT 2002
+#define IDC_PLUS_HELP 2004
+#define IDC_BUILDTIME 2005
+#define IDC_O_HELP_TITLEFORMAT 2064
+#define IDC_OPTIONSTAB 2111
+#define IDC_HEADERBAR 2397
+#define IDC_AVATARSONTASKBAR 2735
+#define IDC_TSLABEL_EXPLAINTHEME 3123
+#define IDC_TSLABEL_REOPENWARN 3124
+#define IDD_OPT_TYPINGNOTIFYPOPUP 30159
+#define IDI_START1 30160
+#define IDI_STOP1 30161
+#define IDI_START2 30162
+#define IDI_STOP2 30163
+#define IDI_ENABLED 30164
+#define IDI_DISABLED 30165
+#define IDD_OPT 30166
+#define IDC_START 30167
+#define IDC_STOP 30168
+#define IDI_START3 30169
+#define IDI_STOP3 30170
+#define IDI_START4 30171
+#define IDI_STOP4 30172
+#define IDI_START5 30173
+#define IDI_STOP5 30174
+#define IDI_START6 30175
+#define IDI_STOP6 30176
+#define IDI_START7 30177
+#define IDI_STOP7 30178
+#define IDI_START8 30179
+#define IDI_STOP8 30180
+#define IDI_START9 30181
+#define IDI_STOP9 30182
+#define IDC_ICON1 31600
+#define IDC_ICON2 31601
+#define IDC_TIMEOUT_POPUP2 31602
+#define IDC_TIMEOUT_CUSTOM2 31603
+#define IDC_TIMEOUT_POPUP 31604
+#define IDC_TIMEOUT_PROTO 31605
+#define IDC_TIMEOUT_CUSTOM 31606
+#define IDC_TIMEOUT_VALUE 31607
+#define IDC_TIMEOUT_POPUP3 31608
+#define IDC_TIMEOUT_PERMANENT2 31608
+#define IDC_USEWINCOLORS 31609
+#define IDC_USEPOPUPCOLORS 31610
+#define IDC_TYPEON_BG 31611
+#define IDC_TYPEON_TX 31612
+#define IDC_TYPEOFF_BG 31613
+#define IDC_TYPEOFF_TX 31614
+#define IDC_INFO 31615
+#define IDC_INFO2 31616
+#define IDC_WO 31617
+#define IDC_TIMEOUT_PERMANENT1 31618
+#define IDC_TIMEOUT_PERMANENT 31618
+#define IDC_SHOWMENU 31619
+#define IDC_DISABLED 31620
+#define IDC_ONEPOPUP 31621
+#define IDC_WOCL 31622
+#define IDC_ICONS 31623
+#define IDC_TIMEOUT_VALUE2 31624
+#define IDC_PREVIEW_ALL 31625
+#define ID_CLOSETAB_DETACHTAB 40025
+#define ID_TABCONTEXT_NEXTTAB 40026
+#define ID_TABCONTEXT_ATTACH 40027
+#define ID_TABCONTEXT_CLOSECONTAINER 40028
+#define ID_TABCONTEXT_PREVTAB 40029
+#define ID_CLOSETAB 40030
+#define ID_TABMENU_CLOSETAB 40031
+#define ID_TABMENU_SAVELOCALESETTINGFORTHISCONTACT 40034
+#define ID_TABMENU_OPENWINDOWSERVICE 40035
+#define ID_TABMENU_ATTACHTOCONTAINER 40036
+#define ID_Menu 40037
+#define ID_PICMENU_TOGGLEAVATARDISPLAY 40041
+#define ID_PICMENU_SETTINGS 40042
+#define ID_LOG_CONTAINEROPTIONS 40045
+#define ID_TABMENU_CONTAINEROPTIONS 40046
+#define ID_LOGMENU_SHOWMESSAGEICONS 40056
+#define ID_LOGMENU_LOADDEFAULTS 40057
+#define ID_LOGMENU_ALWAYSUSEGLOBALSPLITTERPOSITION 40060
+#define ID_LOGMENU_TIMESTAMPSETTINGS 40061
+#define ID_LOGMENU_MESSAGELOGFORMATTING 40062
+#define ID_TABMENU_CLOSECONTAINER 40063
+#define ID_STATUSBARSETTINGS_USEGLOBALDEFAULT 40065
+#define ID_STATUSBARSETTINGS_SHOWTHESTATUSBAR 40066
+#define ID_STATUSBARSETTINGS_HIDETHESTATUSBAR 40067
+#define ID_VIEW_SHOWMENUBAR 40076
+#define ID_VIEW_SHOWSTATUSBAR 40077
+#define ID_VIEW_SHOWTOOLBAR 40078
+#define ID_TOOLBAR_SENDBUTTON 40079
+#define ID_TOOLBAR_USERINFORMATION 40080
+#define ID_TOOLBAR_EXTRABUTTONS 40081
+#define ID_VIEW_SHOWAVATAR 40082
+#define ID_VIEW_SHOWTITLEBAR 40083
+#define ID_FILE 40084
+#define ID_FILE_CLOSE 40085
+#define ID_FILE_CLOSEMESSAGESESSION 40086
+#define ID_VIEW_SHOWMULTISENDCONTACTLIST 40087
+#define ID_VIEW_TITLEBAR 40088
+#define ID_VIEW_TABSATBOTTOM 40093
+#define ID_VIEW_STAYONTOP 40095
+#define ID_HELP 40096
+#define ID_OPTIONS_EVENTPOPUPS 40097
+#define ID_EVENTPOPUPS_DISABLEALLEVENTPOPUPS 40098
+#define ID_OPTIONS_SOUNDS 40101
+#define ID_SOUNDS_DISABLEALLMESSAGESOUNDS 40102
+#define ID_SOUNDS_SYNCSOUNDSWITHEVENTPOPUPS 40103
+#define ID_SOUNDS_ENABLEALLMESSAGESOUNDS 40104
+#define ID_VIEW_FLASHING 40105
+#define ID_WINDOWFLASHING_USEDEFAULTVALUES 40106
+#define ID_WINDOWFLASHING_FLASHUNTILFOCUSED 40107
+#define ID_WINDOWFLASHING_DISABLEFLASHING 40108
+#define ID_FILE_SAVEMESSAGELOGAS 40109
+#define ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISMINIMIZED 40110
+#define ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISUNFOCUSED 40111
+#define ID_EVENTPOPUPS_SHOWPOPUPSFORALLINACTIVESESSIONS 40112
+#define ID_OPTIONS_SAVECURRENTWINDOWPOSITIONASDEFAULT 40113
+#define ID_CONTAINER_CONTAINEROPTIONS 40114
+#define ID_MESSAGELOG 40115
+#define ID_MESSAGELOG_LOGITEMSTOSHOW 40116
+#define ID_LOGITEMSTOSHOW_USETHINGRIDLINES 40117
+#define ID_MESSAGELOG_TIMESTAMPSETTINGS 40118
+#define ID_MESSAGELOG_MESSAGELOGFORMATTING 40119
+#define ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISFOCUSED 40120
+#define ID_LOGMENU_MESSAGELOGSETTINGSAREGLOBAL 40124
+#define ID_USER 40125
+#define ID_TITLEBAR_USESTATICCONTAINERICON 40126
+#define ID_PICMENU_ALWAYSKEEPTHEBUTTONBARATFULLWIDTH 40134
+#define ID_SENDMENU_SENDDEFAULT 40135
+#define ID_SENDMENU_SENDTOMULTIPLEUSERS 40136
+#define ID_SENDMENU_SENDTOCONTAINER 40137
+#define ID_SENDMENU_FORCEANSISEND 40138
+#define ID_VIEW_VERTICALMAXIMIZE 40143
+#define ID_SENDMENU_SENDLATER 40144
+#define ID_PROTOMENU_SPLITTER 40145
+#define ID_MODE_GLOBAL 40148
+#define ID_MODE_PRIVATE 40150
+#define ID_UNREADMENU_TEST 40151
+#define ID_UNREADMENU_FOOBAR 40152
+#define ID_UNREADMENU_ 40153
+#define ID_TRAYCONTEXT_RECENTSESSIONS 40154
+#define ID_RECENTSESSIONS_1 40155
+#define ID_TRAYCONTEXT_FAVORITES 40156
+#define ID_FAVORITES_1 40157
+#define ID_TRAYCONTEXT_DISABLEALLPOPUPS 40158
+#define ID_TRAYCONTEXT_DON 40159
+#define ID_TRAYCONTEXT_HIDEALLMESSAGECONTAINERS 40160
+#define ID_TRAYCONTEXT_RESTOREALLMESSAGECONTAINERS 40161
+#define ID_TRAYCONTEXT_DON40223 40164
+#define ID_TRAYCONTEXT_BE 40165
+#define ID_RECENTSESSIONS_2 40166
+#define ID_PROTOMENU_SENDTEXTFORMATTING 40167
+#define ID_SENDTEXTFORMATTING_GLOBAL 40169
+#define ID_Menu40228 40170
+#define ID_VIEW_BOTTOMTOOLBAR 40171
+#define ID_GLOBAL_OFF 40172
+#define ID_SENDTEXTFORMATTING_THISCONTACT 40173
+#define ID_THISCONTACT_GLOBALSETTING 40174
+#define ID_THISCONTACT_BBCODE 40175
+#define ID_THISCONTACT_OFF 40177
+#define ID_GLOBAL_BBCODE 40178
+#define ID_PROTOMENU_FAVORITES 40179
+#define ID_FAVORITES_ADDCONTACTTOFAVORITES 40180
+#define ID_FAVORITES_REMOVECONTACTFROMFAVORITES 40181
+#define ID_FILE_HTTP 40182
+#define ID_LOG_FREEZELOG 40183
+#define ID_FONT_SIZE 40186
+#define ID_SIZE_LARGE 40187
+#define ID_SIZE_BIGGER 40188
+#define ID_SIZE_NORMAL 40189
+#define ID_SIZE_SMALLER 40190
+#define ID_SIZE_TINY 40191
+#define ID_FONT_RED 40192
+#define ID_FONT_GREEN 40193
+#define ID_FONT_BLUE 40194
+#define ID_FONT_MAGENTA 40195
+#define ID_FONT_YELLOW 40196
+#define ID_FONT_BLACK 40197
+#define ID_FONT_WHITE 40198
+#define ID_FONT_CLEARALLFORMATTING 40199
+#define ID_FONT_DEFAULTCOLOR 40200
+#define ID_FONT_CYAN 40201
+#define ID_SENDMENU_SENDWITHOUTTIMEOUTS 40201
+#define ID_DUMMY_NOMESSAGESESSIONSOPENED 40202
+#define ID_TRAYCONTEXT_SHOWTHETRAYICON 40204
+#define ID_INFOPANEL_QUICKTOGGLE 40206
+#define ID_INFOPANEL_GLOBAL 40207
+#define ID_VIEW_INFOPANEL 40208
+#define ID_GLOBAL_ENABLED 40208
+#define ID_GLOBAL_DISABLED 40209
+#define ID_INFOPANEL_THISCONTACT 40210
+#define ID_THISCONTACT_USEGLOBALSETTING 40211
+#define ID_THISCONTACT_ALWAYSON 40212
+#define ID_THISCONTACT_ALWAYSOFF 40213
+#define ID_PANELPICMENU_RESETTHEAVATAR 40218
+#define ID_EDITOR_PASTEANDSENDIMMEDIATELY 40221
+#define ID_HELP_ABOUTTABSRMM 40223
+#define ID_SENDMENU_SENDNUDGE 40228
+#define ID_SPLITTERCONTEXT_SAVEGLOBALFORALLSESSIONS 40229
+#define ID_SPLITTERCONTEXT_SAVEFORTHISCONTACTONLY 40230
+#define ID_SPLITTERCONTEXT_FORGETTHECHANGES 40231
+#define ID_SPLITTERCONTEXT_SETPOSITIONFORTHISSESSION 40232
+#define ID_FONT_CYAN40233 40233
+#define ID_TABMENU_LEAVECHATROOM 40234
+#define ID_PANELPICMENU_SAVETHISPICTUREAS 40235
+#define ID_PICMENU_SAVETHISPICTUREAS 40236
+#define ID_TABMENU_SAVETABPOSITION 40239
+#define ID_TABMENU_CLEARSAVEDTABPOSITION 40240
+#define ID_VISIBILITY_DEFAULT 40241
+#define ID_VISIBILITY_HIDDENFORTHISCONTACT 40242
+#define ID_VISIBILITY_VISIBLEFORTHISCONTACT 40243
+#define ID_LOGMENU_USEADVANCEDTEMPLATE 40244
+#define ID_MESSAGELOG_USESIMPLETEMPLATES 40246
+#define ID_EDITOR_SHOWMESSAGELENGTHINDICATOR 40248
+#define ID_LOGMENU_MESSAGELOGSETTINGS 40250
+#define ID_MESSAGELOGSETTINGS_GLOBAL 40251
+#define ID_MESSAGELOGSETTINGS_FORTHISCONTACT 40252
+#define ID_MESSAGELOG_MESSAGELOGSETTINGS 40253
+#define ID_QUEUEMANAGER_MARKSELECTEDFORREMOVAL 40256
+#define ID_QUEUEMANAGER_RESETSELECTED 40257
+#define ID_QUEUEMANAGER_HOLDSELECTED 40258
+#define ID_QUEUEMANAGER_RESUMESELECTED 40259
+#define ID_QUEUEMANAGER_CANCELALLMULTISENDJOBS 40260
+#define ID_QUEUEMANAGER_COPYMESSAGETOCLIPBOARD 40261
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 17
+#define _APS_NEXT_COMMAND_VALUE 40263
+#define _APS_NEXT_CONTROL_VALUE 1453
+#define _APS_NEXT_SYMED_VALUE 40283
+#endif
+#endif
diff --git a/plugins/TabSRMM/include/sendlater.h b/plugins/TabSRMM/include/sendlater.h
new file mode 100644
index 0000000000..b4ce12880f
--- /dev/null
+++ b/plugins/TabSRMM/include/sendlater.h
@@ -0,0 +1,155 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: sendlater.h 11707 2010-05-05 13:53:11Z silvercircle $
+ *
+ * the sendlater class
+ */
+
+#ifndef __SENDLATER_H
+#define __SENDLATER_H
+
+#define TIMERID_SENDLATER 12000
+#define TIMERID_SENDLATER_TICK 13000
+
+#define TIMEOUT_SENDLATER 10000
+#define TIMEOUT_SENDLATER_TICK 200
+
+class CSendLaterJob {
+
+public:
+ /*
+ * job status/error codes
+ */
+ enum {
+ INVALID_CONTACT = 'I',
+ JOB_DEFERRED = 'D',
+ JOB_AGE = 'O',
+ JOB_MYSTATUS = 'M',
+ JOB_STATUS = 'S',
+ JOB_WAITACK = 'A',
+ JOB_REMOVABLE = 'R',
+ JOB_HOLD = 'H',
+ };
+ /*
+ * internal flags
+ */
+ enum {
+ SLF_SUSPEND = 1,
+ SLF_INVALID = 2
+ };
+ void readFlags();
+ void writeFlags();
+ void cleanDB();
+ bool isPersistentJob();
+ bool mustDelete();
+ CSendLaterJob();
+ ~CSendLaterJob();
+ char szId[20]; // database key name (time stamp of original send)
+ HANDLE hContact; // original contact where the message has been assigned
+ HANDLE hTargetContact; // *real* contact (can be different for metacontacts, e.g).
+ HANDLE hProcess; // returned from the protocols sending service. needed to find it in the ACK handler
+ time_t created; // job was created at this time (important to kill jobs, that are too old)
+ time_t lastSent; // time at which the delivery was initiated. used to handle timeouts
+ char *sendBuffer; // utf-8 send buffer
+ PBYTE pBuf; // conventional send buffer (for non-utf8 protocols)
+ DWORD dwFlags;
+ int iSendCount; // # of times we tried to send it...
+ bool fSuccess, fFailed;
+ BYTE bCode; // error/progress code (for the UI)
+};
+
+typedef std::vector<CSendLaterJob *>::iterator SendLaterJobIterator;
+
+class CSendLater {
+
+public:
+ enum {
+ SENDLATER_AGE_THRESHOLD = (86400 * 3), // 3 days, older messages will be removed from the db.
+ SENDLATER_RESEND_THRESHOLD = 180, // timeouted messages should be resent after that many seconds
+ SENDLATER_PROCESS_INTERVAL = 50 // process the list of waiting job every this many seconds
+ };
+
+ CSendLater();
+ ~CSendLater();
+ bool isAvail() const { return(m_fAvail); }
+ bool isInteractive() const { return(m_fIsInteractive); }
+ bool isJobListEmpty() const { return(m_sendLaterJobList.empty() ? true : false); }
+ bool haveErrorPopups() const { return(m_fErrorPopups); }
+ bool haveSuccessPopups() const { return(m_fSuccessPopups); }
+ void startJobListProcess();
+ time_t lastProcessed() const { return(m_last_sendlater_processed); }
+ void setLastProcessed(const time_t _t) { m_last_sendlater_processed = _t; }
+ void flushQueue() { m_last_sendlater_processed = 0; }
+ bool haveJobs() const
+ {
+ if(m_sendLaterJobList.empty() || m_jobIterator == m_sendLaterJobList.end())
+ return(false);
+ else
+ return(true);
+ }
+ bool processCurrentJob();
+ void processContacts();
+ int addJob(const char *szSetting, LPARAM lParam);
+ void addContact(const HANDLE hContact);
+ static int _cdecl addStub(const char *szSetting, LPARAM lParam);
+ HANDLE processAck(const ACKDATA *ack);
+
+ void invokeQueueMgrDlg();
+ void qMgrUpdate(bool fReEnable = false);
+ static INT_PTR svcQMgr(WPARAM wParam, LPARAM lParam);
+
+private:
+ void processSingleContact(const HANDLE hContact);
+ int sendIt(CSendLaterJob *job);
+
+ INT_PTR CALLBACK DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ static INT_PTR CALLBACK DlgProcStub(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ void qMgrFillList(bool fClear = true);
+ void qMgrSetupColumns();
+ void qMgrSaveColumns();
+ LRESULT qMgrAddFilter(const HANDLE hContact, const TCHAR* tszNick);
+
+ std::vector<HANDLE> m_sendLaterContactList;
+ std::vector<CSendLaterJob *> m_sendLaterJobList;
+ bool m_fAvail;
+ bool m_fIsInteractive;
+ bool m_fErrorPopups;
+ bool m_fSuccessPopups;
+ time_t m_last_sendlater_processed;
+ SendLaterJobIterator m_jobIterator;
+
+ HWND m_hwndDlg;
+ HWND m_hwndList, m_hwndFilter;
+ HANDLE m_hFilter; // contact handle to filter the qmgr list (0 = no filter, show all)
+ LRESULT m_sel; // index of the combo box entry corresponding to the contact filter;
+};
+
+extern CSendLater* sendLater;
+
+#endif /* __SENDLATER_H */
diff --git a/plugins/TabSRMM/include/sendqueue.h b/plugins/TabSRMM/include/sendqueue.h
new file mode 100644
index 0000000000..9914e241f8
--- /dev/null
+++ b/plugins/TabSRMM/include/sendqueue.h
@@ -0,0 +1,123 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+$Id: sendqueue.h 12065 2010-06-25 17:30:24Z silvercircle $
+
+*/
+
+#ifndef __SENDQUEUE_H
+#define __SENDQUEUE_H
+
+#define TIMERID_MSGSEND 100
+#define TIMERID_TYPE 3
+#define TIMERID_AWAYMSG 4
+//#define TIMERID_TOOLTIP 5
+#define TIMEOUT_TYPEOFF 10000 // send type off after 10 seconds of inactivity
+#define SB_CHAR_WIDTH 45
+#define SEND_FLAGS PREF_UNICODE
+
+/*
+ * send flags
+ */
+
+#define SENDJOBS_MAX_SENDS 100
+
+struct SendJob {
+ HANDLE hSendId;
+ char *sendBuffer;
+ int dwLen; // actual buffer length (checked for reallocs()
+ int iSendLength; // length of message in utf-8 octets (used to check maxlen)
+ int sendCount;
+ HANDLE hOwner;
+ HWND hwndOwner;
+ unsigned int iStatus;
+ TCHAR szErrorMsg[128];
+ DWORD dwFlags;
+ int iAcksNeeded;
+ HANDLE hEventSplit;
+ int chunkSize;
+ DWORD dwTime;
+};
+
+class SendQueue {
+public:
+ enum {
+ NR_SENDJOBS = 30,
+ SQ_ERROR = 2,
+ SQ_INPROGRESS = 1,
+ SQ_UNDEFINED = 0
+ };
+
+ SendQueue()
+ {
+ ZeroMemory(m_jobs, (sizeof(SendJob) * NR_SENDJOBS));
+ m_currentIndex = 0;
+ }
+
+ void inc() { m_currentIndex++; }
+ void dec() { m_currentIndex--; }
+
+ ~SendQueue()
+ {
+ for(int i = 0; i < NR_SENDJOBS; i++) {
+ if(m_jobs[i].sendBuffer)
+ free(m_jobs[i].sendBuffer);
+ }
+ }
+
+ SendJob *getJobByIndex(const int index) { return(&m_jobs[index]); }
+
+ void clearJob (const int index);
+ int findNextFailed (const TWindowData *dat) const;
+ void handleError (TWindowData *dat, const int iEntry) const;
+ int addTo (TWindowData *dat, const int iLen, int dwFlags);
+ int sendQueued (TWindowData *dat, const int iEntry);
+ int getSendLength (const int iEntry, const int sendMode);
+ void checkQueue (const TWindowData *dat) const;
+ void logError (const TWindowData *dat, int iSendJobIndex,
+ const TCHAR *szErrMsg) const;
+ void recallFailed (const TWindowData *dat, int iEntry) const;
+ void showErrorControls (TWindowData *dat, const int showCmd) const;
+ int ackMessage (TWindowData *dat, WPARAM wParam, LPARAM lParam);
+ int doSendLater (int iIndex, TWindowData *dat, HANDLE hContact = 0, bool fIsSendLater = true);
+ /*
+ * static members
+ */
+ static int TSAPI RTL_Detect (const wchar_t *pszwText);
+ static char* TSAPI MsgServiceName (const HANDLE hContact, const TWindowData *dat, int isUnicode);
+ static int TSAPI GetProtoIconFromList (const char *szProto, int iStatus);
+ static LRESULT TSAPI WarnPendingJobs (unsigned int uNrMessages);
+ static void TSAPI NotifyDeliveryFailure (const TWindowData *dat);
+ static void TSAPI UpdateSaveAndSendButton (TWindowData *dat);
+ static void TSAPI EnableSending (const TWindowData *dat, const int iMode);
+private:
+ SendJob m_jobs[NR_SENDJOBS];
+ int m_currentIndex;
+};
+
+extern SendQueue *sendQueue;
+
+int TSAPI ActivateExistingTab (TContainerData *pContainer, HWND hwndChild);
+void TSAPI ShowMultipleControls (const HWND hwndDlg, const UINT * controls, int cControls, int state);
+void TSAPI HandleIconFeedback (TWindowData *dat, HICON iIcon);
+
+#endif /* __SENDQUEUE_H */
diff --git a/plugins/TabSRMM/include/sidebar.h b/plugins/TabSRMM/include/sidebar.h
new file mode 100644
index 0000000000..4cc60be747
--- /dev/null
+++ b/plugins/TabSRMM/include/sidebar.h
@@ -0,0 +1,239 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: sidebar.h 11744 2010-05-13 20:34:30Z silvercircle $
+ *
+ * the contact switch bar on the left (or right) side
+ *
+ */
+
+#ifndef __SIDEBAR_H
+#define __SIDEBAR_H
+
+struct TSideBarNotify {
+ NMHDR nmHdr;
+ const TWindowData* dat;
+};
+/* layout descrtiption structure */
+
+struct TSideBarLayout {
+ TCHAR szName[50]; // everything wants a name...
+ LONG width; // width of the switchbar element (a single button)
+ LONG height; // height of a single switchbar element
+ DWORD dwFlags; // flags, obviously :)
+
+ /*
+ * the following 4 items define pointers to the actual renderer functions for that sidebar layout
+ * a default is always provided, however, it has been designed to be easily extendible without
+ * rewriting lots of code just in order to change how the switchbar items look like.
+ */
+ void (__fastcall *pfnContentRenderer)(const HDC hdc, const RECT *rc, const CSideBarButton *item);
+ void (__fastcall *pfnBackgroundRenderer)(const HDC hdc, const RECT *rc, const CSideBarButton *item);
+ const SIZE& (__fastcall *pfnMeasureItem)(CSideBarButton *item);
+ void (__fastcall *pfnLayout)(const CSideBar *sideBar, RECT *rc);
+ UINT uId; // numeric id by which the layout is identified. basically, the index into the array.
+};
+
+class CSideBar;
+
+class CSideBarButton
+{
+public:
+ CSideBarButton(const UINT id, CSideBar *sideBar);
+ CSideBarButton(const TWindowData *dat, CSideBar *sideBar);
+ ~CSideBarButton();
+
+ LONG getHeight() const { return(m_sz.cy); }
+ const SIZE& getSize() const { return(m_sz); }
+ void setSize(const SIZE& newSize){ m_sz = newSize; }
+ const bool isTopAligned() const { return(m_isTopAligned); }
+ const HWND getHwnd() const { return(m_hwnd); }
+ const UINT getID() const { return(m_id); }
+ const HANDLE getContactHandle() const { return(m_dat->hContact); }
+ const TWindowData* getDat() const { return(m_dat); }
+ const TSideBarLayout* getLayout() const { return(m_sideBarLayout); }
+
+ void RenderThis (const HDC hdc) const;
+ void renderIconAndNick (const HDC hdc, const RECT *rcItem) const;
+ int testCloseButton() const;
+ void Show(const int showCmd) const;
+ void activateSession() const;
+ const SIZE& measureItem();
+ void setLayout(const TSideBarLayout *newLayout);
+ void invokeContextMenu();
+
+public:
+ CSideBar* m_sideBar;
+ const MButtonCtrl* m_buttonControl; // private data struct of the Win32 button object
+private:
+ void _create();
+private:
+ const TSideBarLayout* m_sideBarLayout;
+ HWND m_hwnd; // window handle for the TSButton object
+ const TWindowData* m_dat; // session data
+ UINT m_id; // control id
+ bool m_isTopAligned;
+ SIZE m_sz;
+};
+
+typedef std::vector<CSideBarButton *>::iterator ButtonIterator;
+
+class CSideBar
+{
+public:
+ enum {
+ NR_LAYOUTS = 4
+ };
+
+ enum {
+ /* layout ids. index into m_layouts[] */
+
+ SIDEBARLAYOUT_VERTICAL = 0,
+ SIDEBARLAYOUT_NORMAL = 1,
+ SIDEBARLAYOUT_COMPLEX = 2,
+ SIDEBARLAYOUT_LARGE = 3,
+
+ /* flags */
+
+ SIDEBARORIENTATION_LEFT = 8,
+ SIDEBARORIENTATION_RIGHT = 16,
+
+ SIDEBARLAYOUT_DYNHEIGHT = 32,
+ SIDEBARLAYOUT_VERTICALORIENTATION = 64,
+ SIDEBARLAYOUT_NOCLOSEBUTTONS = 128
+ };
+
+ enum {
+ SIDEBAR_GAP = 2 // gap between sidebar container window and content tab sheet border
+ };
+
+ CSideBar(TContainerData *pContainer);
+ ~CSideBar();
+
+ void Init (const bool fForce = false);
+ void addSession (const TWindowData *dat, int position = -1);
+ HRESULT removeSession (const TWindowData *dat);
+ void updateSession (const TWindowData *dat);
+
+ void processScrollerButtons (UINT cmd);
+ void Layout (const RECT *rc = 0, bool fOnlyCalc = false);
+ void setVisible (bool fNewVisibility);
+ void showAll (int showCmd);
+
+ const LONG getWidth() const { return(m_isVisible ? m_width + SIDEBAR_GAP : 0); }
+ const DWORD getFlags() const { return(m_dwFlags); }
+ const TContainerData* getContainer() const { return(m_pContainer); }
+ const bool isActive() const { return(m_isActive); }
+ const bool isVisible() const { return(m_isVisible); }
+ const CSideBarButton* getActiveItem() const { return(m_activeItem); }
+ const CSideBarButton* getScrollUp() const { return(m_up); }
+ const CSideBarButton* getScrollDown() const { return(m_down); }
+ bool isSkinnedContainer() const { return(CSkin::m_skinEnabled ? true : false); }
+ const UINT getLayoutId() const { return(m_uLayout); }
+ void invalidateButton (const TWindowData* dat);
+
+ const CSideBarButton* setActiveItem (const CSideBarButton *newItem)
+ {
+ CSideBarButton *oldItem = m_activeItem;
+ m_activeItem = const_cast<CSideBarButton *>(newItem);
+ if(oldItem)
+ ::InvalidateRect(oldItem->getHwnd(), NULL, FALSE);
+ ::InvalidateRect(m_activeItem->getHwnd(), NULL, FALSE);
+ scrollIntoView(m_activeItem);
+ return(oldItem);
+ }
+ /**
+ * this item has its close button currently hovered
+ * @param item: the CSideBarButton* which is hovered
+ */
+ void setHoveredClose (CSideBarButton* item)
+ {
+ m_hoveredClose = item;
+ }
+ HWND getScrollWnd() const { return(m_hwndScrollWnd); }
+ const CSideBarButton* getHoveredClose() const { return(m_hoveredClose); }
+ const CSideBarButton* setActiveItem (const TWindowData *dat);
+
+ static const TSideBarLayout* getLayouts (int& uLayoutCount)
+ {
+ uLayoutCount = NR_LAYOUTS;
+ return(m_layouts);
+ }
+ void scrollIntoView (const CSideBarButton *item = 0);
+ void resizeScrollWnd (LONG x, LONG y, LONG width, LONG height) const;
+ static LRESULT CALLBACK wndProcStub (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+private:
+ void createScroller();
+ void destroyScroller();
+ void populateAll();
+ void removeAll();
+ void Invalidate();
+ ButtonIterator findSession (const TWindowData *dat);
+ ButtonIterator findSession (const HANDLE hContact);
+
+ LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+private:
+ HWND m_hwndScrollWnd;
+ std::vector<CSideBarButton*> m_buttonlist; // our list of buttons
+ TContainerData* m_pContainer; // our master and commander...
+ LONG m_width; // required width of the bar (m_elementWidth + padding)
+ DWORD m_dwFlags;
+ CSideBarButton* m_up, *m_down; // the scroller buttons (up down)
+ CSideBarButton* m_activeItem; // active button item (for highlighting)
+ const CSideBarButton* m_hoveredClose; // item which must display an active close button
+ LONG m_topHeight, m_bottomHeight;
+ LONG m_firstVisibleOffset, m_totalItemHeight;
+ int m_iTopButtons, m_iBottomButtons;
+ LONG m_elementHeight, m_elementWidth; // width / height for a single element.
+ // can be dynamic (see measeureItem() in CSideBarButtonItem
+ bool m_isActive; // the sidebar is active (false, if it does _nothing at all_
+ bool m_isVisible; // visible aswell (not collapsed)
+ TSideBarLayout* m_currentLayout; // the layout in use. will be passed to new button items
+ UINT m_uLayout; // layout id number, currently in use
+
+private:
+ /*
+ * layouts. m_layouts[] is static and contains layout descriptions
+ * renderer functions are static aswell
+ */
+ static TSideBarLayout m_layouts[NR_LAYOUTS];
+ static void __fastcall m_DefaultBackgroundRenderer(const HDC hdc, const RECT *rc, const CSideBarButton *item);
+ static void __fastcall m_DefaultContentRenderer(const HDC hdc, const RECT *rc, const CSideBarButton *item);
+ static void __fastcall m_AdvancedContentRenderer(const HDC hdc, const RECT *rc, const CSideBarButton *item);
+
+ static const SIZE& __fastcall m_measureAdvancedVertical(CSideBarButton *item);
+};
+
+inline void CSideBarButton::setLayout(const TSideBarLayout *newLayout)
+{
+ m_sideBarLayout = newLayout;
+}
+
+#endif
diff --git a/plugins/TabSRMM/include/taskbar.h b/plugins/TabSRMM/include/taskbar.h
new file mode 100644
index 0000000000..1b1725d48f
--- /dev/null
+++ b/plugins/TabSRMM/include/taskbar.h
@@ -0,0 +1,197 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: taskbar.h 12227 2010-07-23 16:57:25Z silvercircle $
+ *
+ * - Windows 7 taskbar integration class
+ * - Proxy window class, needed to support custom aero peek tab
+ * thumbnails
+ * - Thumbnail classes to provide task bar thumbnails for Aero peek
+ * preview.
+ */
+
+#ifndef __TASKBAR_H
+#define __TASKBAR_H
+
+#define PROXYCLASSNAME _T("TabSRMM_DWMProxy")
+extern HINSTANCE g_hInst;
+
+class CProxyWindow;
+
+class CThumbBase {
+public:
+ CThumbBase (const CProxyWindow* pWnd);
+ virtual ~CThumbBase ();
+
+ const HBITMAP getHBM () const { return(m_hbmThumb); }
+ const bool isValid () const { return(m_isValid); }
+ virtual void setValid (const bool fNewValid) { m_isValid = fNewValid; }
+ virtual void update () = 0;
+
+protected:
+ HBITMAP m_hbmThumb, m_hbmOld;
+ const TWindowData* m_dat;
+ LONG m_width, m_height;
+ HDC m_hdc;
+ const CProxyWindow* m_pWnd;
+ RECT m_rc, m_rcTop, m_rcBottom, m_rcIcon;
+ DWORD m_dtFlags;
+ SIZE m_sz;
+ LONG m_cx, m_cy;
+ HFONT m_hOldFont;
+
+ virtual void renderBase ();
+
+private:
+ virtual void renderContent () = 0;
+ void setupRect ();
+
+private:
+ bool m_isValid;
+};
+
+class CThumbIM : public CThumbBase {
+
+public:
+ CThumbIM (const CProxyWindow* pWnd);
+ virtual ~CThumbIM () {};
+ void update ();
+
+private:
+ void renderContent ();
+};
+
+class CThumbMUC : public CThumbBase {
+
+public:
+ CThumbMUC (const CProxyWindow* pWnd);
+ virtual ~CThumbMUC () {};
+ void update ();
+
+private:
+ void renderContent ();
+};
+
+class CProxyWindow
+{
+public:
+ CProxyWindow(const TWindowData *dat);
+ ~CProxyWindow();
+
+ void updateIcon (const HICON hIcon) const;
+ void updateTitle (const TCHAR *tszTitle) const;
+ void setBigIcon (const HICON hIcon, bool fInvalidate = true);
+ void setOverlayIcon (const HICON hIcon, bool fInvalidate = true);
+ void activateTab () const;
+ void Invalidate () const;
+ const TWindowData* getDat () const { return(m_dat); }
+ const LONG getWidth () const { return(m_width); }
+ const LONG getHeight () const { return(m_height); }
+ const HWND getHwnd () const { return(m_hwndProxy); }
+ const HICON getBigIcon () const { return(m_hBigIcon); }
+ const HICON getOverlayIcon () const { return(m_hOverlayIcon); }
+ void verifyDwmState ();
+
+ static LRESULT CALLBACK stubWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ static void add (TWindowData *dat);
+ static void verify (TWindowData *dat);
+
+private:
+ const TWindowData* m_dat;
+ HWND m_hwndProxy;
+ LONG m_width, m_height;
+ HICON m_hBigIcon, m_hOverlayIcon;
+
+ LRESULT CALLBACK wndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ void sendThumb (LONG width, LONG height);
+ void sendPreview ();
+ CThumbBase* m_thumb;
+};
+
+class CTaskbarInteract
+{
+public:
+ CTaskbarInteract()
+ {
+ m_pTaskbarInterface = 0;
+ m_IconSize = 0;
+ m_isEnabled = IsWinVer7Plus() ? true : false;
+
+ if(m_isEnabled) {
+ ::CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_ALL, IID_ITaskbarList3, (void**)&m_pTaskbarInterface);
+ updateMetrics();
+ if(0 == m_pTaskbarInterface)
+ m_isEnabled = false;
+ }
+
+ /*
+ * register proxy window class
+ */
+ WNDCLASSEX wcex = {0};
+ wcex.cbSize = sizeof(wcex);
+ wcex.lpfnWndProc = CProxyWindow::stubWndProc;
+ wcex.hInstance = g_hInst;
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wcex.lpszClassName = PROXYCLASSNAME;
+ ::RegisterClassEx(&wcex);
+ }
+
+ ~CTaskbarInteract()
+ {
+ if(m_isEnabled && m_pTaskbarInterface) {
+ m_pTaskbarInterface->Release();
+ m_pTaskbarInterface = 0;
+ m_isEnabled = false;
+ }
+ ::UnregisterClass(PROXYCLASSNAME, g_hInst);
+ }
+ const LONG getIconSize () const { return(m_IconSize); }
+ const bool haveAlwaysGroupingMode () const { return(m_fHaveAlwaysGrouping); }
+
+ bool setOverlayIcon (HWND hwndDlg, LPARAM lParam) const;
+ void clearOverlayIcon (HWND hwndDlg) const;
+ bool haveLargeIcons ();
+ LONG updateMetrics ();
+ void registerTab (const HWND hwndTab, const HWND hwndContainer) const;
+ void unRegisterTab (const HWND hwndTab) const;
+ void SetTabActive (const HWND hwndTab, const HWND hwndGroup) const;
+
+ //const TCHAR* getFileNameFromWindow (const HWND hWnd);
+private:
+ bool m_isEnabled;
+ ITaskbarList3* m_pTaskbarInterface;
+ bool m_fHaveLargeicons;
+ bool m_fHaveAlwaysGrouping;
+ LONG m_IconSize;
+};
+
+extern CTaskbarInteract* Win7Taskbar;
+
+#endif /* __TASKBAR_H */
+
diff --git a/plugins/TabSRMM/include/templates.h b/plugins/TabSRMM/include/templates.h
new file mode 100644
index 0000000000..f347a68102
--- /dev/null
+++ b/plugins/TabSRMM/include/templates.h
@@ -0,0 +1,50 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+$Id: templates.h 11044 2009-12-11 09:16:30Z silvercircle $
+
+templates for the message log...
+
+*/
+
+struct TemplateEditorInfo {
+ BOOL rtl;
+ BOOL changed; // template in edit field is changed
+ BOOL selchanging;
+ int inEdit; // template currently in editor
+ BOOL updateInfo[TMPL_ERRMSG + 1]; // item states...
+ HWND hwndParent;
+ HANDLE hContact;
+};
+
+struct TemplateEditorNew {
+ HANDLE hContact;
+ BOOL rtl;
+ HWND hwndParent;
+};
+
+BOOL CALLBACK DlgProcTemplateEdit(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static void LoadTemplatesFrom(TTemplateSet *tSet, HANDLE hContact, int rtl);
+void LoadDefaultTemplates();
+
+#define DM_UPDATETEMPLATEPREVIEW (WM_USER + 50)
+
diff --git a/plugins/TabSRMM/include/themes.h b/plugins/TabSRMM/include/themes.h
new file mode 100644
index 0000000000..d1cc15d53c
--- /dev/null
+++ b/plugins/TabSRMM/include/themes.h
@@ -0,0 +1,409 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: themes.h 11997 2010-06-14 20:12:34Z silvercircle $
+ *
+ * The class CSkin implements the skinning engine and loads skins from
+ * their skin definition files (.tsk).
+ *
+ * CImageItem implements a single rectangular skin item with an image
+ * and its rendering.
+ *
+ */
+
+#ifndef __THEMES_H
+#define __THEMES_H
+
+HBITMAP IMG_LoadLogo(const TCHAR *szName);
+
+class CSideBarButton;
+
+typedef struct {
+ HWND hwnd;
+ int stateId; // button state
+ int focus; // has focus (1 or 0)
+ HFONT hFont; // font
+ HICON arrow; // uses down arrow
+ int defbutton; // default button
+ HICON hIcon, hIconPrivate;
+ HBITMAP hBitmap;
+ int pushBtn;
+ int pbState;
+ HANDLE hThemeButton;
+ HANDLE hThemeToolbar;
+ BOOL bThemed;
+ BOOL bToolbarButton; // is a toolbar button (important for aero background rendering)
+ BOOL bTitleButton;
+ TCHAR cHot;
+ int flatBtn;
+ int dimmed;
+ HICON overlay;
+ struct TContainerData *pContainer;
+ CSideBarButton *sitem;
+} MButtonCtrl;
+
+#define BUTTONSETASTOOLBARBUTTON (BUTTONSETASFLATBTN + 21)
+#define BUTTONSETASSIDEBARBUTTON (BUTTONSETASFLATBTN + 22)
+#define BUTTONSETOVERLAYICON (BUTTONSETASFLATBTN + 23)
+
+struct AeroEffect {
+ TCHAR tszName[40];
+ DWORD m_baseColor;
+ DWORD m_gradientColor;
+ BYTE m_baseAlpha;
+ BYTE m_finalAlpha;
+ BYTE m_cornerType;
+ BYTE m_gradientType;
+ DWORD m_cornerRadius;
+ DWORD m_glowSize;
+ COLORREF m_clrBack;
+ COLORREF m_clrToolbar;
+ COLORREF m_clrToolbar2;
+ void (TSAPI *pfnEffectRenderer)(const HDC hdc, const RECT *rc, int iEffectArea);
+};
+/**
+ * CImageItem implementes image-based skin items. These items are loaded
+ * from a skin file definition (.tsk file) and are then linked to one or
+ * more skin items.
+ */
+class CImageItem
+{
+public:
+ CImageItem()
+ {
+ ZeroMemory(this, sizeof(CImageItem));
+ }
+ CImageItem(const CImageItem& From)
+ {
+ *this = From;
+ m_nextItem = 0;
+ }
+ CImageItem(const TCHAR *szName)
+ {
+ ZeroMemory(this, sizeof(CImageItem));
+ _sntprintf(m_szName, 40, szName);
+ m_szName[39] = 0;
+ }
+
+ CImageItem(BYTE bottom, BYTE left, BYTE top, BYTE right, HDC hdc, HBITMAP hbm, DWORD dwFlags,
+ HBRUSH brush, BYTE alpha, LONG inner_height, LONG inner_width, LONG height, LONG width)
+ {
+ m_bBottom = bottom;
+ m_bLeft = left,
+ m_bTop = top;
+ m_bRight = right;
+ m_hdc = hdc;
+ m_hbm = hbm;
+ m_dwFlags = dwFlags;
+ m_fillBrush = brush;
+ m_inner_height = inner_height;
+ m_inner_width = inner_width;
+ m_height = height;
+ m_width = width;
+
+ m_bf.SourceConstantAlpha = alpha;
+ m_bf.AlphaFormat = 0;
+ m_bf.BlendOp = AC_SRC_OVER;
+ m_bf.BlendFlags = 0;
+ }
+ ~CImageItem()
+ {
+ Free();
+ }
+
+ void Clear()
+ {
+ m_hdc = 0; m_hbm = 0; m_hbmOld = 0;
+ m_fillBrush = (HBRUSH)0;
+ }
+
+ void setBitmap(const HBITMAP hbm)
+ {
+ m_hbm = hbm;
+ }
+
+ void setAlphaFormat(const BYTE bFormat, const BYTE bConstantAlpha)
+ {
+ m_bf.AlphaFormat = bFormat;
+ m_bf.SourceConstantAlpha = bConstantAlpha;
+ }
+
+ void setMetrics(const LONG width, const LONG height)
+ {
+ m_height = height;
+ m_width = width;
+
+ m_inner_height = m_height - m_bBottom - m_bTop;
+ m_inner_width = m_width - m_bLeft - m_bRight;
+ if(!(m_dwFlags & IMAGE_FLAG_DIVIDED))
+ m_bStretch = IMAGE_STRETCH_B;
+ }
+
+ void Free();
+ CImageItem* getNextItem() const { return(m_nextItem); }
+ void setNextItem(CImageItem *item) { m_nextItem = item; }
+ HBITMAP getHbm() const { return(m_hbm); }
+ DWORD getFlags() const { return(m_dwFlags); }
+ HDC getDC() const { return(m_hdc); }
+ const BLENDFUNCTION& getBF() const
+ {
+ const BLENDFUNCTION &bf = m_bf;
+ return(bf);
+ }
+ const TCHAR* getName() const { return (m_szName); }
+ TCHAR* Read(const TCHAR *szFilename);
+ void Create(const TCHAR *szImageFile);
+ void __fastcall Render(const HDC hdc, const RECT *rc, bool fIgnoreGlyph) const;
+ static void TSAPI PreMultiply(HBITMAP hBitmap, int mode);
+ static void TSAPI SetBitmap32Alpha(HBITMAP hBitmap, BYTE bAlpha = 255);
+ static void TSAPI Colorize(HBITMAP hBitmap, BYTE dr, BYTE dg, BYTE db, BYTE alpha = 0);
+ static HBITMAP TSAPI LoadPNG(const TCHAR *szFilename);
+
+public:
+ bool m_fValid; // verified item, indicates that all parameters are valid
+private:
+ TCHAR m_szName[40]; // everything wants a name, an image item doesn't need one though
+ HBITMAP m_hbm; // the bitmap handle
+ BYTE m_bLeft, m_bRight, m_bTop, m_bBottom; // sizing margins for the outer 8 image parts
+ BYTE m_alpha; // constant alpha for the entire image, applied via m_bf. sums with perpixel alpha
+ DWORD m_dwFlags; // flags
+ HDC m_hdc; // *can* hold a pre-created hdc to speed up rendering
+ HBITMAP m_hbmOld; // old bitmap, needs to be selected into m_hdc before destroying it
+ LONG m_inner_height, m_inner_width; // dimensions of the inner image part
+ LONG m_width, m_height; // width and height of the image, in pixels
+ BLENDFUNCTION m_bf; // for AlphaBlend()
+ BYTE m_bStretch; // stretch mode (unused in tabSRMM
+ HBRUSH m_fillBrush; // brush to fill the inner part (faster) dwFlags & IMAGE_FILLSOLID must be set
+ LONG m_glyphMetrics[4]; // these coordinates point into the glyph image (if IMAGE_GLYPH is set)
+ CImageItem* m_nextItem; // next item in a set of image items (usually the skin set)
+};
+
+/**
+ * Implements the skinning engine. There is only one instance of this class and
+ * it always holds the currently loaded skin (if any).
+ */
+class CSkin
+{
+public:
+ enum {
+ AERO_EFFECT_NONE = 0,
+ AERO_EFFECT_MILK = 1,
+ AERO_EFFECT_CARBON = 2,
+ AERO_EFFECT_SOLID = 3,
+ AERO_EFFECT_WHITE = 4,
+ AERO_EFFECT_CUSTOM = 5,
+ AERO_EFFECT_LAST = 6
+ };
+ enum {
+ AERO_EFFECT_AREA_MENUBAR = 0,
+ AERO_EFFECT_AREA_STATUSBAR = 1,
+ AERO_EFFECT_AREA_INFOPANEL = 2,
+ AERO_EFFECT_AREA_TAB_ACTIVE = 3,
+ AERO_EFFECT_AREA_TAB_HOVER = 4,
+ AERO_EFFECT_AREA_TAB_NORMAL = 5,
+ AERO_EFFECT_AREA_SIDEBAR_LEFT = 6,
+ AERO_EFFECT_AREA_SIDEBAR_RIGHT = 7,
+ AERO_EFFECT_AREA_TAB_TOP = 0x1000,
+ AERO_EFFECT_AREA_TAB_BOTTOM = 0x2000
+ };
+
+ enum {
+ DEFAULT_GLOW_SIZE = 10
+ };
+
+ /*
+ * avatar border types (skinned mode only)
+ */
+ enum {
+ AVBORDER_NONE = 0,
+ AVBORDER_NORMAL = 1,
+ AVBORDER_ROUNDED = 2
+ };
+
+ CSkin()
+ {
+ m_default_bf.SourceConstantAlpha = 255;
+ m_default_bf.AlphaFormat = AC_SRC_ALPHA;
+ m_default_bf.BlendOp = AC_SRC_OVER;
+ }
+
+ ~CSkin()
+ {
+ Unload();
+ }
+
+ void Init(bool fStartup = false);
+ void Load();
+ void Unload();
+ void UnloadAeroTabs();
+ void setFileName();
+ void ReadItem(const int id, const TCHAR *section);
+ void LoadItems();
+ void LoadIcon(const TCHAR *szSection, const TCHAR *name, HICON *hIcon);
+ void ReadImageItem(const TCHAR *szItemName);
+ void ReadButtonItem(const TCHAR *itemName) const;
+ bool haveGlyphItem() const { return(m_fHaveGlyph); }
+ int getNrIcons() const { return(m_nrSkinIcons); }
+ const DWORD getDwmColor() const { return(m_dwmColor); }
+
+ const TIconDescW* getIconDesc(const int id) const { return(&m_skinIcons[id]); }
+ /**
+ * get the glyph image item (a single PNG image, containing a number of textures
+ * for the skin.
+ *
+ * @return CImageItem&: reference to the glyph item. Cannot be
+ * modified.
+ *
+ */
+ const CImageItem* getGlyphItem() const
+ {
+ return(m_fHaveGlyph ? &m_glyphItem : 0);
+ }
+ bool warnToClose() const;
+ COLORREF getColorKey() const { return(m_ContainerColorKey); }
+
+ void setupAeroSkins();
+ void extractSkinsAndLogo(bool fForceOverwrite = false) const;
+ void setupTabCloseBitmap(bool fDeleteOnly = false);
+
+ /*
+ * static member functions
+ */
+ static void TSAPI SkinDrawBGFromDC(HWND hwndClient, HWND hwnd, RECT *rcClient, HDC hdcTarget);
+ static void TSAPI SkinDrawBG(HWND hwndClient, HWND hwnd, struct TContainerData *pContainer, RECT *rcClient, HDC hdcTarget);
+ static void TSAPI MY_AlphaBlend(HDC hdcDraw, DWORD left, DWORD top, int width, int height, int bmWidth, int bmHeight, HDC hdcMem);
+ static void TSAPI DrawDimmedIcon(HDC hdc, LONG left, LONG top, LONG dx, LONG dy, HICON hIcon, BYTE alpha);
+ static DWORD __fastcall HexStringToLong(const TCHAR *szSource);
+ static UINT TSAPI DrawRichEditFrame(HWND hwnd, const TWindowData *mwdat, UINT skinID, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC OldWndProc);
+ static UINT TSAPI NcCalcRichEditFrame(HWND hwnd, const TWindowData *mwdat, UINT skinID, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC OldWndProc);
+ static HBITMAP TSAPI CreateAeroCompatibleBitmap(const RECT &rc, HDC dc);
+ static int TSAPI RenderText(HDC hdc, HANDLE hTheme, const TCHAR *szText, RECT *rc, DWORD dtFlags, const int iGlowSize = DEFAULT_GLOW_SIZE, COLORREF clr = 0, bool fForceAero = false);
+ static void TSAPI MapClientToParent(HWND hwndClient, HWND hwndParent, RECT &rc);
+ static void TSAPI RenderToolbarBG(const TWindowData *dat, HDC hdc, const RECT &rcWindow);
+ static HBITMAP TSAPI ResizeBitmap(HBITMAP hBmpSrc, LONG width, LONG height, bool &mustFree);
+ static void TSAPI ApplyAeroEffect(const HDC hdc, const RECT* rc, int iEffectArea, HANDLE hbp = 0);
+ static void TSAPI setAeroEffect(const LRESULT effect);
+ static void TSAPI initAeroEffect();
+ static HANDLE TSAPI InitiateBufferedPaint(const HDC hdcSrc, RECT& rc, HDC& hdcOut);
+ static void TSAPI FinalizeBufferedPaint(HANDLE hbp, RECT *rc);
+ static bool __fastcall DrawItem(const HDC hdc, const RECT *rc, const CSkinItem *item);
+ static void TSAPI UpdateToolbarBG(TWindowData* dat, DWORD dwRdwOptFlags = 0);
+ static void TSAPI FillBack(const HDC hdc, RECT* rc);
+
+public:
+ static bool m_DisableScrollbars, m_bClipBorder;
+ static char m_SkinnedFrame_left, m_SkinnedFrame_right, m_SkinnedFrame_bottom, m_SkinnedFrame_caption;
+ static char m_realSkinnedFrame_left, m_realSkinnedFrame_right, m_realSkinnedFrame_bottom, m_realSkinnedFrame_caption;
+ static HPEN m_SkinLightShadowPen, m_SkinDarkShadowPen;
+ static int m_titleBarLeftOff, m_titleButtonTopOff, m_captionOffset, m_captionPadding,
+ m_titleBarRightOff, m_sidebarTopOffset, m_sidebarBottomOffset, m_bRoundedCorner;
+ static SIZE m_titleBarButtonSize;
+ static int m_bAvatarBorderType;
+ static COLORREF m_avatarBorderClr, m_tmp_tb_low, m_tmp_tb_high;
+ static COLORREF m_sideBarContainerBG;
+ static COLORREF m_ContainerColorKey, m_DefaultFontColor;
+ static HBRUSH m_ContainerColorKeyBrush, m_MenuBGBrush;
+ static bool m_skinEnabled;
+ static bool m_frameSkins;
+ static HICON m_closeIcon, m_minIcon, m_maxIcon;
+ static BLENDFUNCTION m_default_bf; // general purpose bf, dynamically modified when needed
+
+ /*
+ * cached bitmap for tab close button
+ */
+
+ static HBITMAP m_tabCloseBitmap, m_tabCloseOldBitmap;
+ static HDC m_tabCloseHDC;
+
+ /*
+ * controls the aero effect. Set by initAeroEffect()
+ */
+
+ static UINT m_aeroEffect; // effect id, initAeroEffect() is using it to set
+ // the parameters below.
+ static AeroEffect m_aeroEffects[AERO_EFFECT_LAST];
+ static AeroEffect m_currentAeroEffect;
+ static AeroEffect* m_pCurrentAeroEffect;
+ static DWORD m_glowSize;
+ static HBRUSH m_BrushBack, m_BrushFill;
+
+ static COLORREF m_dwmColorRGB;
+
+ static CImageItem *m_switchBarItem, *m_tabTop, *m_tabBottom, *m_tabGlowTop, *m_tabGlowBottom;
+ static bool m_fAeroSkinsValid;
+
+private:
+ TCHAR m_tszFileName[MAX_PATH]; // full path and filename of the currently loaded skin
+ CSkinItem* m_SkinItems;
+ CImageItem* m_ImageItems; // the list of image item objects
+ CImageItem m_glyphItem;
+
+ bool m_fLoadOnStartup; // load the skin on plugin initialization.
+ bool m_fHaveGlyph;
+ void SkinCalcFrameWidth();
+ TIconDescW *m_skinIcons;
+ int m_nrSkinIcons;
+ DWORD m_dwmColor;
+
+private:
+ static void TSAPI AeroEffectCallback_Milk(const HDC hdc, const RECT *rc, int iEffectArea);
+ static void TSAPI AeroEffectCallback_Carbon(const HDC hdc, const RECT *rc, int iEffectArea);
+ static void TSAPI AeroEffectCallback_Solid(const HDC hdc, const RECT *rc, int iEffectArea);
+};
+
+/*
+ * window data for the tab control window class
+ */
+
+struct TabControlData {
+ BOOL m_VisualStyles;
+ HWND hwnd;
+ DWORD dwStyle;
+ DWORD cx, cy;
+ HANDLE hTheme, hThemeButton, hbp;
+ BYTE m_xpad;
+ TContainerData *pContainer;
+ BOOL bDragging;
+ int iBeginIndex;
+ int iHoveredCloseIcon;
+ HWND hwndDrag;
+ TWindowData *dragDat;
+ HIMAGELIST himlDrag;
+ BOOL bRefreshWithoutClip;
+ BOOL fSavePos;
+ BOOL fTipActive;
+ BOOL fAeroTabs;
+ BOOL fCloseButton;
+ TWindowData* helperDat; // points to the client data of the active tab
+ CImageItem* helperItem, *helperGlowItem; // aero ui, holding the skin image for the tabs
+};
+
+extern CSkin *Skin;
+
+#endif /* __THEMES_H */
+
diff --git a/plugins/TabSRMM/include/translator.h b/plugins/TabSRMM/include/translator.h
new file mode 100644
index 0000000000..e248a319f8
--- /dev/null
+++ b/plugins/TabSRMM/include/translator.h
@@ -0,0 +1,513 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: translator.h 12299 2010-08-10 02:39:36Z silvercircle $
+ *
+ * string handling
+ *
+ */
+
+#ifndef __STRINGS_H
+#define __STRINGS_H
+
+class CTranslator {
+
+public:
+
+ enum {
+ NR_WEEKDAYS = 7,
+ NR_MONTHS = 12
+ };
+
+ enum {
+ CNT_MENU_STAYONTOP = 0,
+ CNT_MENU_HIDETITLEBAR = 1,
+ CNT_MENU_CONTAINEROPTIONS = 2,
+ CNT_TITLE_DEFAULT = 3,
+ CNT_ATTACH_TO = 4,
+ GEN_META_CONTACT = 5,
+ GEN_META_FORCED = 6,
+ GEN_META_AUTOSELECT = 7,
+ GEN_META_USEPROTO = 8,
+ GEN_META_SETDEFAULT = 9,
+ GEN_MUC_NICKNAME = 10,
+ GEN_MUC_UID = 11,
+ GEN_MUC_STATUS = 12,
+ GEN_MUC_ROOM_TITLE_USER = 13,
+ GEN_MUC_ROOM_TITLE_USERS = 14,
+ GEN_MUC_ROOM_TITLE_FILTER = 15,
+ GEN_MUC_PRIVSESSION = 16,
+ GEN_MUC_PRIVSESSION_MULTI = 17,
+ GEN_MUC_FILTER_ERROR = 18,
+ GEN_MUC_FILTER_ERROR_TITLE = 19,
+ GEN_MUC_TEXTCOLOR = 20,
+ GEN_MUC_BGCOLOR = 21,
+ CNT_OPT_TITLE = 22,
+ CNT_OPT_TABSTOP = 23,
+ CNT_OPT_TABSBOTTOM = 24,
+ CNT_OPT_TABSLEFT = 25,
+ CNT_OPT_TABSRIGHT = 26,
+ CNT_OPT_HEADERBAR = 27,
+ GEN_MENUBAR_FILE = 28,
+ GEN_MENUBAR_VIEW = 29,
+ GEN_MENUBAR_USER = 30,
+ GEN_MENUBAR_ROOM = 31,
+ GEN_MENUBAR_LOG = 32,
+ GEN_MENUBAR_CONTAINER = 33,
+ GEN_MENUBAR_HELP = 34,
+ CNT_SBAR_SOUNDS = 35,
+ GEN_ENABLED = 36,
+ GEN_DISABLED = 37,
+ CNT_SBAR_MTN = 38,
+ GEN_IP_TIP_XSTATUS = 39,
+ GEN_IP_TIP_CLIENT = 40,
+ GEN_IP_TIP_STATUSMSG = 41,
+ GEN_IP_TIP_TITLE = 42,
+ GEN_SKIN_WARNCLOSE = 43,
+ GEN_SKIN_WARNCLOSE_TITLE = 44,
+ GEN_MTN_POPUP_WARNING = 45,
+ GEN_MTN_POPUP_UNSUPPORTED = 46,
+ GEN_CONTACT = 47,
+ GEN_MTN_START = 48,
+ GEN_MTN_STOP = 49,
+ GEN_FAVORITES = 50,
+ GEN_RECENT_SESSIONS = 51,
+ GEN_SBAR_LASTRECEIVED = 52,
+ GEN_SBAR_TIP_MSGLENGTH = 53,
+ CNT_OPT_TITLE_GEN = 54,
+ CNT_OPT_TITLE_LAYOUT = 55,
+ CNT_OPT_TITLE_TABS = 56,
+ CNT_OPT_TITLE_NOTIFY = 57,
+ CNT_OPT_TITLE_FLASHING = 58,
+ CNT_OPT_TITLE_TITLEBAR = 59,
+ CNT_OPT_TITLE_THEME = 60,
+ CNT_OPT_TITLE_TRANS = 61,
+ CNT_OPT_DESC_TABS = 62,
+ CNT_OPT_DESC_NOTIFY = 63,
+ CNT_OPT_DESC_THEME = 64,
+ CNT_OPT_DESC_TRANS = 65,
+ GEN_POPUPS_MESSAGE = 66,
+ GEN_POPUPS_UNKNOWN = 67,
+ GEN_POPUPS_NEW = 68,
+ GEN_NO_STATUS = 69,
+ GEN_MTN_STARTWITHNICK = 70,
+ GEN_MTN_TTITLE = 71,
+ GEN_MSG_TTITLE = 72,
+ GEN_ICONPACK_WARNING = 73, // unused!
+ CNT_SELECT_FOR = 74,
+ CNT_SELECT_INUSE = 75,
+ CNT_SELECT_RENAMEERROR = 76,
+ CNT_SELECT_DELETEERROR = 77,
+ GEN_WARN_CLOSE = 78,
+ GEN_MSG_SAVE_NODIR = 79,
+ GEN_MSG_SAVE = 80,
+ GEN_MSG_SAVE_FILE_EXISTS = 81,
+ GEN_MUC_TOPIC_IS = 82,
+ GEN_MUC_NO_TOPIC = 83,
+ GEN_MTN_STOPPED = 84,
+ GEN_AVATAR_SETTINGS = 85,
+ GEN_AVATAR_SETOWN = 86,
+ GEN_WARNING_LOADTEMPLATES = 87,
+ GEN_TITLE_LOADTHEME = 88,
+ GEN_WARNING_PASTEANDSEND_DISABLED = 89,
+ GEN_WARNING_NUDGE_DISABLED = 90,
+ GEN_UNKNOWN_CONTACT = 91,
+ GEN_LOG_TODAY = 92,
+ GEN_LOG_YESTERDAY = 93,
+ GEN_LOG_USEDEFAULTCP = 94,
+ GEN_MSG_UINCOPY = 95,
+ GEN_MSG_NOUIN = 96,
+ GEN_MSG_UINCOPY_NOMC = 97,
+ GEN_MSG_SIGNEDOFF = 98,
+ GEN_MSG_SIGNEDON = 99,
+ GEN_MSG_CHANGEDSTATUS = 100,
+ GEN_SQ_WARNING = 101,
+ GEN_SQ_WARNING_TITLE = 102,
+ GEN_SQ_MULTISEND_NO_CONTACTS = 103,
+ GEN_SQ_DELIVERYFAILED = 104,
+ GEN_SQ_DELIVERYFAILEDLATE = 105,
+ GEN_SQ_MULTISEND_SUCCESS = 106,
+ GEN_SQ_QUEUED_MESSAGE = 107,
+ GEN_SQ_QUEUING_NOT_AVAIL = 108,
+ GEN_SQ_SENDLATER_HEADER = 109,
+ CNT_SBAR_SLIST = 110,
+ GEN_MSG_ENCODING = 111,
+ GEN_MSG_FAILEDSEND = 112,
+ GEN_MSG_TOO_LONG_SPLIT = 113,
+ GEN_MSG_TOO_LONG_NOSPLIT = 114,
+ GEN_MSG_CLOSE = 115,
+ GEN_MSG_SAVEANDCLOSE = 116,
+ GEN_MSG_LOGFROZENSTATIC = 117,
+ GEN_MSG_TIP_CONTACTMENU = 118,
+ GEN_MSG_BUTTON_RETRY = 119,
+ GEN_MSG_BUTTON_CANCEL = 120,
+ GEN_MSG_BUTTON_SENDLATER = 121,
+ GEN_MSG_SEL_COPIED = 122,
+ GEN_MSG_LOGFROZENQUEUED = 123,
+ GEN_MSG_UNKNOWNCLIENT = 124,
+ GEN_MSG_NOXSTATUSMSG = 125,
+ GEN_MSG_DELIVERYFAILURE = 126,
+ GEN_MSG_SENDTIMEOUT = 127,
+ GEN_MSG_SHOWPICTURE = 128,
+ GEN_MSG_NO_EDIT_NOTES = 129,
+ GEN_MSG_EDIT_NOTES_TIP = 130,
+ GEN_MSG_MC_OFFLINEPROTOCOL = 131,
+ GEN_MSG_OFFLINE_NO_FILE = 132,
+ GEN_STRING_FILE = 133,
+ GEN_STRING_MESSAGEFROM = 134,
+ GEN_SQ_MULTISENDERROR = 135,
+ GEN_MUC_LOOKUP = 136,
+ GEN_MUC_LOOKUP_NOWORD = 137,
+ GEN_MUC_MESSAGEAMP = 138,
+ GEN_STRING_UTF8 = 139,
+ MUC_LOG_JOINED = 140,
+ MUC_LOG_ME_JOINED = 141,
+ MUC_LOG_LEFT = 142,
+ MUC_LOG_DISC = 143,
+ MUC_LOG_NICKCHANGE = 144,
+ MUC_LOG_ME_NICKCHANGE = 145,
+ MUC_LOG_KICK = 146,
+ MUC_LOG_NOTICE = 147,
+ MUC_LOG_TOPICIS = 148,
+ MUC_LOG_TOPICSETBYON = 149,
+ MUC_LOG_TOPICSETBY = 150,
+ MUC_LOG_STATUSENABLE = 151,
+ MUC_LOG_STATUSDISABLE = 152,
+ GEN_MUC_MENU_ADDTOHIGHLIGHT = 153,
+ GEN_MUC_HIGHLIGHT_ADD = 154,
+ GEN_MUC_HIGHLIGHT_EDIT = 155,
+ GEN_MUC_MENU_EDITHIGHLIGHTLIST = 156,
+ GEN_MSG_CONTACT_NOT_ON_LIST = 157,
+ GEN_SQ_SENDLATER_SUCCESS_POPUP = 158,
+ GEN_IP_MENU_COPY = 159,
+ GEN_IP_MENU_USER_DETAILS = 160,
+ GEN_IP_MENU_MSGPREFS = 161,
+ GEN_IP_MENU_ROOMPREFS = 162,
+ GEN_IP_MENU_HISTORY = 163,
+ GEN_STRING_HOUR = 164,
+ GEN_STRING_HOURS = 165,
+ GEN_STRING_MINUTE = 166,
+ GEN_STRING_MINUTES = 167,
+ MUC_SBAR_IDLEFORMAT = 168,
+ MUC_SBAR_ON_SERVER = 169,
+ MUC_SBAR_IDLEFORMAT_SHORT = 170,
+ CNT_OPT_TITLE_AVATARS = 171,
+ GEN_MUC_TRAY_HILIGHT = 172,
+ GEN_MUC_TRAY_MSG = 173,
+ GEN_MUC_TRAY_JOINED = 174,
+ GEN_MUC_TRAY_LEFT = 175,
+ GEN_MUC_TRAY_QUIT = 176,
+ GEN_MUC_TRAY_NICK = 177,
+ GEN_MUC_TRAY_KICK = 178,
+ GEN_MUC_TRAY_NOTICE = 179,
+ GEN_MUC_TRAY_TOPIC = 180,
+ GEN_MUC_TRAY_INFO = 181,
+ GEN_MUC_TRAY_STATUS_ON = 182,
+ GEN_MUC_TRAY_STATUS_OFF = 183,
+
+ GEN_MUC_POPUP_MSG = 184,
+ GEN_MUC_POPUP_JOINED = 185,
+ GEN_MUC_POPUP_LEFT = 186,
+ GEN_MUC_POPUP_LEFT1 = 187,
+ GEN_MUC_POPUP_QUIT = 188,
+ GEN_MUC_POPUP_QUIT1 = 189,
+ GEN_MUC_POPUP_NICK = 190,
+ GEN_MUC_POPUP_KICK = 191,
+ GEN_MUC_POPUP_KICK1 = 192,
+ GEN_MUC_POPUP_NOTICE = 193,
+ GEN_MUC_POPUP_TOPIC = 194,
+ GEN_MUC_POPUP_TOPIC1 = 195,
+ GEN_MUC_POPUP_STATUS_ON = 196,
+ GEN_MUC_POPUP_STATUS_OFF = 197,
+ CNT_OPT_TITLE_SOUNDS = 198,
+ GEN_IP_IDLENOTICE = 199,
+ GEN_INFOTIP_STATUSMSG = 200,
+ GEN_INFOTIP_XSTATUS = 201,
+ GEN_INFOTIP_LISTENING = 202,
+ GEN_INFOTIP_CLIENT = 203,
+ GEN_BB_IMGTOOLTIP = 204,
+ QMGR_COL_ODATE = 205,
+ QMGR_COL_MESSAGETEXT = 206,
+ QMGR_COL_STATUS = 207,
+ QMGR_COL_LASTSENDINFO = 208,
+ QMGR_FILTER_ALLCONTACTS = 209,
+ QMGR_STATUS_FAILED = 210,
+ QMGR_STATUS_SENTOK = 211,
+ QMGR_STATUS_PENDING = 212,
+ QMGR_STATUS_WAITACK = 213,
+ QMGR_ERROR_NOMULTISEND = 214,
+ QMGR_STATUS_REMOVED = 215,
+ QMGR_WARNING_REMOVAL = 216,
+ QMGR_TITLE = 217,
+ QMGR_STATUS_HOLD = 218,
+ QMGR_STATUS_DEFERRED = 219,
+ GEN_SQ_SENDLATER_FAILED_POPUP = 220,
+ GEN_SQ_SENDLATER_ERROR_MSG_TOO_LONG = 221,
+ GEN_DEFAULT_CONTAINER_NAME = 222,
+ GEN_STRING_EVENT_FILE_NODESC = 223,
+ GEN_STRING_EVENT_FILE_INVALID = 224,
+ GEN_STRING_EVENT_FILE = 225,
+ GEN_TOOLTIP_ADDCONTACT = 226,
+ GEN_TOOLTIP_DONTADD = 227,
+ GEN_TOOLTIP_EXPANDSIDEBAR = 228,
+ GEN_TASKBAR_STRING_CHAT_ROOM = 229,
+ GEN_TASKBAR_STRING_SERVER_WINDOW = 230,
+ GEN_TASKBAR_STRING_UNREAD = 231,
+ GEN_TASKBAR_STRING_USERS = 232,
+ GEN_AEROPEEK_NOHPP = 233,
+ GEN_STRING_WARNING_TITLE = 234,
+ STR_LAST = 235
+ };
+
+ enum {
+ OPT_UPREFS_IPGLOBAL = 0,
+ OPT_UPREFS_IPON = 1,
+ OPT_UPREFS_IPOFF = 2,
+ OPT_UPREFS_AVON = 3,
+ OPT_UPREFS_AVOFF = 4,
+ OPT_UPREFS_FORCEHPP = 5,
+ OPT_UPREFS_FORCEIEV = 6,
+ OPT_UPREFS_FORCEDEFAULT = 7,
+ OPT_UPREFS_SIMPLETAGS = 8,
+ OPT_UPREFS_BBCODE = 9,
+ OPT_UPREFS_FORMATTING_OFF = 10,
+ OPT_UPREFS_DEFAULTCP = 11,
+ OPT_UPREFS_NOTZSVC = 12,
+ OPT_UPREFS_TITLE = 13,
+ OPT_UPREFS_MSGLOG = 14,
+ OPT_UPREFS_GENERIC = 15,
+ OPT_AERO_EFFECT_NONE = 16,
+ OPT_AERO_EFFECT_MILK = 17,
+ OPT_AERO_EFFECT_CARBON = 18,
+ OPT_AERO_EFFECT_SOLID = 19,
+ OPT_GEN_NONE = 20,
+ OPT_GEN_AUTO = 21,
+ OPT_GEN_SUNKEN = 22,
+ OPT_GEN_1PIXEL = 23,
+ OPT_GEN_ROUNDED = 24,
+ OPT_GEN_GLOBALLY_ON = 25,
+ OPT_GEN_ON_IF_PRESENT = 26,
+ OPT_GEN_GLOBALLY_OFF = 27,
+ OPT_GEN_ON_ALWAYS_BOTTOM = 28,
+ OPT_GEN_DONT_SHOW = 29,
+ OPT_TAB_LAYOUTTWEAKS = 30,
+ OPT_TAB_SKINLOAD = 31,
+ OPT_IPANEL_VISBILITY_TITLE = 32,
+ OPT_IPANEL_VISIBILTY_IM = 33,
+ OPT_IPANEL_VISIBILTY_CHAT = 34,
+ OPT_IPANEL_SYNC_TITLE_IM = 35,
+ OPT_IPANEL_SYNC_TITLE_MUC = 36,
+ OPT_IPANEL_VIS_INHERIT = 37,
+ OPT_IPANEL_VIS_OFF = 38,
+ OPT_IPANEL_VIS_ON = 39,
+ OPT_IPANEL_SIZE_GLOBAL = 40,
+ OPT_IPANEL_SIZE_PRIVATE = 41,
+ OPT_GEN_OFF = 42,
+ OPT_GEN_BBCODE = 43,
+ OPT_LOG_DEFAULT = 44,
+ OPT_LOG_IEVIEW = 45,
+ OPT_LOG_HPP = 46,
+ OPT_MTN_NEW = 47,
+ OPT_MTN_UNKNOWN = 48,
+ OPT_GEN_ALWAYS = 49,
+ OPT_MTN_NOTFOCUSED = 50,
+ OPT_MTN_ONLYCLOSED = 51,
+ OPT_CNT_ESCNORMAL = 52,
+ OPT_CNT_ESCMINIMIZE = 53,
+ OPT_CNT_ESCCLOS = 54,
+ OPT_MTN_UNSUPPORTED = 55,
+ OPT_SMODE_CHOOSE = 56,
+ OPT_MUC_LOGTIP1 = 57,
+ OPT_MUC_LOGTIP2 = 58,
+ OPT_MUC_LOGTIP3 = 59,
+ OPT_MUC_LOGTIP4 = 60,
+ OPT_MUC_LOGTIP5 = 61,
+ OPT_MUC_LOGTIP6 = 62,
+ OPT_MUC_LOGTIP7 = 63,
+ OPT_MUC_LOGTIP8 = 64,
+ OPT_MUC_LOGTIP9 = 65,
+ OPT_MUC_LOGTIP10 = 66,
+ OPT_MUC_LOGTIP11 = 67,
+ OPT_MUC_LOGTIP12 = 68,
+ OPT_MUC_LOGTIP13 = 69,
+ OPT_MUC_LOGTIP14 = 70,
+ OPT_MUC_LOGTIP15 = 71,
+ OPT_MUC_LOGTIP16 = 72,
+ OPT_MUC_LOGTIP17 = 73,
+ OPT_MUC_LOGTIP18 = 74,
+ OPT_MUC_LOGTIP19 = 75,
+ OPT_MUC_LOGTIP20 = 76,
+ OPT_MUC_LOGTIP21 = 77,
+ OPT_MUC_LOGTIP22 = 78,
+ OPT_MUC_OPTHEADER1 = 79,
+ OPT_MUC_OPTHEADER2 = 80,
+ OPT_MUC_VARIABLES = 81,
+ OPT_MUC_SELECTFOLDER = 82,
+ OPT_MUC_NOMARKERS = 83,
+ OPT_MUC_ASICONS = 84,
+ OPT_MUC_ASSYMBOLS = 85,
+ OPT_TEMP_TITLE = 86,
+ OPT_TEMP_RESET = 87,
+ OPT_TEMP_WASRESET = 88,
+ OPT_TEMP_HELPTITLE = 89,
+ OPT_TABS_GENERAL = 90,
+ OPT_TABS_TABS = 91,
+ OPT_TABS_CONTAINERS = 92,
+ OPT_TABS_LOG = 93,
+ OPT_TABS_TOOLBAR = 94,
+ OPT_TABS_ADVANCED = 95,
+ OPT_TABS_MUC_SETTINGS = 96,
+ OPT_TABS_MUC_LOG = 97,
+ OPT_TABS_MUC_EVENTS = 98,
+ OPT_TABS_MUC_HIGHLIGHT = 99,
+ OPT_MSGLOG_EXPLAINSETTINGS = 100,
+ OPT_SKIN_NOSKINSELECT = 101,
+ OPT_LAST = 102
+ };
+
+ enum {
+ WARN_RELNOTES = 0,
+ WARN_ICONPACKVERSION = 1,
+ WARN_EDITUSERNOTES = 2,
+ WARN_ICONPACKMISSING = 3,
+ WARN_AEROPEEKSKIN = 4,
+ WARN_CHAT_ENABLED = 5,
+ WARN_IMGSVC_MISSING = 6,
+ WARN_HPP_APICHECK = 7,
+ WARN_NO_SENDLATER = 8,
+ WARN_CLOSEWINDOW = 9,
+ WARN_OPTION_CLOSE = 10,
+ WARN_THEME_OVERWRITE = 11,
+ WARN_LAST = 12
+ };
+ /*
+ * identities for the option trees
+ */
+
+ enum {
+ TREE_MODPLUS = 0,
+ TREE_NEN = 1,
+ TREE_MSG = 2,
+ TREE_LOG = 3,
+ TREE_TAB = 4,
+ };
+
+ CTranslator();
+ ~CTranslator();
+
+ inline static const wchar_t* get(const UINT id)
+ {
+ return(m_translated[id]);
+ }
+
+ inline static const wchar_t* getOpt(const UINT id)
+ {
+ return(m_OptTranslated[id]);
+ }
+
+ inline static const wchar_t* getWarning(const UINT id)
+ {
+ return(m_WarningsTranslated[id]);
+ }
+
+ inline static const wchar_t* getUntranslatedWarning(const UINT id)
+ {
+ return(m_Warnings[id]);
+ }
+
+ inline static const wchar_t* getWeekday(const UINT id)
+ {
+ return(weekDays_translated[id]);
+ }
+
+ inline static const wchar_t* getMonth(const UINT id)
+ {
+ return(months_translated[id]);
+ }
+
+ static void preTranslateAll()
+ {
+ int i;
+
+ for(i = 0; i < STR_LAST; i++)
+ m_translated[i] = TranslateTS(m_strings[i]);
+
+ for(i = 0; i < OPT_LAST; i++)
+ m_OptTranslated[i] = TranslateTS(m_OptStrings[i]);
+
+ for(i = 0; i < WARN_LAST; i++)
+ m_WarningsTranslated[i] = TranslateTS(m_Warnings[i]);
+
+ translateGroupTree(m_lvGroupsModPlus);
+ translateGroupTree(m_lvGroupsNEN);
+ translateGroupTree(m_lvGroupsMsg);
+ translateGroupTree(m_lvGroupsTab);
+ translateGroupTree(m_lvGroupsLog);
+
+ translateOptionTree(m_lvItemsModPlus);
+ translateOptionTree(m_lvItemsNEN);
+ translateOptionTree(m_lvItemsMsg);
+ translateOptionTree(m_lvItemsTab);
+ translateOptionTree(m_lvItemsLog);
+
+ for(i = 0; i < NR_WEEKDAYS; i++)
+ weekDays_translated[i] = TranslateTS(weekDays[i]);
+
+ for(i = 0; i < NR_MONTHS; i++)
+ months_translated[i] = TranslateTS(months[i]);
+ }
+
+ static void translateGroupTree(TOptionListGroup *groups);
+ static void translateOptionTree(TOptionListItem *items);
+
+ static TOptionListItem* getTree(UINT id);
+ static TOptionListGroup* getGroupTree(UINT id);
+
+private:
+ static wchar_t *m_strings[STR_LAST];
+ static wchar_t *m_translated[STR_LAST];
+
+ static wchar_t *m_OptStrings[OPT_LAST];
+ static wchar_t *m_OptTranslated[OPT_LAST];
+
+ static wchar_t *m_Warnings[WARN_LAST];
+ static wchar_t *m_WarningsTranslated[WARN_LAST];
+
+ static wchar_t *weekDays[7];
+ static wchar_t *months[12];
+
+ static wchar_t *weekDays_translated[7];
+ static wchar_t *months_translated[12];
+
+ static TOptionListGroup m_lvGroupsModPlus[], m_lvGroupsNEN[], m_lvGroupsMsg[], m_lvGroupsLog[], m_lvGroupsTab[];
+ static TOptionListItem m_lvItemsModPlus[], m_lvItemsNEN[], m_lvItemsMsg[], m_lvItemsLog[], m_lvItemsTab[];
+};
+
+#endif
+
+
diff --git a/plugins/TabSRMM/include/typingnotify.h b/plugins/TabSRMM/include/typingnotify.h
new file mode 100644
index 0000000000..03fb9851b7
--- /dev/null
+++ b/plugins/TabSRMM/include/typingnotify.h
@@ -0,0 +1,76 @@
+#define UM_SETDLGITEMINT 5674
+
+#define TIMEOUT_MINVALUE -1
+#define TIMEOUT_MAXVALUE 99
+#define TIMEOUT_POPUP 1
+#define TIMEOUT_CUSTOM 2
+#define TIMEOUT_PROTO 3
+#define TIMEOUT_PERMANENT 4
+#define COLOR_OWN 1
+#define COLOR_WINDOWS 2
+#define COLOR_POPUP 3
+
+#define Module "TypingNotify"
+
+#define SET_WO "NotWhenFocused"
+#define DEF_WO 0
+#define SET_DISABLED "Disabled"
+#define DEF_DISABLED 0
+#define SET_TIMEOUT "Timeout"
+#define DEF_TIMEOUT 7
+#define SET_TIMEOUT2 "Timeout2"
+#define DEF_TIMEOUT2 7
+#define SET_TIMEOUT_MODE "TimeoutMode"
+#define DEF_TIMEOUT_MODE TIMEOUT_POPUP
+#define SET_TIMEOUT_MODE2 "TimeoutMode2"
+#define DEF_TIMEOUT_MODE2 TIMEOUT_POPUP
+#define SET_COLOR_MODE "ColorMode"
+#define DEF_COLOR_MODE COLOR_OWN
+#define SET_ICON_SETID "IconSet"
+#define DEF_ICON_SETID 0
+#define SET_SHOWDISABLEMENU "ShowDisableMenu"
+#define DEF_SHOWDISABLEMENU 1
+#define SET_ONEPOPUP "OnePopUp"
+#define DEF_ONEPOPUP 1
+
+
+static HANDLE hDisableMenu = NULL;
+static HANDLE hPopUpsList = NULL;
+
+static BYTE OnePopUp;
+static BYTE ShowMenu;
+static BYTE PopupService=0;
+static BYTE StartDisabled;
+static BYTE StopDisabled;
+static BYTE Disabled;
+static BYTE ColorMode;
+static BYTE TimeoutMode;
+static BYTE TimeoutMode2;
+static int Timeout;
+static int Timeout2;
+static int newTimeout;
+static int newTimeout2;
+static BYTE newTimeoutMode;
+static BYTE newTimeoutMode2;
+static BYTE newColorMode;
+static TCHAR szStart[128];
+static TCHAR szStop[128];
+
+static HANDLE hntfStarted = 0;
+static HANDLE hntfStopped = 0;
+
+
+struct colors_s
+{
+ int res;
+ char desc[10];
+ COLORREF color;
+};
+
+static struct colors_s colorPicker[4] =
+{
+ {IDC_TYPEON_BG, "ON_BG", RGB(255,255,255)},
+ {IDC_TYPEON_TX, "ON_TX", RGB(0,0,0)},
+ {IDC_TYPEOFF_BG, "OFF_BG", RGB(255,255,255)},
+ {IDC_TYPEOFF_TX, "OFF_TX", RGB(0,0,0)}
+};
diff --git a/plugins/TabSRMM/include/utils.h b/plugins/TabSRMM/include/utils.h
new file mode 100644
index 0000000000..fd101c0aca
--- /dev/null
+++ b/plugins/TabSRMM/include/utils.h
@@ -0,0 +1,268 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: utils.h 12833 2010-09-27 23:45:55Z silvercircle $
+ *
+ * utility functions for TabSRMM
+ *
+ */
+
+#ifndef __UTILS_H
+#define __UTILS_H
+
+#define RTF_CTABLE_DEFSIZE 8
+
+#define RTF_DEFAULT_HEADER _T("{\\rtf1\\ansi\\deff0\\pard\\li%u\\fi-%u\\ri%u\\tx%u")
+
+#define CNT_KEYNAME "CNTW_Def"
+#define CNT_BASEKEYNAME "CNTW_"
+
+struct TRTFColorTable {
+ TCHAR szName[10];
+ COLORREF clr;
+ int index;
+ int menuid;
+};
+
+static TRTFColorTable _rtf_ctable[] = {
+ _T("red"), RGB(255, 0, 0), 0, ID_FONT_RED,
+ _T("blue"), RGB(0, 0, 255), 0, ID_FONT_BLUE,
+ _T("green"), RGB(0, 255, 0), 0, ID_FONT_GREEN,
+ _T("magenta"), RGB(255, 0, 255), 0, ID_FONT_MAGENTA,
+ _T("yellow"), RGB(255, 255, 0), 0, ID_FONT_YELLOW,
+ _T("cyan"), RGB(0, 255, 255), 0, ID_FONT_CYAN,
+ _T("black"), 0, 0, ID_FONT_BLACK,
+ _T("white"), RGB(255, 255, 255), 0, ID_FONT_WHITE,
+ _T(""), 0, 0, 0
+};
+
+class Utils {
+
+public:
+ enum {
+ CMD_CONTAINER = 1,
+ CMD_MSGDIALOG = 2,
+ CMD_INFOPANEL = 4,
+ };
+ static int TSAPI FindRTLLocale (TWindowData *dat);
+ static TCHAR* TSAPI GetPreviewWithEllipsis (TCHAR *szText, size_t iMaxLen);
+ static TCHAR* TSAPI FilterEventMarkers (TCHAR *wszText);
+ static const TCHAR* TSAPI FormatRaw (TWindowData *dat, const TCHAR *msg, int flags, BOOL isSent);
+ static const TCHAR* TSAPI FormatTitleBar (const TWindowData *dat, const TCHAR *szFormat);
+ static char* TSAPI FilterEventMarkers (char *szText);
+ static const TCHAR* TSAPI DoubleAmpersands (TCHAR *pszText);
+ static void TSAPI RTF_CTableInit ();
+ static void TSAPI RTF_ColorAdd (const TCHAR *tszColname, size_t length);
+ static void TSAPI CreateColorMap (TCHAR *Text);
+ static int TSAPI RTFColorToIndex (int iCol);
+ static int TSAPI ReadContainerSettingsFromDB (const HANDLE hContact, TContainerSettings *cs, const char *szKey = 0);
+ static int TSAPI WriteContainerSettingsToDB (const HANDLE hContact, TContainerSettings *cs, const char *szKey = 0);
+ static void TSAPI SettingsToContainer (TContainerData *pContainer);
+ static void TSAPI ContainerToSettings (TContainerData *pContainer);
+ static void TSAPI ReadPrivateContainerSettings (TContainerData *pContainer, bool fForce = false);
+ static void TSAPI SaveContainerSettings (TContainerData *pContainer, const char *szSetting);
+ static DWORD CALLBACK StreamOut (DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb);
+ static LRESULT TSAPI CmdDispatcher (UINT uType, HWND hwndDlg, UINT cmd, WPARAM wParam, LPARAM lParam, TWindowData *dat = 0,
+ TContainerData *pContainer = 0);
+ static void TSAPI addMenuItem (const HMENU& m, MENUITEMINFO& mii, HICON hIcon,
+ const TCHAR *szText, UINT uID, UINT pos);
+ static void TSAPI enableDlgControl (const HWND hwnd, UINT id, BOOL fEnable = 1);
+ static void TSAPI showDlgControl (const HWND hwnd, UINT id, int showCmd);
+ static int TSAPI mustPlaySound (const TWindowData *dat);
+ static HICON TSAPI iconFromAvatar (const TWindowData *dat);
+ static void TSAPI getIconSize (HICON hIcon, int& sizeX, int& sizeY);
+
+ static void TSAPI extractResource (const HMODULE h, const UINT uID, const TCHAR *tszName, const TCHAR *tszPath,
+ const TCHAR *tszFilename, bool fForceOverwrite);
+ static void TSAPI scaleAvatarHeightLimited (const HBITMAP hBm, double& dNewWidth, double& dNewHeight, const LONG maxHeight);
+
+ static AVATARCACHEENTRY* TSAPI loadAvatarFromAVS (const HANDLE hContact);
+ static void TSAPI sanitizeFilename (wchar_t *tszFilename);
+ static void TSAPI ensureTralingBackslash (wchar_t *szPathname);
+
+ static void* TSAPI safeAlloc (const size_t size);
+ static void* TSAPI safeCalloc (const size_t size);
+ static void* TSAPI safeMirAlloc (const size_t size);
+ static void* TSAPI safeMirCalloc (const size_t size);
+
+ static HMODULE TSAPI loadSystemLibrary (const wchar_t* szFilename);
+
+ static INT_PTR CALLBACK PopupDlgProcError (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ static const TCHAR* extractURLFromRichEdit (const ENLINK* _e, const HWND hwndRich);
+
+ template<typename T> static size_t TSAPI CopyToClipBoard(T* _t, const HWND hwndOwner)
+ {
+ HGLOBAL hData;
+
+ if (!OpenClipboard(hwndOwner) || _t == 0)
+ return(0);
+
+ std::basic_string<T> *s = new std::basic_string<T>(_t);
+ size_t _s = sizeof(T);
+ size_t i = _s * (s->length() + 1);
+
+ EmptyClipboard();
+ hData = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, i);
+
+ CopyMemory((void *)GlobalLock(hData), (void *)_t, i);
+ GlobalUnlock(hData);
+ SetClipboardData(_s == sizeof(char) ? CF_TEXT : CF_UNICODETEXT, hData);
+ CloseClipboard();
+ delete s;
+ return(i);
+ }
+
+ template<typename T> static void AddToFileList(T ***pppFiles, int *totalCount, const TCHAR* szFilename)
+ {
+ size_t _s = sizeof(T);
+
+ *pppFiles = (T**)mir_realloc(*pppFiles, (++*totalCount + 1) * sizeof(T*));
+ (*pppFiles)[*totalCount] = NULL;
+
+ if(_s == 1)
+ (*pppFiles)[*totalCount-1] = reinterpret_cast<T *>(mir_t2a(szFilename));
+ else
+ (*pppFiles)[*totalCount-1] = reinterpret_cast<T *>(mir_tstrdup(szFilename));
+
+ if (GetFileAttributes(szFilename) & FILE_ATTRIBUTE_DIRECTORY) {
+ WIN32_FIND_DATA fd;
+ HANDLE hFind;
+ TCHAR szPath[MAX_PATH];
+
+ lstrcpy(szPath, szFilename);
+ lstrcat(szPath, _T("\\*"));
+ if ((hFind = FindFirstFile(szPath, &fd)) != INVALID_HANDLE_VALUE) {
+ do {
+ if (!lstrcmp(fd.cFileName, _T(".")) || !lstrcmp(fd.cFileName, _T("..")))
+ continue;
+ lstrcpy(szPath, szFilename);
+ lstrcat(szPath, _T("\\"));
+ lstrcat(szPath, fd.cFileName);
+ AddToFileList(pppFiles, totalCount, szPath);
+ } while (FindNextFile(hFind, &fd));
+ FindClose(hFind);
+ }
+ }
+ }
+
+ /**
+ * safe strlen function - do not overflow the given buffer length
+ * if the buffer does not contain a valid (zero-terminated) string, it
+ * will return 0.
+ *
+ * careful: maxlen must be given in element counts!!
+ */
+ template<typename T> static size_t safe_strlen(const T* src, const size_t maxlen = 0)
+ {
+ size_t s = 0;
+
+ while(s < maxlen && *(src++))
+ s++;
+
+ if(s >= maxlen && *src != 0)
+ return(0);
+ else
+ return(s);
+ }
+
+public:
+ static TRTFColorTable* rtf_ctable;
+ static int rtf_ctable_size;
+};
+
+LRESULT TSAPI _dlgReturn(HWND hWnd, LRESULT result);
+
+
+
+/**
+ * implement a warning dialog with a "do not show this again" check
+ * box
+ */
+
+class CWarning {
+
+public:
+ /*
+ * the warning IDs
+ */
+ enum {
+ WARN_RELNOTES = 0,
+ WARN_ICONPACK_VERSION = 1,
+ WARN_EDITUSERNOTES = 2,
+ WARN_ICONPACKMISSING = 3,
+ WARN_AEROPEEK_SKIN = 4,
+ WARN_CHAT_ENABLED = 5,
+ WARN_SENDFILE = 6,
+ WARN_HPP_APICHECK = 7,
+ WARN_NO_SENDLATER = 8,
+ WARN_CLOSEWINDOW = 9,
+ WARN_OPTION_CLOSE = 10,
+ WARN_THEME_OVERWRITE = 11,
+ WARN_LAST = 12
+ };
+
+ /*
+ * the flags (low word is reserved for default windows flags like MB_OK etc.
+ */
+
+ enum {
+ CWF_UNTRANSLATED = 0x00010000, // do not translate the msg (useful for some error messages)
+ CWF_NOALLOWHIDE = 0x00020000 // critical message, hide the "do not show this again" check box
+ };
+
+ CWarning(const wchar_t* tszTitle, const wchar_t* tszText, const UINT uId, const DWORD dwFlags);
+ ~CWarning();
+
+public:
+ /*
+ * static function to construct and show the dialog, returns the
+ * user's choice
+ */
+ static LRESULT show (const int uId, DWORD dwFlags = 0, const wchar_t* tszTxt = 0);
+ static void destroyAll ();
+ LRESULT ShowDialog () const;
+
+private:
+ std::basic_string<wchar_t>* m_szTitle;
+ std::basic_string<wchar_t>* m_szText;
+ UINT m_uId;
+ HFONT m_hFontCaption;
+ DWORD m_dwFlags;
+ HWND m_hwnd;
+ bool m_fIsModal;
+
+ INT_PTR CALLBACK dlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ //void resize () const;
+ static INT_PTR CALLBACK stubDlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ static __int64 getMask (); // get bit mask for disabled message classes
+
+private:
+ static HANDLE hWindowList;
+};
+
+#endif /* __UTILS_H */
diff --git a/plugins/TabSRMM/include/version.h b/plugins/TabSRMM/include/version.h
new file mode 100644
index 0000000000..0ebcca8317
--- /dev/null
+++ b/plugins/TabSRMM/include/version.h
@@ -0,0 +1,15 @@
+#define VER_PLAIN "3,1,99,8"
+#define _VER_MAJOR 3
+#define _VER_MINOR 1
+#define _VER_REVISION 99
+#define _VER_BUILD 8
+
+#if defined(_WIN64)
+ #define RES_FILE_DESC "TabSRMM (Unicode) x86_amd64"
+ #define ADDONS_UPDATE_URL "http://addons.miranda-im.org/details.php?action=viewfile&id=4318"
+ #define ADDONS_DL_URL "http://addons.miranda-im.org/feed.php?dlfile=4318"
+#else
+ #define RES_FILE_DESC "TabSRMM (Unicode) x86"
+ #define ADDONS_UPDATE_URL "http://addons.miranda-im.org/details.php?action=viewfile&id=4317"
+ #define ADDONS_DL_URL "http://addons.miranda-im.org/feed.php?dlfile=4317"
+#endif
diff --git a/plugins/TabSRMM/msgwindow.rc b/plugins/TabSRMM/msgwindow.rc
new file mode 100644
index 0000000000..2c54f0b9d3
--- /dev/null
+++ b/plugins/TabSRMM/msgwindow.rc
@@ -0,0 +1,128 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include <winres.h>
+#include "include/resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#include "richedit.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "../../include/statusmodes.h"
+#include "include/version.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#pragma code_page(1251)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MSGSPLITNEW DIALOGEX 0, 0, 188, 79
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_SPLITTER,"Static",SS_ENHMETAFILE,0,46,187,1
+ CONTROL "",IDC_MESSAGE,"RichEdit20W",ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_NOHIDESEL | ES_WANTRETURN |
+ WS_VSCROLL | WS_TABSTOP,0,48,144,31,WS_EX_ACCEPTFILES |
+ WS_EX_STATICEDGE
+ CONTROL "",IDC_CONTACTPIC,"Button",BS_OWNERDRAW,155,48,34,31
+ CONTROL "",IDC_MULTISPLITTER,"Static",SS_ENHMETAFILE,186,0,2,30
+ CONTROL "",IDC_RETRY,"TSButtonClass",WS_TABSTOP,26,10,55,12,0x18000000L
+ CONTROL "",IDC_CANCELSEND,"TSButtonClass", WS_TABSTOP, 86,10,55,12,0x18000000L
+ CONTROL "",IDC_MSGSENDLATER,"TSButtonClass",WS_TABSTOP,146,10,55,12,0x18000000L
+ CONTROL "",IDC_STATICTEXT,"Static",SS_OWNERDRAW | WS_GROUP,27,0,160,9
+ CONTROL "",IDC_STATICERRORICON,"Static",SS_OWNERDRAW,4,3,20,20
+ CONTROL "",IDC_LOG,"RichEdit20A",ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL | ES_READONLY | WS_VSCROLL | WS_TABSTOP,0,0,188,30,WS_EX_STATICEDGE
+ CONTROL "",IDC_ADD,"TSButtonClass",WS_TABSTOP,155,64,16,14,0x18000000L
+ CONTROL "",IDC_CANCELADD,"TSButtonClass",WS_TABSTOP,171,64,16,14,0x18000000L
+ CONTROL "",IDC_LOGFROZENTEXT,"Static",SS_OWNERDRAW | WS_GROUP,10,3,188,18
+ CONTROL "",IDC_PANELSPLITTER,"Static",SS_ENHMETAFILE,0,32,188,1,WS_EX_TRANSPARENT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION _VER_MAJOR,_VER_MINOR,_VER_REVISION,_VER_BUILD
+ PRODUCTVERSION _VER_MAJOR,_VER_MINOR,_VER_REVISION,_VER_BUILD
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "CompanyName", "Miranda IM project"
+ VALUE "FileDescription", RES_FILE_DESC
+ VALUE "FileVersion", VER_PLAIN
+ VALUE "InternalName", "TabSRMsg"
+ VALUE "LegalCopyright", "Copyright (C) 2004-2010"
+ VALUE "LegalTrademarks", "Licensed under the Gnu general public license V2 or any later version."
+ VALUE "OriginalFilename", "tabsrmm.dll"
+ VALUE "ProductName", "TabSRMM message window plugin for Miranda IM"
+ VALUE "ProductVersion", VER_PLAIN
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "include/resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#include ""richedit.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""..\\..\\include\\statusmodes.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Neutral resources
+
diff --git a/plugins/TabSRMM/pack.cmd b/plugins/TabSRMM/pack.cmd
new file mode 100644
index 0000000000..92d4da0cb6
--- /dev/null
+++ b/plugins/TabSRMM/pack.cmd
@@ -0,0 +1,24 @@
+@echo off
+set PluginName=tabSRMM
+nmake -f %PluginName%.mak CFG="%PluginName% - Win32 Release"
+nmake -f %PluginName%.mak CFG="%PluginName% - Win32 Release Unicode"
+if errorlevel 1 (
+ echo "Make failed"
+ goto :eof )
+
+del "%temp%\%PluginName%.zip" > nul
+del "%temp%\%PluginName%W.zip" > nul
+del "%temp%\%PluginName%Src.zip" > nul
+del *.user > nul
+
+rd /S /Q Release
+rd /S /Q Release_Unicode
+
+7z.exe a -tzip -r -mx=9 "%temp%\%PluginName%.zip" ../../bin/Release/%PluginName%*.dll
+del ../../../bin/Release/Plugins/%PluginName%.dll >nul
+
+7z.exe a -tzip -r -mx=9 "%temp%\%PluginName%W.zip" "../../bin/Release Unicode/%PluginName%*.dll"
+del "../../../bin/Release Unicode/Plugins/%PluginName%.dll" >nul
+
+7z.exe a -tzip -r0 -mx=9 "%temp%\%PluginName%Src.zip" -xr!.svn -x!*.cmd
+goto :eof
diff --git a/plugins/TabSRMM/res/Logo.ico b/plugins/TabSRMM/res/Logo.ico
new file mode 100644
index 0000000000..e777e06380
--- /dev/null
+++ b/plugins/TabSRMM/res/Logo.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/Font2.ico b/plugins/TabSRMM/res/NOVA/Font2.ico
new file mode 100644
index 0000000000..0accc238f5
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/Font2.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/Incom.ico b/plugins/TabSRMM/res/NOVA/Incom.ico
new file mode 100644
index 0000000000..19957e4ac8
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/Incom.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/Outg.ico b/plugins/TabSRMM/res/NOVA/Outg.ico
new file mode 100644
index 0000000000..637196b745
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/Outg.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/Status change.ico b/plugins/TabSRMM/res/NOVA/Status change.ico
new file mode 100644
index 0000000000..8bfe42bf39
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/Status change.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/avatar.ico b/plugins/TabSRMM/res/NOVA/avatar.ico
new file mode 100644
index 0000000000..cad68be597
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/avatar.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/block.ico b/plugins/TabSRMM/res/NOVA/block.ico
new file mode 100644
index 0000000000..bdb0086c5b
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/block.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/bold.ico b/plugins/TabSRMM/res/NOVA/bold.ico
new file mode 100644
index 0000000000..fc34113b6b
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/bold.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/check.ico b/plugins/TabSRMM/res/NOVA/check.ico
new file mode 100644
index 0000000000..9649501087
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/check.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/clock.ico b/plugins/TabSRMM/res/NOVA/clock.ico
new file mode 100644
index 0000000000..6ae180c48f
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/clock.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/color.ico b/plugins/TabSRMM/res/NOVA/color.ico
new file mode 100644
index 0000000000..689762edbb
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/color.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/delete.ico b/plugins/TabSRMM/res/NOVA/delete.ico
new file mode 100644
index 0000000000..6e39da592b
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/delete.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/emoticon.ico b/plugins/TabSRMM/res/NOVA/emoticon.ico
new file mode 100644
index 0000000000..e0d066ce33
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/emoticon.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/favlist.ico b/plugins/TabSRMM/res/NOVA/favlist.ico
new file mode 100644
index 0000000000..9b55cd0afa
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/favlist.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/file.ico b/plugins/TabSRMM/res/NOVA/file.ico
new file mode 100644
index 0000000000..fadf04c4da
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/file.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/font.ico b/plugins/TabSRMM/res/NOVA/font.ico
new file mode 100644
index 0000000000..ce8272a715
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/font.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/history.ico b/plugins/TabSRMM/res/NOVA/history.ico
new file mode 100644
index 0000000000..e757b93e54
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/history.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/icon_down_arrow.ico b/plugins/TabSRMM/res/NOVA/icon_down_arrow.ico
new file mode 100644
index 0000000000..1fd67fdb0f
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/icon_down_arrow.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/info.ico b/plugins/TabSRMM/res/NOVA/info.ico
new file mode 100644
index 0000000000..715b7a1bec
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/info.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/italic.ico b/plugins/TabSRMM/res/NOVA/italic.ico
new file mode 100644
index 0000000000..5c61422a71
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/italic.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/message.ico b/plugins/TabSRMM/res/NOVA/message.ico
new file mode 100644
index 0000000000..b82dc84cb4
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/message.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/mtn.ico b/plugins/TabSRMM/res/NOVA/mtn.ico
new file mode 100644
index 0000000000..f50625f7c7
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/mtn.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/multisend.ico b/plugins/TabSRMM/res/NOVA/multisend.ico
new file mode 100644
index 0000000000..8f15a489f0
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/multisend.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/nomtn.ico b/plugins/TabSRMM/res/NOVA/nomtn.ico
new file mode 100644
index 0000000000..0f398a2ae6
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/nomtn.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/options.ico b/plugins/TabSRMM/res/NOVA/options.ico
new file mode 100644
index 0000000000..ddb72fb8ca
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/options.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/pencil.ico b/plugins/TabSRMM/res/NOVA/pencil.ico
new file mode 100644
index 0000000000..a2dcf7fd17
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/pencil.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/plus.ico b/plugins/TabSRMM/res/NOVA/plus.ico
new file mode 100644
index 0000000000..a6a7e6f38c
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/plus.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/quote.ico b/plugins/TabSRMM/res/NOVA/quote.ico
new file mode 100644
index 0000000000..7e0a596ddc
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/quote.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/recentlist.ico b/plugins/TabSRMM/res/NOVA/recentlist.ico
new file mode 100644
index 0000000000..9e4c60d9d3
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/recentlist.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/sbaroptions.ico b/plugins/TabSRMM/res/NOVA/sbaroptions.ico
new file mode 100644
index 0000000000..0693dd7f27
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/sbaroptions.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/secureOff.ico b/plugins/TabSRMM/res/NOVA/secureOff.ico
new file mode 100644
index 0000000000..e47cde2a31
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/secureOff.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/secureon.ico b/plugins/TabSRMM/res/NOVA/secureon.ico
new file mode 100644
index 0000000000..9db93af58c
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/secureon.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/slist.ico b/plugins/TabSRMM/res/NOVA/slist.ico
new file mode 100644
index 0000000000..86139d5e23
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/slist.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/sounds_off.ico b/plugins/TabSRMM/res/NOVA/sounds_off.ico
new file mode 100644
index 0000000000..a4d8f9093d
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/sounds_off.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/sounds_on.ico b/plugins/TabSRMM/res/NOVA/sounds_on.ico
new file mode 100644
index 0000000000..f27798f6ed
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/sounds_on.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/strike.ico b/plugins/TabSRMM/res/NOVA/strike.ico
new file mode 100644
index 0000000000..6ecace8a51
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/strike.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/underline.ico b/plugins/TabSRMM/res/NOVA/underline.ico
new file mode 100644
index 0000000000..01cf64a36a
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/underline.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/NOVA/userprefs.ico b/plugins/TabSRMM/res/NOVA/userprefs.ico
new file mode 100644
index 0000000000..7028f10d03
--- /dev/null
+++ b/plugins/TabSRMM/res/NOVA/userprefs.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/SKIN/close.ico b/plugins/TabSRMM/res/SKIN/close.ico
new file mode 100644
index 0000000000..84bd384dbc
--- /dev/null
+++ b/plugins/TabSRMM/res/SKIN/close.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/SKIN/default.tabsrmm b/plugins/TabSRMM/res/SKIN/default.tabsrmm
new file mode 100644
index 0000000000..2bfbf019a7
--- /dev/null
+++ b/plugins/TabSRMM/res/SKIN/default.tabsrmm
@@ -0,0 +1,341 @@
+[TabSRMM Theme]
+Version=4
+Cookie=25099837
+[StdFonts]
+Valid=1
+[Font0]
+Face=Candara
+Color=1910060
+Style=1
+Size=243
+Set=0
+[Font1]
+Face=Calibri
+Color=2634300
+Style=0
+Size=243
+Set=0
+[Font2]
+Face=Candara
+Color=2634300
+Style=1
+Size=243
+Set=0
+[Font3]
+Face=Calibri
+Color=2634300
+Style=0
+Size=243
+Set=0
+[Font4]
+Face=Cambria
+Color=8404992
+Style=1
+Size=243
+Set=0
+[Font5]
+Face=Consolas
+Color=0
+Style=0
+Size=245
+Set=0
+[Font6]
+Face=Cambria
+Color=25025
+Style=1
+Size=243
+Set=0
+[Font7]
+Face=Consolas
+Color=0
+Style=0
+Size=245
+Set=0
+[Font8]
+Face=Calibri
+Color=4276545
+Style=0
+Size=243
+Set=0
+[Font9]
+Face=Calibri
+Color=3622227
+Style=0
+Size=243
+Set=0
+[Font10]
+Face=Calibri
+Color=4802889
+Style=0
+Size=243
+Set=0
+[Font11]
+Face=Calibri
+Color=3622227
+Style=0
+Size=243
+Set=0
+[Font12]
+Face=Cambria
+Color=16744576
+Style=1
+Size=243
+Set=0
+[Font13]
+Face=Consolas
+Color=6316128
+Style=0
+Size=245
+Set=0
+[Font14]
+Face=Cambria
+Color=6381921
+Style=1
+Size=243
+Set=0
+[Font15]
+Face=Consolas
+Color=6316128
+Style=0
+Size=245
+Set=0
+[Font16]
+Face=Comic Sans MS
+Color=12517376
+Style=0
+Size=243
+Set=0
+[Font17]
+Face=Calibri
+Color=18653
+Style=0
+Size=243
+Set=0
+[Font18]
+Face=Calibri
+Color=255
+Style=0
+Size=243
+Set=0
+[Font19]
+Face=Calibri
+Color=16711935
+Style=0
+Size=243
+Set=0
+[Font20]
+Face=Arial
+Color=16711680
+Style=0
+Size=245
+Set=0
+[Font21]
+Face=Arial
+Color=18135
+Style=0
+Size=245
+Set=0
+[MiscFonts]
+Valid=1
+[IPFont100]
+Face=Comic Sans MS
+Color=4194432
+Style=3
+Size=11
+Set=0
+[IPFont101]
+Face=Lucida Grande
+Color=4605510
+Style=1
+Size=8
+Set=0
+[IPFont102]
+Face=Lucida Grande
+Color=5447138
+Style=2
+Size=8
+Set=0
+[IPFont103]
+Face=Lucida Grande
+Color=11567140
+Style=2
+Size=8
+Set=0
+[IPFont104]
+Face=Lucida Grande
+Color=7682361
+Style=0
+Size=8
+Set=0
+[IPFont105]
+Face=Candara
+Color=526344
+Style=1
+Size=9
+Set=0
+[ChatFonts]
+Valid=1
+[ChatFont0]
+Face=Trebuchet MS
+Color=4079166
+Style=0
+Size=245
+Set=0
+[ChatFont1]
+Face=Calibri
+Color=8268161
+Style=1
+Size=244
+Set=0
+[ChatFont2]
+Face=Calibri
+Color=2570178
+Style=1
+Size=244
+Set=0
+[ChatFont3]
+Face=Calibri
+Color=4685383
+Style=0
+Size=243
+Set=0
+[ChatFont4]
+Face=Calibri
+Color=5939360
+Style=0
+Size=243
+Set=0
+[ChatFont5]
+Face=Calibri
+Color=1392614
+Style=0
+Size=243
+Set=0
+[ChatFont6]
+Face=Calibri
+Color=6579300
+Style=0
+Size=243
+Set=0
+[ChatFont7]
+Face=Calibri
+Color=10508890
+Style=0
+Size=243
+Set=0
+[ChatFont8]
+Face=Calibri
+Color=3965600
+Style=0
+Size=243
+Set=0
+[ChatFont9]
+Face=Calibri
+Color=4276545
+Style=0
+Size=243
+Set=0
+[ChatFont10]
+Face=Calibri
+Color=11157059
+Style=0
+Size=243
+Set=0
+[ChatFont11]
+Face=Calibri
+Color=10503750
+Style=0
+Size=243
+Set=0
+[ChatFont12]
+Face=Calibri
+Color=11184640
+Style=0
+Size=243
+Set=0
+[ChatFont13]
+Face=Calibri
+Color=4625990
+Style=0
+Size=243
+Set=0
+[ChatFont14]
+Face=Calibri
+Color=4605590
+Style=0
+Size=243
+Set=0
+[ChatFont15]
+Face=Calibri
+Color=10508960
+Style=0
+Size=243
+Set=0
+[ChatFont16]
+Face=Calibri
+Color=5281460
+Style=0
+Size=243
+Set=0
+[ChatFont17]
+Face=Webdings
+Color=193
+Style=0
+Size=243
+Set=2
+[ChatFont18]
+Face=Consolas
+Color=7161362
+Style=1
+Size=245
+Set=0
+[Message Log]
+BackgroundColor=15132390
+IncomingBG=15790320
+OutgoingBG=15790320
+InputBG=15790320
+HgridColor=12566463
+DWFlags=-1677697439
+VGrid=1
+ExtraMicroLF=0
+LeftIndent=80
+RightIndent=9
+OldIncomingBG=15790320
+OldOutgoingBG=15790320
+StatusBG=14277119
+[Chat]
+UserListBG=13619151
+[Custom Colors]
+InfopanelBG=15790320
+cc1=179
+cc2=9071957
+cc3=13882323
+cc4=13816530
+cc5=179
+[Templates]
+Message In=%I %N %h:%m [%E] %l%M
+Message Out=%I %N %h:%m [%E] %l%M
+Group In (Start)= %I %S%fm%cs» %N, %fm%c4%&r%?n%H%S%fm%cs » %fd%c0[%T%fd%c0]%|%M
+Group Out (Start)= %I %S%fm%cs» %N, %fm%c4%&r%?n%H%S%fm%cs » %fd%c0[%T%fd%c0]%|%M
+Group In (Inner)= %S%fm%cs» %fd%c0[%T%fd%c0]%|%M
+Group Out (Inner)= %S%fm%cs« %fd%c0[%T%fd%c0]%|%M
+Status change= %I %fm%&r at %fm%&T,%! %N, %M
+Error message=%I%S %r, %h:%m:%s, %e%l%M
+[RTLTemplates]
+Message In=%I %S %N %D%n%S %T%|%M
+Message Out=%I %S %N %D%n%S %T%|%M
+Group In (Start)=%I %S%fm%cs» %N %fm%c4%&r%?n%H%S%fd%c0]%fm%cs» %T%fd%c0[%|%M
+Group Out (Start)=%I %S%fm%cs« %N %fm%c4%&D%n%H%S%fd%c0]%fm%cs« %T%fd%c0[%|%M
+Group In (Inner)=%S %fd%c0]%fm%cs» %T%fd%c0[%|%M
+Group Out (Inner)=%S %fd%c0]%fm%cs« %T%fd%c0[%|%M
+Status change=%I%S %D, %T, %N %M%!
+Error message=%I%S %D, %T, %e%l%M
+[Nick Colors]
+0=4210816
+1=12615680
+2=8421376
+3=7161362
+4=7161362
+5=10721934
+6=16777215
+7=0
diff --git a/plugins/TabSRMM/res/SKIN/default.tsk b/plugins/TabSRMM/res/SKIN/default.tsk
new file mode 100644
index 0000000000..1bfea009d5
--- /dev/null
+++ b/plugins/TabSRMM/res/SKIN/default.tsk
@@ -0,0 +1,342 @@
+; default tabsrmm skin
+; googletalk - lookalike
+
+[%Frame]
+ALPHA=100
+;Left=12
+;Top=12
+;Right=12
+;Bottom=12
+;COLOR1=262b35
+;COLOR2=262b35
+;TEXTCOLOR=cccccc
+
+[%FrameInactive]
+ALPHA=100
+Left=12
+Top=12
+Right=12
+Bottom=12
+;COLOR1=ffffff
+;COLOR2=ffffff
+;TEXTCOLOR=cccccc
+
+;[%InfoPanelfield]
+;ALPHA=0
+;COLOR1=F5F5F5
+;COLOR2=F5F5F5
+;TEXTCOLOR=000000
+;top=0
+;bottom=0
+;left=0
+;right=0
+;GRADIENT=none
+
+[%Tabitem_active]
+ALPHA=100
+TEXTCOLOR=ffffff
+Bottom=-3
+
+[%Tabitem_active_bottom]
+ALPHA=100
+TEXTCOLOR=ffffff
+Top=-3
+
+
+[%Tabitem]
+ALPHA=100
+TEXTCOLOR=ffffff
+
+[%Tabitem_bottom]
+ALPHA=100
+TEXTCOLOR=ffffff
+
+[%Tabitem_hottrack]
+ALPHA=100
+TEXTCOLOR=ffffff
+
+[%Tabitem_hottrack_bottom]
+ALPHA=100
+TEXTCOLOR=ffffff
+
+[%Tabpage]
+;ALPHA=100
+;TEXTCOLOR=cccccc
+
+
+[%Titlebutton]
+ALPHA=0
+COLOR1=f5f5f5
+COLOR2=f5f5f5
+TEXTCOLOR=787878
+
+GRADIENT=down
+RADIUS=6
+Left=1
+Right=1
+
+[%Titlebuttonmouseover]
+ALPHA=0
+COLOR1=d3d3d3
+COLOR2=d3d3d3
+TEXTCOLOR=787878
+GRADIENT=none
+RADIUS=6
+
+[%Titlebuttonpressed]
+ALPHA=0
+COLOR1=d3d3d3
+COLOR2=d3d3d3
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=787878
+GRADIENT=none
+RADIUS=6
+
+[%Container]
+ALPHA=100
+COLOR1=F5F5F5
+COLOR2=F5F5F5
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=0
+GRADIENT=none
+RADIUS=0
+
+[%Buttonnotpressed]
+;ALPHA=50
+;COLOR1=444444
+;COLOR2=444444
+;TEXTCOLOR=fefefe
+
+[%Buttonpressed]
+;ALPHA=10
+;COLOR1=444444
+;COLOR2=444444
+;TEXTCOLOR=fefefe
+
+[%Buttonmouseover]
+;ALPHA=0
+;COLOR1=444444
+;COLOR2=444444
+;TEXTCOLOR=fefefe
+
+[%Statusbarpanel]
+;TEXTCOLOR=ffffff
+
+[%InputArea]
+ALPHA=100
+COLOR1=f5f5f5
+COLOR2=f5f5f5
+TEXTCOLOR=cccc
+Left=4
+Right=4
+top=4
+bottom=4
+radius=13
+
+[%MessageLog]
+ALPHA=100
+COLOR1=f5f5f5
+COLOR2=f5f5f5
+TEXTCOLOR=cccc
+Left=4
+Right=4
+top=4
+bottom=4
+radius=13
+
+[%Userlist]
+ALPHA=100
+COLOR1=f5f5f5
+COLOR2=f5f5f5
+TEXTCOLOR=cccc
+Left=4
+Right=4
+top=4
+bottom=4
+radius=13
+
+[%InfoPanelBackground]
+ALPHA=100
+COLOR1=fff6f2
+COLOR2=FFD4C1
+TEXTCOLOR=cccc
+Left=1
+Right=1
+top=1
+bottom=1
+radius=0
+Gradient=down
+
+[$glyphs]
+Image=glyph.png
+Alpha=100
+Perpixel=1
+
+[$Frame]
+ALPHA=100
+Glyph=26, 0, 75, 56
+Image=Back.png
+PERPIXEL=1
+fillColor=ffffff
+;ColorKey=0000ff
+Right=24
+Top=28
+Bottom=28
+Left=24
+Item0=Frame
+
+[$FrameInactive]
+ALPHA=100
+Glyph=81, 21, 130,77
+Image=Back.png
+PERPIXEL=1
+fillColor=ffffff
+;ColorKey=0000ff
+Right=24
+Top=28
+Bottom=28
+Left=24
+Item0=FrameInactive
+
+[$Statuspanel]
+Glyph=80,0,99,20
+Left=4
+Top=4
+Right=4
+Bottom=4
+Item0=Statusbarpanel
+PERPIXEL=1
+
+[$Tabactive]
+Glyph=102,1,125,20
+;fillColor=5e6268
+Left=6
+Top=4
+Right=6
+Bottom=4
+Item0=Tabitem_active
+PERPIXEL=1
+
+[$Tabactivebottom]
+Glyph=128,0,151,19
+;fillColor=5e6268
+Left=6
+Top=4
+Right=6
+Bottom=4
+Item0=Tabitem_active_bottom
+PERPIXEL=1
+
+[$TabInactive]
+Glyph=154,0,177,19
+;fillColor=5e6268
+Left=6
+Top=4
+Right=6
+Bottom=4
+Item0=Tabitem
+Item1=Tabitem_hottrack
+PERPIXEL=1
+
+[$TabInactiveBottom]
+Glyph=0, 0, 23, 18
+;fillColor=5e6268
+Left=6
+Top=4
+Right=6
+Bottom=4
+Item0=Tabitem_bottom
+Item1=Tabitem_hottrack_bottom
+PERPIXEL=1
+
+[$Tabpage]
+Glyph=180,0,199,20
+fillColor=ffffff
+Left=5
+Top=5
+Right=5
+Bottom=5
+Item0=Tabpage
+Item1=InputArea
+Item2=MessageLog
+Item3=Userlist
+PERPIXEL=1
+
+[$Button]
+Glyph=80,0,99,20
+Left=4
+Top=4
+Right=4
+Bottom=4
+Item0=Buttonnotpressed
+PERPIXEL=1
+
+[$Buttonmouseover]
+Glyph=0,59,19,79
+Left=4
+Top=4
+Right=4
+Bottom=4
+Item0=Buttonmouseover
+PERPIXEL=1
+
+[$Buttonpressed]
+Glyph=0,21,19,41
+Left=4
+Top=4
+Right=4
+Bottom=4
+Item0=Buttonpressed
+PERPIXEL=1
+
+[Global]
+CloseGlyph=close.ico
+MinimizeGlyph=minimize.ico
+MaximizeGlyph=maximize.ico
+FontColor=787878
+Version=1
+Signature=101
+FrameLessMode=1
+CompositedWindow=0
+TabSkinning=1
+LightShadow=f5f5f5
+DarkShadow=f5f5f5
+TabTextNormal=787878
+TabTextActive=787878
+TabTextUnread=787878
+TabTextHottrack=787878
+MenuBarBG=f5f5f5
+NoScrollbars=0
+SbarHeight=15
+Name=Default Skin for TabSRMM 3
+
+[WindowFrame]
+Left=7
+Right=7
+Bottom=7
+Caption=18
+ClipFrame=0
+CaptionPadding=5
+RadiusTL=6
+RadiusTR=6
+RadiusBL=6
+RadiusBR=6
+TitleButtonWidth = 16
+TitleButtonHeight = 16
+TitleButtonTopOffset = 6
+CaptionOffset = 6
+
+[ClientArea]
+Left=2
+Right=2
+Top=1
+Bottom=2
+Inner=2
+
+[Avatars]
+BorderType=1
+BorderColor=787878
+
+[Theme]
+File=default.tabsrmm
diff --git a/plugins/TabSRMM/res/SKIN/glyph.png b/plugins/TabSRMM/res/SKIN/glyph.png
new file mode 100644
index 0000000000..e6d4c1c016
--- /dev/null
+++ b/plugins/TabSRMM/res/SKIN/glyph.png
Binary files differ
diff --git a/plugins/TabSRMM/res/SKIN/logo.png b/plugins/TabSRMM/res/SKIN/logo.png
new file mode 100644
index 0000000000..4f2972bdaf
--- /dev/null
+++ b/plugins/TabSRMM/res/SKIN/logo.png
Binary files differ
diff --git a/plugins/TabSRMM/res/SKIN/maximize.ico b/plugins/TabSRMM/res/SKIN/maximize.ico
new file mode 100644
index 0000000000..2abcf619e1
--- /dev/null
+++ b/plugins/TabSRMM/res/SKIN/maximize.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/SKIN/minimize.ico b/plugins/TabSRMM/res/SKIN/minimize.ico
new file mode 100644
index 0000000000..da6081edea
--- /dev/null
+++ b/plugins/TabSRMM/res/SKIN/minimize.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/SKIN/tabskin_aero.png b/plugins/TabSRMM/res/SKIN/tabskin_aero.png
new file mode 100644
index 0000000000..9cbb5b99f4
--- /dev/null
+++ b/plugins/TabSRMM/res/SKIN/tabskin_aero.png
Binary files differ
diff --git a/plugins/TabSRMM/res/SKIN/tabskin_aero_button.png b/plugins/TabSRMM/res/SKIN/tabskin_aero_button.png
new file mode 100644
index 0000000000..494e2c57d4
--- /dev/null
+++ b/plugins/TabSRMM/res/SKIN/tabskin_aero_button.png
Binary files differ
diff --git a/plugins/TabSRMM/res/SKIN/tabskin_aero_glow.png b/plugins/TabSRMM/res/SKIN/tabskin_aero_glow.png
new file mode 100644
index 0000000000..5c989f6c3a
--- /dev/null
+++ b/plugins/TabSRMM/res/SKIN/tabskin_aero_glow.png
Binary files differ
diff --git a/plugins/TabSRMM/res/SKIN/unknown.png b/plugins/TabSRMM/res/SKIN/unknown.png
new file mode 100644
index 0000000000..ae8aad4f41
--- /dev/null
+++ b/plugins/TabSRMM/res/SKIN/unknown.png
Binary files differ
diff --git a/plugins/TabSRMM/res/leftarrow.ico b/plugins/TabSRMM/res/leftarrow.ico
new file mode 100644
index 0000000000..f225f4889c
--- /dev/null
+++ b/plugins/TabSRMM/res/leftarrow.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/messAnim/M1.ico b/plugins/TabSRMM/res/messAnim/M1.ico
new file mode 100644
index 0000000000..351ea67b42
--- /dev/null
+++ b/plugins/TabSRMM/res/messAnim/M1.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/messAnim/M2.ico b/plugins/TabSRMM/res/messAnim/M2.ico
new file mode 100644
index 0000000000..f13dedaca8
--- /dev/null
+++ b/plugins/TabSRMM/res/messAnim/M2.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/messAnim/M3.ico b/plugins/TabSRMM/res/messAnim/M3.ico
new file mode 100644
index 0000000000..635a7c20f0
--- /dev/null
+++ b/plugins/TabSRMM/res/messAnim/M3.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/messAnim/M4.ico b/plugins/TabSRMM/res/messAnim/M4.ico
new file mode 100644
index 0000000000..752e97005d
--- /dev/null
+++ b/plugins/TabSRMM/res/messAnim/M4.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/overlay_disabled.ico b/plugins/TabSRMM/res/overlay_disabled.ico
new file mode 100644
index 0000000000..49d7bf1805
--- /dev/null
+++ b/plugins/TabSRMM/res/overlay_disabled.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/overlay_enabled.ico b/plugins/TabSRMM/res/overlay_enabled.ico
new file mode 100644
index 0000000000..780544d440
--- /dev/null
+++ b/plugins/TabSRMM/res/overlay_enabled.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/Font2.ico b/plugins/TabSRMM/res/proxal/Font2.ico
new file mode 100644
index 0000000000..40ba164cfe
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/Font2.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/Incom.ico b/plugins/TabSRMM/res/proxal/Incom.ico
new file mode 100644
index 0000000000..285cb6053b
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/Incom.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/Outg.ico b/plugins/TabSRMM/res/proxal/Outg.ico
new file mode 100644
index 0000000000..5680900f59
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/Outg.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/Pencil.ico b/plugins/TabSRMM/res/proxal/Pencil.ico
new file mode 100644
index 0000000000..95ce9ef31c
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/Pencil.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/Status change.ico b/plugins/TabSRMM/res/proxal/Status change.ico
new file mode 100644
index 0000000000..6ff4abcdb6
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/Status change.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/avatar.ico b/plugins/TabSRMM/res/proxal/avatar.ico
new file mode 100644
index 0000000000..f6ef57240b
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/avatar.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/block.ico b/plugins/TabSRMM/res/proxal/block.ico
new file mode 100644
index 0000000000..e46440788a
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/block.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/bold.ico b/plugins/TabSRMM/res/proxal/bold.ico
new file mode 100644
index 0000000000..9940db4ba9
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/bold.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/check.ico b/plugins/TabSRMM/res/proxal/check.ico
new file mode 100644
index 0000000000..1472a6e681
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/check.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/color.ico b/plugins/TabSRMM/res/proxal/color.ico
new file mode 100644
index 0000000000..11c54ab502
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/color.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/delete.ico b/plugins/TabSRMM/res/proxal/delete.ico
new file mode 100644
index 0000000000..c5266a6b84
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/delete.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/emoticon.ico b/plugins/TabSRMM/res/proxal/emoticon.ico
new file mode 100644
index 0000000000..d22cd0c95b
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/emoticon.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/favlist.ico b/plugins/TabSRMM/res/proxal/favlist.ico
new file mode 100644
index 0000000000..2f6f34dcf4
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/favlist.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/file.ico b/plugins/TabSRMM/res/proxal/file.ico
new file mode 100644
index 0000000000..7a130f520e
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/file.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/font.ico b/plugins/TabSRMM/res/proxal/font.ico
new file mode 100644
index 0000000000..e866b666e0
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/font.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/history.ico b/plugins/TabSRMM/res/proxal/history.ico
new file mode 100644
index 0000000000..b2477bc7d3
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/history.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/info.ico b/plugins/TabSRMM/res/proxal/info.ico
new file mode 100644
index 0000000000..c8b2beb955
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/info.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/italic.ico b/plugins/TabSRMM/res/proxal/italic.ico
new file mode 100644
index 0000000000..c94d290436
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/italic.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/message.ico b/plugins/TabSRMM/res/proxal/message.ico
new file mode 100644
index 0000000000..963cec572c
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/message.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/mtn.ico b/plugins/TabSRMM/res/proxal/mtn.ico
new file mode 100644
index 0000000000..c66482a55f
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/mtn.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/multisend.ico b/plugins/TabSRMM/res/proxal/multisend.ico
new file mode 100644
index 0000000000..adb0a7bf3b
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/multisend.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/nomtn.ico b/plugins/TabSRMM/res/proxal/nomtn.ico
new file mode 100644
index 0000000000..76d70f0182
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/nomtn.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/options.ico b/plugins/TabSRMM/res/proxal/options.ico
new file mode 100644
index 0000000000..e72c9e75a2
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/options.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/plus.ico b/plugins/TabSRMM/res/proxal/plus.ico
new file mode 100644
index 0000000000..664f6c87a7
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/plus.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/quote.ico b/plugins/TabSRMM/res/proxal/quote.ico
new file mode 100644
index 0000000000..156f4e6805
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/quote.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/recentlist.ico b/plugins/TabSRMM/res/proxal/recentlist.ico
new file mode 100644
index 0000000000..1902ff2c9d
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/recentlist.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/sbaroptions.ico b/plugins/TabSRMM/res/proxal/sbaroptions.ico
new file mode 100644
index 0000000000..3bf4dc2d5c
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/sbaroptions.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/secureOff.ico b/plugins/TabSRMM/res/proxal/secureOff.ico
new file mode 100644
index 0000000000..085bdb6d6b
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/secureOff.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/secureon.ico b/plugins/TabSRMM/res/proxal/secureon.ico
new file mode 100644
index 0000000000..e17fb86f6f
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/secureon.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/slist.ico b/plugins/TabSRMM/res/proxal/slist.ico
new file mode 100644
index 0000000000..0ca1f31b90
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/slist.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/sounds_off.ico b/plugins/TabSRMM/res/proxal/sounds_off.ico
new file mode 100644
index 0000000000..f797c207c8
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/sounds_off.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/sounds_on.ico b/plugins/TabSRMM/res/proxal/sounds_on.ico
new file mode 100644
index 0000000000..7e5f84f8d5
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/sounds_on.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/strikethrough.ico b/plugins/TabSRMM/res/proxal/strikethrough.ico
new file mode 100644
index 0000000000..f7be9ce972
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/strikethrough.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/underline.ico b/plugins/TabSRMM/res/proxal/underline.ico
new file mode 100644
index 0000000000..5137d8cb66
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/underline.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/proxal/userprefs.ico b/plugins/TabSRMM/res/proxal/userprefs.ico
new file mode 100644
index 0000000000..86753ad578
--- /dev/null
+++ b/plugins/TabSRMM/res/proxal/userprefs.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/pulldown.ico b/plugins/TabSRMM/res/pulldown.ico
new file mode 100644
index 0000000000..372482f6c1
--- /dev/null
+++ b/plugins/TabSRMM/res/pulldown.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/pullup.ico b/plugins/TabSRMM/res/pullup.ico
new file mode 100644
index 0000000000..735916cca1
--- /dev/null
+++ b/plugins/TabSRMM/res/pullup.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/res_TN/popup.ico b/plugins/TabSRMM/res/res_TN/popup.ico
new file mode 100644
index 0000000000..2ae079b729
--- /dev/null
+++ b/plugins/TabSRMM/res/res_TN/popup.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/res_TN/popup_no.ico b/plugins/TabSRMM/res/res_TN/popup_no.ico
new file mode 100644
index 0000000000..11ba330c3a
--- /dev/null
+++ b/plugins/TabSRMM/res/res_TN/popup_no.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/rightarrow.ico b/plugins/TabSRMM/res/rightarrow.ico
new file mode 100644
index 0000000000..7a62791682
--- /dev/null
+++ b/plugins/TabSRMM/res/rightarrow.ico
Binary files differ
diff --git a/plugins/TabSRMM/res/unknown.bmp b/plugins/TabSRMM/res/unknown.bmp
new file mode 100644
index 0000000000..96bdb0fd83
--- /dev/null
+++ b/plugins/TabSRMM/res/unknown.bmp
Binary files differ
diff --git a/plugins/TabSRMM/resource.rc b/plugins/TabSRMM/resource.rc
new file mode 100644
index 0000000000..27618792f5
--- /dev/null
+++ b/plugins/TabSRMM/resource.rc
@@ -0,0 +1,1142 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "include\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <windows.h>
+#include <winres.h>
+#include "../../include/statusmodes.h"
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_EXCEPTION DIALOGEX 0, 0, 370, 131
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "TabSRMM exception"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ EDITTEXT IDC_EXCEPTION_DETAILS,7,18,356,60,ES_MULTILINE | ES_READONLY
+ DEFPUSHBUTTON "Copy to clipboard",IDC_COPY_EXCEPTION,108,114,80,14
+ PUSHBUTTON "Continue",IDOK,196,114,80,14
+ PUSHBUTTON "Exit Miranda",IDCANCEL,284,114,80,14
+ LTEXT "",IDC_EX_REASON,7,5,354,9
+ LTEXT "Although the exception was caught and you may continue working with Miranda, you should restart the program as soon as possible. The exception may have damaged internal data structures and can have a serious impact on stability.",IDC_STATIC,7,83,352,26
+END
+
+IDD_INFOPANEL DIALOGEX 0, 0, 282, 176
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_BORDER
+EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC,0,0,281,175
+ LTEXT "Customize the panel",IDC_IPCONFIG_TITLE,6,4,271,11
+ GROUPBOX "Scope of settings",IDC_GROUP_SCOPE,5,15,271,43
+ LTEXT "",IDC_STATIC_VISIBILTY,10,27,128,10
+ COMBOBOX IDC_PANELVISIBILITY,149,24,118,16,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Use global or private panel height",IDC_STATIC,10,42,128,10
+ COMBOBOX IDC_PANELSIZE,149,39,118,16,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "Set size to",IDC_GROUP_SIZE,5,59,271,45
+ PUSHBUTTON "Compact (1 Line)",IDC_SIZECOMPACT,10,71,84,14
+ PUSHBUTTON "Normal (2 Lines)",IDC_SIZENORMAL,98,71,84,14
+ PUSHBUTTON "Large",IDC_SIZELARGE,187,71,84,14
+ LTEXT "Tip: To use a custom size you can always drag the bottom edge of the panel",IDC_SIZE_TIP,11,89,255,12
+ GROUPBOX "Other options",IDC_GROUP_OTHER,5,105,271,39
+ CONTROL "",IDC_NOSYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,114,254,9
+ LTEXT "Note: All settings are applied immediately",IDC_IPCONFIG_FOOTER,7,146,267,11
+ LTEXT "The container is using private settings. The panel height will not be shared with other containers.",IDC_IPCONFIG_PRIVATECONTAINER,7,157,267,18
+ LTEXT "Show picture for this contact",IDC_STATIC,10,129,128,10
+ COMBOBOX IDC_PANELPICTUREVIS,149,126,118,16,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_OPTIONS_PLUS DIALOGEX 0, 0, 303, 226
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Advanced tweaks",IDC_STATIC,3,0,300,224
+ CONTROL "",IDC_PLUS_CHECKTREE,"SysTreeView32",TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,6,9,294,136
+ LTEXT "Message send timeout",IDC_STATIC,11,155,161,11
+ EDITTEXT IDC_SECONDS,187,152,35,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_TIMEOUTSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,226,153,11,11
+ LTEXT "seconds.",IDC_STATIC,243,154,36,8
+ LTEXT "Input history size",IDC_STATIC,11,168,162,10
+ EDITTEXT IDC_HISTORYSIZE,187,167,35,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_HISTORYSIZESPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,225,166,11,13
+ LTEXT "entries",IDC_STATIC,243,169,28,10
+ LTEXT "Options marked with an asterisk (*) will only take effect after Miranda has been restarted.",IDC_STATIC,11,188,283,18
+ CONTROL "More about advanced tweaks",IDC_PLUS_HELP,"Hyperlink",WS_TABSTOP | 0x1,11,210,158,9
+ PUSHBUTTON "Revert to (safe) defaults",IDC_PLUS_REVERT,180,207,111,14
+END
+
+IDD_POPUP_OPT DIALOGEX 0, 0, 314, 257
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Event notify options",IDC_STATIC,3,0,310,157
+ CONTROL "Limit message preview to",IDC_LIMITPREVIEW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,123,138,12
+ EDITTEXT IDC_MESSAGEPREVIEWLIMIT,153,123,37,13,ES_AUTOHSCROLL
+ CONTROL "",IDC_MESSAGEPREVIEWLIMITSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,196,123,9,13
+ LTEXT "characters",IDC_STATIC,210,124,89,10
+ PUSHBUTTON "Only show event notifications when my status is...",IDC_POPUPSTATUSMODES,11,139,292,15
+ GROUPBOX "Popup Options",IDC_STATIC,3,158,310,97
+ LTEXT "Text",IDC_STATIC,60,167,23,8
+ LTEXT "Background",IDC_STATIC,86,167,47,8
+ CTEXT "Timeout (seconds, 0 = default, -1 = no timeout)",IDC_STATIC,134,167,168,8
+ LTEXT "Message",IDC_STATIC,11,181,44,13
+ CONTROL "",IDC_COLTEXT_MESSAGE,"ColourPicker",WS_TABSTOP,56,179,24,13
+ CONTROL "",IDC_COLBACK_MESSAGE,"ColourPicker",WS_TABSTOP,92,179,24,13
+ CONTROL "Default colors",IDC_CHKDEFAULTCOL_MESSAGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,123,179,72,12
+ LTEXT "Others",IDC_STATIC,12,197,44,11
+ CONTROL "",IDC_COLTEXT_OTHERS,"ColourPicker",WS_TABSTOP,56,195,24,13
+ CONTROL "",IDC_COLBACK_OTHERS,"ColourPicker",WS_TABSTOP,92,195,24,13
+ CONTROL "Default colors",IDC_CHKDEFAULTCOL_OTHERS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,123,195,72,12
+ EDITTEXT IDC_DELAY_MESSAGE,210,179,46,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_DELAY_MESSAGE_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,197,179,9,13
+ EDITTEXT IDC_DELAY_OTHERS,210,195,46,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_DELAY_OTHERS_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,199,196,11,13
+ PUSHBUTTON "Preview",IDC_PREVIEW,261,178,48,61
+ CONTROL "",IDC_EVENTOPTIONS,"SysTreeView32",TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP,6,8,303,109
+ CONTROL "",IDC_COLTEXT_MUC,"ColourPicker",WS_TABSTOP,56,211,24,13
+ CONTROL "",IDC_COLBACK_MUC,"ColourPicker",WS_TABSTOP,92,211,24,13
+ CONTROL "Default colors",IDC_CHKDEFAULTCOL_MUC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,123,211,72,12
+ LTEXT "Group chats",IDC_STATIC,12,212,44,11
+ EDITTEXT IDC_DELAY_MUC,210,211,46,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_DELAY_MESSAGE_MUC_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,253,211,9,13
+ LTEXT "Errors",IDC_STATIC,12,227,44,11
+ CONTROL "",IDC_COLTEXT_ERR,"ColourPicker",WS_TABSTOP,56,227,24,13
+ CONTROL "",IDC_COLBACK_ERR,"ColourPicker",WS_TABSTOP,92,227,24,13
+ CONTROL "Default colors",IDC_CHKDEFAULTCOL_ERR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,123,227,72,12
+ EDITTEXT IDC_DELAY_ERR,210,227,46,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_DELAY_ERR_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,253,227,9,13
+ CONTROL "Use the message log color theme for group chat popups",IDC_MUC_LOGCOLORS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,240,263,12
+ LTEXT "No compatible popup plugin was found. The event notification\nsystem is not available.",IDC_NOPOPUPAVAIL,6,30,303,109
+END
+
+IDD_CHOOSESTATUSMODES DIALOGEX 0, 0, 226, 154
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,112,133,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,169,133,50,14
+ CONTROL "All modes",IDC_ALWAYS,"Button",BS_AUTOCHECKBOX,19,17,70,14
+ GROUPBOX "Choose modes",IDC_STATUSGROUP,7,7,212,119
+ CONTROL "",ID_STATUS_ONLINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,39,82,11
+ CONTROL "",ID_STATUS_AWAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,54,82,11
+ CONTROL "",ID_STATUS_NA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,69,82,11
+ CONTROL "",ID_STATUS_DND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,84,82,11
+ CONTROL "",ID_STATUS_OCCUPIED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,39,82,11
+ CONTROL "",ID_STATUS_INVISIBLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,54,82,11
+ CONTROL "",ID_STATUS_ONTHEPHONE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,69,82,11
+ CONTROL "",ID_STATUS_OUTTOLUNCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,84,82,11
+ CONTROL "",ID_STATUS_FREECHAT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,99,82,11
+END
+
+IDD_MSGCONTAINER DIALOGEX 0, 0, 436, 233
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_MSGTABS,"TSTabCtrlClass",0xc048,31,7,5,5
+END
+
+IDD_USERPREFS DIALOGEX 0, 0, 316, 265
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Message log view mode (does not affect open windows)",IDC_STATIC,4,5,310,39
+ COMBOBOX IDC_IEVIEWMODE,8,25,128,46,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP
+ LTEXT "Select how to display the message log. This setting can be ignored when one of the listed plugins is not installed.",IDC_STATIC,143,17,164,24
+ GROUPBOX "Send text formatting method",IDC_STATIC,4,45,310,33
+ COMBOBOX IDC_TEXTFORMATTING,8,57,128,46,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "You can override the global setting for text formatting here. Use ""Force Off"" to never send formatting info for this contact.",IDC_STATIC,143,52,164,24
+ GROUPBOX "ANSI codepage",IDC_STATIC,4,82,310,32
+ COMBOBOX IDC_CODEPAGES,8,94,128,46,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Codepage for ANSI encoding/decoding when sending or receiving non-unicode messages.",IDC_STATIC,143,87,164,24
+ GROUPBOX "Other options",IDC_STATIC,4,118,310,142
+ LTEXT "Info panel mode",IDC_STATIC,12,128,128,8
+ COMBOBOX IDC_INFOPANEL,9,138,130,46,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Show avatar in message window",IDC_STATIC,12,158,127,8
+ COMBOBOX IDC_SHOWAVATAR,9,169,130,46,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Use private splitter position",IDC_PRIVATESPLITTER,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,187,296,12
+ CONTROL "Contact is a favorite contact",IDC_ISFAVORITE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,199,297,12
+ CONTROL "Force ANSI send / receive",IDC_FORCEANSI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,142,164,12
+ CONTROL "Ignore sending timeouts",IDC_IGNORETIMEOUTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,154,164,12
+ CONTROL "Load only actual history",IDC_LOADONLYACTUAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,166,164,12
+ CONTROL "Always trim message log to",IDC_ALWAYSTRIM2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,214,163,12
+ EDITTEXT IDC_TRIM,178,213,33,12,ES_RIGHT | ES_NUMBER | WS_DISABLED
+ CONTROL "",IDC_TRIMSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK | WS_DISABLED,213,207,10,14
+ LTEXT "Events",IDC_STATIC,240,215,64,8
+END
+
+IDD_CONTAINEROPTIONS DIALOGEX 0, 0, 428, 258
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION " "
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_HEADERBAR,"MHeaderbarCtrl",WS_TABSTOP,0,0,428,24
+ LTEXT "",IDC_STATIC,0,24,427,213
+ CONTROL "",IDC_SECTIONTREE,"SysTreeView32",TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS | TVS_TRACKSELECT | TVS_FULLROWSELECT | TVS_NONEVENHEIGHT | WS_BORDER | WS_HSCROLL | WS_TABSTOP,1,30,87,205
+ CONTROL "Only show tab bar when it's needed",IDC_O_NOTABS,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,105,44,310,10
+ CONTROL "Container stays on top",IDC_O_STICKY,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,105,55,310,10
+ CONTROL "Vertical maximize",IDC_VERTICALMAX,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,105,66,310,10
+ LTEXT "Close or hide inactive container after",IDC_O_AUTOHIDE,105,81,150,22
+ EDITTEXT IDC_AUTOCLOSETABTIME,280,79,41,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_AUTOCLOSETABSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,155,149,11,11
+ LTEXT "sec. (0=never)",IDC_O_AUTOHIDESECONDS,325,81,122,11
+ CONTROL "Automatically size input area (*)",IDC_AUTOSPLITTER,
+ "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,105,108,310,10
+ CONTROL "Use default setting",IDC_O_FLASHDEFAULT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,105,42,310,10
+ CONTROL "Flash until focused",IDC_O_FLASHALWAYS,"Button",BS_AUTORADIOBUTTON,105,53,310,10
+ CONTROL "Disable flashing",IDC_O_FLASHNEVER,"Button",BS_AUTORADIOBUTTON,105,64,310,11
+ CONTROL "Enable popups if minimized",IDC_O_DONTREPORT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,44,310,10
+ CONTROL "Enable popups if unfocused",IDC_DONTREPORTUNFOCUSED2,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,55,310,10
+ CONTROL "Enable popups if focused",IDC_DONTREPORTFOCUSED2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,66,310,10
+ CONTROL "Show popups for inactive tabs in active containers",IDC_ALWAYSPOPUPSINACTIVE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,77,310,10
+ CONTROL "Hide the status bar",IDC_CNTNOSTATUSBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,44,310,10
+ CONTROL "Hide the menu bar",IDC_HIDEMENUBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,55,310,10
+ CONTROL "User ID in status bar",IDC_UIDSTATUSBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,66,310,10
+ CONTROL "Hide the tool bar",IDC_HIDETOOLBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,77,310,10
+ CONTROL "Place the tool bar at the bottom (*)",IDC_BOTTOMTOOLBAR,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,88,310,10
+ CONTROL "Show the info panel",IDC_INFOPANEL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,99,310,10
+ CONTROL "Hide title bar",IDC_O_HIDETITLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,44,310,10
+ LTEXT "Title bar format",IDC_O_TITLEBARFORMAT,105,69,310,11
+ EDITTEXT IDC_TITLEFORMAT,105,81,260,13,ES_AUTOHSCROLL
+ CONTROL "Available formats",IDC_O_HELP_TITLEFORMAT,"Hyperlink",WS_TABSTOP,136,98,200,12
+ EDITTEXT IDC_THEME,105,44,123,13,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_SELECTTHEME,263,42,27,13
+ LTEXT "Use this to specify a private message log theme for this container. This will have no effect when using IEView or another message log viewer and should NOT be confused with skins.",IDC_TSLABEL_EXPLAINTHEME,110,63,310,40
+ CONTROL "Use global container size and position",IDC_USEGLOBALSIZE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,107,310,11
+ PUSHBUTTON "Save current as global",IDC_SAVESIZEASGLOBAL,105,118,160,14
+ CONTROL "Enable transparency",IDC_TRANSPARENCY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,53,260,11
+ LTEXT "active",IDC_TSLABEL_ACTIVE,146,72,26,11
+ CONTROL "",IDC_TRANSPARENCY_ACTIVE,"msctls_trackbar32",TBS_BOTH | WS_TABSTOP,174,65,95,20
+ LTEXT "inactive",IDC_TSLABEL_INACTIVE,140,105,35,9
+ CONTROL "",IDC_TRANSPARENCY_INACTIVE,"msctls_trackbar32",TBS_BOTH | WS_TABSTOP,174,98,95,20
+ CONTROL "When checked, this container will use private settings, otherwise settings are shared among containers.",IDC_CNTPRIVATE,
+ "Button",BS_AUTOCHECKBOX | BS_LEFT | BS_TOP | BS_MULTILINE | WS_TABSTOP,96,216,331,19
+ DEFPUSHBUTTON "OK",IDOK,264,240,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,319,240,50,14
+ PUSHBUTTON "Apply",IDC_APPLY,371,240,50,14,WS_DISABLED
+ GROUPBOX "Static",IDC_TITLEBOX,95,27,329,187
+ EDITTEXT IDC_DESC,99,191,323,20,ES_MULTILINE | ES_READONLY | ES_WANTRETURN | NOT WS_BORDER | NOT WS_TABSTOP
+ LTEXT "Tab location",IDC_O_TABMODE,121,41,260,12
+ COMBOBOX IDC_TABMODE,120,50,260,14,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "When using the switch bar, use the following layout",IDC_O_SBARLAYOUT,121,66,270,12
+ COMBOBOX IDC_SBARLAYOUT,120,76,260,14,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Flash event icon on tab",IDC_FLASHICON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,120,94,290,10
+ CONTROL "Flash text label on tabs",IDC_FLASHLABEL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,120,105,290,10
+ CONTROL "Single row tab control (*)",IDC_SINGLEROWTAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,120,116,290,10
+ CONTROL "Close button on tabs",IDC_CLOSEBUTTONONTABS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,120,127,290,10
+ CONTROL "Use button tabs (*)",IDC_BUTTONTABS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,120,138,290,10
+ LTEXT "You have chosen to disable all event notifications for open message windows.",IDC_O_EXPLAINGLOBALNOTIFY,103,105,240,30
+ LTEXT "Show contact avatars",IDC_O_STATIC_AVATAR,105,41,233,12
+ COMBOBOX IDC_AVATARMODE,105,50,220,14,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Show my own avatars",IDC_O_STATIC_OWNAVATAR,105,66,233,12
+ COMBOBOX IDC_OWNAVATARMODE,105,76,220,14,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Show avatars on task bar (Win 7, large task bar required)",IDC_AVATARSONTASKBAR,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,98,233,30
+ CONTROL "Enable sound effects",IDC_O_ENABLESOUNDS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,43,233,10
+ CONTROL "Play sounds when minimized",IDC_O_SOUNDSMINIMIZED,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,55,233,10
+ CONTROL "Play sounds when not focused",IDC_O_SOUNDSUNFOCUSED,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,67,233,10
+ CONTROL "Play sounds for inactive tabs in active containers",IDC_O_SOUNDSINACTIVE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,79,233,10
+ CONTROL "Play sounds for the active tab / window",IDC_O_SOUNDSFOCUSED,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,91,233,10
+ LTEXT "Options marked with an asterisk (*) do not affect open message windows.",IDC_TSLABEL_REOPENWARN,6,240,255,16
+END
+
+IDD_OPT_MSGDLG DIALOGEX 0, 0, 303, 226
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Message window options",IDC_STATIC,3,0,300,156
+ CONTROL "",IDC_WINDOWOPTIONS,"SysTreeView32",TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP,6,9,294,141
+ GROUPBOX "Size and scaling options for the bottom avatar display",IDC_STATIC,3,158,300,42
+ LTEXT "Maximum display height (pixels)",IDC_STATIC,10,170,160,10
+ EDITTEXT IDC_MAXAVATARHEIGHT,174,169,35,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_AVATARSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,209,166,9,11
+ LTEXT "(0 = no limit)",IDC_STATIC,224,170,75,11
+ CONTROL "Try to keep original size",IDC_PRESERVEAVATARSIZE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,184,285,9
+ CONTROL "Help on this",IDC_HELP_GENERAL,"Hyperlink",WS_TABSTOP | 0x1,4,209,67,9
+ PUSHBUTTON "Reset all hidden warnings",IDC_RESETWARNINGS,144,206,153,15
+END
+
+IDD_OPT_MSGLOG DIALOGEX 0, 0, 303, 226
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Options",IDC_STATIC,3,0,300,106
+ CONTROL "",IDC_LOGOPTIONS,"SysTreeView32",TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,6,9,294,94
+ GROUPBOX "Indent values",IDC_STMSGLOGGROUP2,3,107,145,29
+ LTEXT "Left/Right",IDC_STATIC,10,119,48,11
+ EDITTEXT IDC_INDENTAMOUNT,60,117,29,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_INDENTSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_HOTTRACK,72,120,10,11
+ EDITTEXT IDC_RIGHTINDENT,94,117,29,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_RINDENTSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,113,118,10,11
+ LTEXT "px",IDC_STATIC,131,119,11,9
+ GROUPBOX "Template sets",IDC_STMSGLOGGROUP,3,138,300,26
+ PUSHBUTTON "Standard templates...",IDC_MODIFY,27,147,95,14
+ PUSHBUTTON "RTL templates...",IDC_RTLMODIFY,178,147,95,14
+ GROUPBOX "Load History Events",IDC_STATIC,3,168,300,57
+ CONTROL "Load unread events only",IDC_LOADUNREAD,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,10,176,135,10
+ CONTROL "Load number of previous events",IDC_LOADCOUNT,"Button",BS_AUTORADIOBUTTON,10,187,138,10
+ CONTROL "Load previous events less than",IDC_LOADTIME,"Button",BS_AUTORADIOBUTTON,10,200,138,10
+ CONTROL "Always trim message log to",IDC_ALWAYSTRIM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,212,146,10
+ EDITTEXT IDC_LOADCOUNTN,164,185,39,12,ES_RIGHT | ES_NUMBER | WS_DISABLED
+ CONTROL "Spin1",IDC_LOADCOUNTSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,203,184,10,14
+ EDITTEXT IDC_LOADTIMEN,164,198,39,12,ES_RIGHT | ES_NUMBER | WS_DISABLED
+ CONTROL "Spin1",IDC_LOADTIMESPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK | WS_DISABLED,200,196,10,14
+ EDITTEXT IDC_TRIM,164,211,39,12,ES_RIGHT | ES_NUMBER | WS_DISABLED
+ CONTROL "",IDC_TRIMSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK | WS_DISABLED,200,209,10,14
+ LTEXT "Events",IDC_STATIC,215,212,82,8
+ LTEXT "minutes old",IDC_STMINSOLD,215,200,83,8,WS_DISABLED
+ GROUPBOX "Global message log display",IDC_STMSGLOGGROUP3,149,107,147,29
+ COMBOBOX IDC_MSGLOGDIDSPLAY,155,117,135,46,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Static",IDC_EXPLAINMSGLOGSETTINGS,31,25,240,59
+END
+
+IDD_OPT_MSGTYPE DIALOGEX 0, 0, 283, 251
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Typing Notification",IDC_STATIC,7,0,269,121
+ LTEXT "Send typing notifications to the following users when you are typing a message to the them:",IDC_STATIC,19,10,245,19
+ CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x3da,18,29,248,88,WS_EX_CLIENTEDGE
+ GROUPBOX " Show typing notifications in the message window",IDC_STATIC,7,124,269,25
+ CONTROL "",IDC_SHOWNOTIFY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,123,12,12
+ CONTROL "Flash window once on typing events (only if flashing enabled)",IDC_TYPEFLASHWIN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,135,230,10
+ GROUPBOX " Show typing notifications in the contact list and tray",IDC_STATIC,7,152,269,48
+ CONTROL "",IDC_NOTIFYTRAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,150,12,12
+ CONTROL "Show typing notification when message dialog is open",IDC_TYPEWIN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,163,230,10
+ CONTROL "Show typing notification when no message dialog is open",IDC_TYPENOWIN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,175,230,10
+ CONTROL "Show balloon tooltip in the system tray",IDC_NOTIFYBALLOON,
+ "Button",BS_AUTOCHECKBOX | WS_GROUP,44,188,206,10
+ GROUPBOX " Show popups when a user is typing",IDC_STATIC111,7,203,269,30
+ CONTROL "",IDC_NOTIFYPOPUP,"Button",BS_AUTOCHECKBOX,16,202,12,12
+ COMBOBOX IDC_MTN_POPUPMODE,32,216,230,46,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "More about typing notifications",IDC_MTN_HELP,"Hyperlink",WS_TABSTOP | 0x1,9,237,262,9
+END
+
+IDD_OPT_TABBEDMSG DIALOGEX 0, 0, 303, 226
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Tab options",IDC_STATIC,3,0,300,147
+ CONTROL "",IDC_TABMSGOPTIONS,"SysTreeView32",TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP,6,9,294,134
+ GROUPBOX "Miscellaneous options",IDC_STATIC,3,149,300,75
+ PUSHBUTTON "Setup status modes for automatic tab creation...",IDC_SETUPAUTOCREATEMODES,8,189,291,14
+ CONTROL "Limit nicknames on tabs to",IDC_CUT_TABTITLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,210,152,10
+ EDITTEXT IDC_CUT_TITLEMAX,166,208,30,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_CUT_TITLEMAXSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,191,208,11,13
+ LTEXT "characters",IDC_STATIC,208,210,88,9
+ LTEXT "ESC key behavior",IDC_STATIC,38,161,135,9
+ COMBOBOX IDC_ESCMODE,8,172,291,46,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_SELECTCONTAINER DIALOGEX 0, 0, 212, 147
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Select container"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Available containers",IDC_STATIC,7,7,198,98
+ LISTBOX IDC_CNTLIST,11,19,118,63,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK",IDOK,134,19,66,14
+ PUSHBUTTON "Cancel",IDCANCEL,134,36,66,14
+ PUSHBUTTON "Delete",IDC_DELETECONTAINER,134,68,66,14
+ EDITTEXT IDC_NEWCONTAINERNAME,11,86,117,12,ES_AUTOHSCROLL
+ PUSHBUTTON "Rename",IDC_RENAMECONTAINER,134,85,66,14
+ GROUPBOX "Create a new container",IDC_STATIC,7,107,198,34
+ EDITTEXT IDC_NEWCONTAINER,11,120,117,12,ES_AUTOHSCROLL
+ PUSHBUTTON "Create new",IDC_CREATENEW,134,119,66,14
+END
+
+IDD_OPT_TOOLBAR DIALOGEX 0, 0, 303, 226
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_TOOLBARTREE,"SysTreeView32",TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS | TVS_CHECKBOXES | TVS_FULLROWSELECT | WS_TABSTOP,16,23,116,178,WS_EX_CLIENTEDGE
+ CONTROL "Show in IM chats",IDC_IMCHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,144,51,155,10
+ CONTROL "Show in chat rooms",IDC_CHATCHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,144,64,155,10
+ EDITTEXT IDC_EDIT1,227,118,40,14,ES_AUTOHSCROLL
+ CONTROL "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,257,116,10,14
+ LTEXT "Gap between buttons:",IDC_STATIC,144,122,79,8
+ CONTROL "Hide if there isn't enough space",IDC_CANBEHIDDEN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,144,77,155,10
+ PUSHBUTTON "Reset",IDC_BBRESET,82,204,50,14
+ PUSHBUTTON "Insert Separator",IDC_SEPARATOR,144,142,125,14
+END
+
+IDD_OPT_CONTAINERS DIALOGEX 0, 0, 303, 226
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "To set container options, please use the container settings dialog. It is available by:\n1. choosing ""container settings"" from the system menu of a container.\n2. right clicking the tab or the button bar in any message window.",IDC_STATIC,7,2,298,25
+ GROUPBOX "Tabs should be used in the following way",IDC_STATIC,3,30,300,60
+ CONTROL "Use contact list groups for organizing tabs (one window per group)",IDC_CONTAINERGROUPMODE,
+ "Button",BS_AUTORADIOBUTTON | WS_GROUP,6,40,296,10
+ CONTROL "Tabbed interface, limit the maximum number of tabs per window to:",IDC_LIMITTABS,
+ "Button",BS_AUTORADIOBUTTON,6,52,237,9
+ EDITTEXT IDC_TABLIMIT,252,51,33,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_TABLIMITSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,285,54,9,10
+ CONTROL "No tabs at all, each session has its own top level window",IDC_SINGLEWINDOWMODE,
+ "Button",BS_AUTORADIOBUTTON,6,63,290,11
+ CONTROL "Default mode (tabbed interface, manual assignments)",IDC_DEFAULTCONTAINERMODE,
+ "Button",BS_AUTORADIOBUTTON,6,75,293,12
+ GROUPBOX "Container flashing",IDC_STATIC,3,90,300,39
+ LTEXT "Flash containers",IDC_STATIC,6,101,135,11
+ EDITTEXT IDC_NRFLASH,150,99,34,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_NRFLASHSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,182,100,14,11
+ LTEXT "times",IDC_STATIC,205,101,83,11
+ LTEXT "Flash interval",IDC_STATIC,6,114,137,11
+ EDITTEXT IDC_FLASHINTERVAL,150,112,34,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_FLASHINTERVALSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,185,115,10,10
+ LTEXT "milliseconds",IDC_STATIC,205,113,81,12
+ CONTROL "Help on containers",IDC_HELP_CONTAINERS,"Hyperlink",WS_TABSTOP | 0x1,21,210,262,9
+ GROUPBOX "Windows Aero settings",IDC_STATIC,3,150,300,42
+ CONTROL "Use Aero UI elements(only when not using a custom skin)",IDC_USEAERO,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,160,281,11
+ COMBOBOX IDC_AEROEFFECT,9,175,158,36,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Use Windows 7 task bar enhancements (restart required)",IDC_USEAEROPEEK,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,195,281,11
+END
+
+IDD_OPT_TYPINGNOTIFYPOPUP DIALOGEX 0, 0, 318, 174
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "PopUps",IDC_STATIC,0,6,164,127
+ CONTROL "...is &typing",IDC_START,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,6,22,80,13
+ CONTROL "...stopped t&yping",IDC_STOP,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,6,36,80,13
+ CTEXT "Back",IDC_STATIC,108,13,24,8
+ CTEXT "Text",IDC_STATIC,134,13,24,8
+ CONTROL "",IDC_TYPEON_BG,"ColourPicker",WS_TABSTOP,108,22,24,12
+ CONTROL "",IDC_TYPEON_TX,"ColourPicker",WS_TABSTOP,134,22,24,12
+ CONTROL "",IDC_TYPEOFF_BG,"ColourPicker",WS_TABSTOP,108,36,24,12
+ CONTROL "",IDC_TYPEOFF_TX,"ColourPicker",WS_TABSTOP,134,36,24,12
+ CONTROL "U&se Popup colours",IDC_USEPOPUPCOLORS,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,6,52,154,13
+ CONTROL "&Use Windows colours",IDC_USEWINCOLORS,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,6,66,133,13
+ CONTROL "Only &one popup for each contact",IDC_ONEPOPUP,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,6,96,156,13
+ CONTROL "Show &entry in the main menu",IDC_SHOWMENU,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,6,110,155,13
+ GROUPBOX "PopUp timeout (is typing)",IDC_STATIC,165,6,148,58,WS_GROUP
+ CONTROL "From PopUp plugin",IDC_TIMEOUT_POPUP,"Button",BS_AUTORADIOBUTTON,177,16,130,10
+ CONTROL "From protocol",IDC_TIMEOUT_PROTO,"Button",BS_AUTORADIOBUTTON,177,27,130,10
+ CONTROL "Permanent",IDC_TIMEOUT_PERMANENT,"Button",BS_AUTORADIOBUTTON,177,38,130,10
+ CONTROL "Custom",IDC_TIMEOUT_CUSTOM,"Button",BS_AUTORADIOBUTTON,177,49,95,10
+ EDITTEXT IDC_TIMEOUT_VALUE,282,48,21,12,ES_AUTOHSCROLL | ES_NUMBER
+ GROUPBOX "PopUp timeout (stopped typing)",IDC_STATIC,165,68,148,47,WS_GROUP
+ CONTROL "From PopUp plugin",IDC_TIMEOUT_POPUP2,"Button",BS_AUTORADIOBUTTON,177,78,130,10
+ CONTROL "Permanent",IDC_TIMEOUT_PERMANENT2,"Button",BS_AUTORADIOBUTTON,177,89,130,10
+ CONTROL "Custom",IDC_TIMEOUT_CUSTOM2,"Button",BS_AUTORADIOBUTTON,177,100,95,10
+ EDITTEXT IDC_TIMEOUT_VALUE2,286,99,21,12,ES_AUTOHSCROLL | ES_NUMBER
+ PUSHBUTTON "Preview",IDC_PREVIEW,244,120,68,14
+ LTEXT "",IDC_INFO,6,157,290,10
+ LTEXT "",IDC_INFO2,6,143,290,10
+END
+
+IDD_TEMPLATEEDIT DIALOGEX 0, 0, 368, 231
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Templates",IDC_STATIC,3,4,108,94
+ LISTBOX IDC_TEMPLATELIST,8,14,97,81,LBS_OWNERDRAWVARIABLE | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "Preview",IDC_STATIC,117,4,249,94
+ CONTROL "",IDC_PREVIEW,"RichEdit20W",WS_VSCROLL | WS_TABSTOP | 0x844,122,14,236,80
+ GROUPBOX "Edit template",IDC_STATIC,3,99,363,129
+ EDITTEXT IDC_EDITTEMPLATE,11,109,344,14,ES_AUTOHSCROLL
+ LTEXT "Double click a template to edit it. Select a template from the list box and click ""Update Preview"" to show a preview message.",IDC_STATIC,11,126,342,26
+ CONTROL "Get more help on variables",IDC_VARIABLESHELP,"Hyperlink",WS_TABSTOP | 0x1,13,157,148,10
+ LTEXT "Define up to 5 colors which you can use with some variables",IDC_STATIC,12,193,174,17
+ CONTROL "",IDC_COLOR1,"ColourPicker",WS_TABSTOP,11,213,24,13
+ CONTROL "",IDC_COLOR2,"ColourPicker",WS_TABSTOP,43,213,24,13
+ CONTROL "",IDC_COLOR3,"ColourPicker",WS_TABSTOP,75,213,24,13
+ CONTROL "",IDC_COLOR4,"ColourPicker",WS_TABSTOP,107,213,24,13
+ CONTROL "",IDC_COLOR5,"ColourPicker",WS_TABSTOP,139,213,24,13
+ PUSHBUTTON "Close",IDCANCEL,200,211,66,15
+ PUSHBUTTON "Update Preview",IDC_UPDATEPREVIEW,268,154,90,15
+ PUSHBUTTON "Save Template",IDC_SAVETEMPLATE,268,173,90,15
+ PUSHBUTTON "Forget",IDC_FORGET,268,192,90,15
+ PUSHBUTTON "Revert to Default",IDC_REVERT,268,211,90,15
+ PUSHBUTTON "Reset all templates...",IDC_RESETALLTEMPLATES,171,154,90,15
+END
+
+IDD_TABCONFIG DIALOGEX 0, 0, 303, 226
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Default width for fixed (single row) tabs",IDC_STATIC,15,52,134,18
+ EDITTEXT IDC_TABWIDTH,163,53,36,13,ES_AUTOHSCROLL
+ CONTROL "",IDC_TABWIDTHSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,195,52,11,13
+ LTEXT "Tab text label padding vertical",IDC_STATIC,14,73,126,10
+ EDITTEXT IDC_TABPADDING,163,71,28,13,ES_AUTOHSCROLL
+ CONTROL "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,187,76,11,13
+ LTEXT "horizontal",IDC_STATIC,212,73,44,10
+ EDITTEXT IDC_HTABPADDING,260,71,28,13,ES_AUTOHSCROLL
+ CONTROL "",IDC_SPIN3,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,292,71,11,13
+ LTEXT "Tab page padding:",IDC_STATIC,14,99,84,11
+ RTEXT "inner",IDC_STATIC,90,99,31,11
+ EDITTEXT IDC_TABBORDER,127,97,28,13,ES_AUTOHSCROLL
+ CONTROL "",IDC_TABBORDERSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,154,96,11,13
+ RTEXT "outer",IDC_STATIC,166,98,30,11
+ EDITTEXT IDC_TABBORDEROUTER,199,97,28,13,ES_AUTOHSCROLL
+ CONTROL "",IDC_TABBORDERSPINOUTER,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,226,103,11,13
+ LTEXT "Bottom tabs vertical adjustment:",IDC_STATIC,13,126,181,9
+ EDITTEXT IDC_BOTTOMTABADJUST,199,123,28,13,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_BOTTOMTABADJUSTSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,226,125,11,13
+ CTEXT "NOTE: some settings will not affect open containers.",IDC_STATIC,3,16,300,10
+ EDITTEXT IDC_TABBORDEROUTERRIGHT,265,97,28,13,ES_AUTOHSCROLL
+ CONTROL "",IDC_TABBORDERSPINOUTERRIGHT,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,291,97,11,13
+ EDITTEXT IDC_TABBORDEROUTERTOP,232,91,28,13,ES_AUTOHSCROLL
+ CONTROL "",IDC_TABBORDERSPINOUTERTOP,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,259,98,11,13
+ EDITTEXT IDC_TABBORDEROUTERBOTTOM,232,104,28,13,ES_AUTOHSCROLL
+ CONTROL "",IDC_TABBORDERSPINOUTERBOTTOM,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,259,104,11,13
+ GROUPBOX "Tab layout tweaks",IDC_STATIC,3,35,297,137
+END
+
+IDD_ABOUT DIALOGEX 0, 0, 228, 140
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "About tabSRMM"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC,0,30,228,110,NOT WS_GROUP
+ CONTROL "",IDC_HEADERBAR,"MHeaderbarCtrl",WS_TABSTOP,0,0,228,30
+ DEFPUSHBUTTON "OK",IDOK,168,123,55,14
+ CTEXT "Copyright © 2004-2010 by the Miranda IM project. More \ndetailed copyright information can be found in the included README file.\n\nThis software is distributed and licensed under the terms of the GNU General Public License V2 or any later version.",IDC_COPYRIGHT,5,39,217,47
+ CTEXT "",IDC_BUILDTIME,37,105,150,11
+ CONTROL "Support and latest version information",IDC_SUPPORT,
+ "Hyperlink",WS_TABSTOP | 0x1,18,91,192,12
+ PUSHBUTTON "Reset all hidden warnings",IDC_RESETWARNINGS,2,123,145,14
+END
+
+IDD_OPT_SKIN DIALOGEX 0, 0, 303, 224
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Static",IDC_SKINROOTFOLDER,10,8,284,25
+ GROUPBOX "Selected skin",IDC_STATIC,7,39,289,29
+ COMBOBOX IDC_SKINNAME,12,50,183,14,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Rescan",IDC_RESCANSKIN,202,50,90,14
+ CONTROL "Load this skin on startup",IDC_USESKIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,72,188,10
+ PUSHBUTTON "Reload active skin",IDC_RELOADSKIN,202,73,90,14
+ GROUPBOX "Skin options",IDC_STATIC,3,87,297,37
+ CONTROL "Load fonts and colors provided by skin",IDC_SKIN_LOADFONTS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,99,281,11
+ CONTROL "Load templates provided by skin (use with care, will overwrite your templates)",IDC_SKIN_LOADTEMPLATES,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,110,281,11
+ GROUPBOX "Skin root folder",IDC_STATIC,7,0,289,36
+ CONTROL "Help on this",IDC_HELP_GENERAL,"Hyperlink",WS_TABSTOP | 0x1,224,211,67,9
+ CTEXT "Before you can load or unload a skin, you must close all message windows.",IDC_SKIN_WARN,9,186,283,20
+ PUSHBUTTON "Close open message windows now",IDC_SKIN_CLOSENOW,9,209,174,12
+ GROUPBOX "Theme support",IDC_STATIC,3,126,297,56
+ LTEXT "You can export and import all your color and font settings here. This allows you to create a Theme file which can be shared between different profiles or with your buddies.",IDC_STATIC,9,137,286,26
+ PUSHBUTTON "Export to a file...",IDC_THEMEEXPORT,9,164,139,14
+ PUSHBUTTON "Import from a file...",IDC_THEMEIMPORT,156,164,139,14
+END
+
+IDD_USERPREFS_FRAME DIALOGEX 0, 0, 326, 316
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_OPTIONSTAB,"SysTabControl32",0x0,2,5,323,284
+ PUSHBUTTON "Ok",IDOK,124,296,71,16
+ PUSHBUTTON "Cancel",IDCANCEL,201,296,71,16
+END
+
+IDD_USERPREFS1 DIALOGEX 0, 0, 316, 265
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ GROUPBOX "Icons",IDC_STATIC,8,36,302,57
+ CONTROL "Event type icons in the message log",IDC_UPREFS_SHOWICONS,
+ "Button",BS_AUTO3STATE | WS_TABSTOP,15,47,290,11
+ CONTROL "Text symbols as event markers",IDC_UPREFS_SHOWSYMBOLS,
+ "Button",BS_AUTO3STATE | WS_TABSTOP,15,63,289,11
+ CONTROL "Use different icons to mark incoming and outgoing messages",IDC_UPREFS_INOUTICONS,
+ "Button",BS_AUTO3STATE | WS_TABSTOP,15,79,291,11
+ GROUPBOX "Date and time",IDC_STATIC,8,96,302,45
+ CONTROL "Show timestamps",IDC_UPREFS_SHOWTIMESTAMP,"Button",BS_AUTO3STATE | WS_TABSTOP,15,107,136,11
+ CONTROL "Show seconds in timestamp",IDC_UPREFS_SHOWSECONDS,
+ "Button",BS_AUTO3STATE | WS_TABSTOP,15,120,136,11
+ CONTROL "Show date in timestamps",IDC_UPREFS_SHOWDATES,"Button",BS_AUTO3STATE | WS_TABSTOP,155,107,150,11
+ CONTROL "Use contacts local time",IDC_UPREFS_LOCALTIME,"Button",BS_AUTO3STATE | WS_TABSTOP,155,120,150,11
+ GROUPBOX "Format",IDC_STATIC,8,144,302,42
+ CONTROL "Indent message body",IDC_UPREFS_INDENT,"Button",BS_AUTO3STATE | WS_TABSTOP,15,154,136,11
+ CONTROL "Display grid lines",IDC_UPREFS_GRID,"Button",BS_AUTO3STATE | WS_TABSTOP,15,167,136,11
+ CONTROL "Message grouping",IDC_UPREFS_GROUPING,"Button",BS_AUTO3STATE | WS_TABSTOP,155,154,150,11
+ CONTROL "Support BBCODE",IDC_UPREFS_BBCODE,"Button",BS_AUTO3STATE | WS_TABSTOP,155,167,150,11
+ GROUPBOX "Misc",IDC_STATIC,8,186,302,52
+ CONTROL "RTL is default text direction",IDC_UPREFS_RTL,"Button",BS_AUTO3STATE | WS_TABSTOP,15,196,290,11
+ CONTROL "Log status changes (in open message windows only)",IDC_UPREFS_LOGSTATUS,
+ "Button",BS_AUTO3STATE | WS_TABSTOP,15,210,290,11
+ PUSHBUTTON "Revert to global options",IDC_REVERTGLOBAL,62,242,191,18
+ LTEXT "You can set private message log options for this contact here. Filled boxes are inherited from the global settings which can be found on Message Sessions->Message Log",IDC_STATIC,16,4,296,28
+ CONTROL "Use normal templates (uncheck to use simple templates)",IDC_UPREFS_NORMALTEMPLATES,
+ "Button",BS_AUTO3STATE | WS_TABSTOP,15,224,290,11
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_HYPERLINKHAND CURSOR "../../src/res/cursor_hyperlink.cur"
+IDC_DROP CURSOR "../../src/res/cursor_drag_copy.CUR"
+IDC_DROPUSER CURSOR "../../src/res/cursor_drop_user.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_CONTEXT MENU
+BEGIN
+ POPUP "Log"
+ BEGIN
+ MENUITEM "&Copy", IDM_COPY
+ MENUITEM "&Quote", IDM_QUOTE
+ MENUITEM "Co&py All", IDM_COPYALL
+ MENUITEM "Select &All", IDM_SELECTALL
+ MENUITEM SEPARATOR
+ MENUITEM "Clear Log", IDM_CLEAR
+ MENUITEM "Freeze Log", ID_LOG_FREEZELOG
+ END
+ POPUP "LogLink"
+ BEGIN
+ MENUITEM "Open in &new window", IDM_OPENNEW
+ MENUITEM "&Open in existing window", IDM_OPENEXISTING
+ MENUITEM "&Copy link", IDM_COPYLINK
+ END
+ POPUP "Editor"
+ BEGIN
+ MENUITEM "Cut", IDM_CUT
+ MENUITEM "Copy", IDM_COPY
+ MENUITEM "Paste", IDM_PASTE
+ MENUITEM "Paste formatted Text", IDM_PASTEFORMATTED
+ MENUITEM "Paste and Send immediately", ID_EDITOR_PASTEANDSENDIMMEDIATELY
+ MENUITEM SEPARATOR
+ MENUITEM "Copy all", IDM_COPYALL
+ MENUITEM "Select all", IDM_SELECTALL
+ MENUITEM SEPARATOR
+ MENUITEM "Show Message Length Indicator", ID_EDITOR_SHOWMESSAGELENGTHINDICATOR
+ END
+END
+
+IDR_TABCONTEXT MENU
+BEGIN
+ POPUP "Tabmenu"
+ BEGIN
+ MENUITEM "Close Tab", ID_TABMENU_CLOSETAB
+ MENUITEM "Leave Chat Room", ID_TABMENU_LEAVECHATROOM
+ MENUITEM SEPARATOR
+ MENUITEM "Save Tab Position", ID_TABMENU_SAVETABPOSITION
+ MENUITEM "Clear saved Tab Position", ID_TABMENU_CLEARSAVEDTABPOSITION
+ MENUITEM SEPARATOR
+ MENUITEM "Attach to Container...", ID_TABMENU_ATTACHTOCONTAINER
+ MENUITEM "Container Options...", ID_TABMENU_CONTAINEROPTIONS
+ MENUITEM SEPARATOR
+ MENUITEM "Close Container", ID_TABMENU_CLOSECONTAINER
+ END
+ POPUP "Picmenu"
+ BEGIN
+ POPUP "Show Contact Picture"
+ BEGIN
+ MENUITEM "Default", ID_VISIBILITY_DEFAULT
+ MENUITEM "Hidden for this Contact", ID_VISIBILITY_HIDDENFORTHISCONTACT
+ MENUITEM "Visible for this Contact", ID_VISIBILITY_VISIBLEFORTHISCONTACT
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Contact Picture Settings...", ID_PICMENU_SETTINGS
+ MENUITEM "Always keep the button bar at full width", ID_PICMENU_ALWAYSKEEPTHEBUTTONBARATFULLWIDTH
+ MENUITEM "Save this Picture As...", ID_PICMENU_SAVETHISPICTUREAS
+ END
+ POPUP "Logmenu"
+ BEGIN
+ POPUP "&Message Log Settings"
+ BEGIN
+ MENUITEM "&Global...", ID_MESSAGELOGSETTINGS_GLOBAL
+ MENUITEM "&For this Contact...", ID_MESSAGELOGSETTINGS_FORTHISCONTACT
+ END
+ END
+ POPUP "Sendmenu"
+ BEGIN
+ MENUITEM "Send &Default", ID_SENDMENU_SENDDEFAULT
+ MENUITEM "Send to &multiple Users", ID_SENDMENU_SENDTOMULTIPLEUSERS
+ MENUITEM "Send to &Container", ID_SENDMENU_SENDTOCONTAINER
+ MENUITEM "Send &Later", ID_SENDMENU_SENDLATER
+ MENUITEM SEPARATOR
+ MENUITEM "Force &ANSI", ID_SENDMENU_FORCEANSISEND
+ MENUITEM "Send unsafe (ignore Timeouts)", ID_FONT_CYAN
+ MENUITEM SEPARATOR
+ MENUITEM "Send Nudge", ID_SENDMENU_SENDNUDGE
+ END
+ POPUP "Protomenu"
+ BEGIN
+ POPUP "Splitter Position"
+ BEGIN
+ MENUITEM "Global", ID_MODE_GLOBAL
+ MENUITEM "Private", ID_MODE_PRIVATE
+ END
+ MENUITEM SEPARATOR
+ POPUP "Send Text Formatting"
+ BEGIN
+ POPUP "Global"
+ BEGIN
+ MENUITEM "BBCode", ID_GLOBAL_BBCODE
+ MENUITEM "Off", ID_GLOBAL_OFF
+ END
+ POPUP "This Contact"
+ BEGIN
+ MENUITEM "Global Setting", ID_THISCONTACT_GLOBALSETTING
+ MENUITEM "BBCode", ID_THISCONTACT_BBCODE
+ MENUITEM "Force Off", ID_THISCONTACT_OFF
+ END
+ END
+ END
+ POPUP "Unread Menu"
+ BEGIN
+ MENUITEM SEPARATOR
+ END
+ POPUP "Traycontext"
+ BEGIN
+ MENUITEM "Recent Sessions", 0
+ MENUITEM SEPARATOR
+ MENUITEM "Favorites", 0
+ MENUITEM SEPARATOR
+ MENUITEM "Show the Tray Icon", ID_TRAYCONTEXT_SHOWTHETRAYICON
+ MENUITEM SEPARATOR
+ MENUITEM "Disable All Event Notifications", ID_TRAYCONTEXT_DISABLEALLPOPUPS
+ MENUITEM "Don't create Windows automatically", ID_TRAYCONTEXT_DON
+ MENUITEM "Hide all Message Containers", ID_TRAYCONTEXT_HIDEALLMESSAGECONTAINERS
+ MENUITEM "Restore all Message Containers", ID_TRAYCONTEXT_RESTOREALLMESSAGECONTAINERS
+ MENUITEM "Don't play Sounds", ID_TRAYCONTEXT_DON40223
+ MENUITEM "Be ""Super Quiet""", ID_TRAYCONTEXT_BE
+ END
+ POPUP "Font"
+ BEGIN
+ MENUITEM "Default Color", ID_FONT_DEFAULTCOLOR
+ MENUITEM "Red", ID_FONT_RED
+ MENUITEM "Green", ID_FONT_GREEN
+ MENUITEM "Blue", ID_FONT_BLUE
+ MENUITEM "Magenta", ID_FONT_MAGENTA
+ MENUITEM "Yellow", ID_FONT_YELLOW
+ MENUITEM "Cyan", ID_FONT_CYAN
+ MENUITEM "Black", ID_FONT_BLACK
+ MENUITEM "White", ID_FONT_WHITE
+ MENUITEM SEPARATOR
+ MENUITEM "Clear all Formatting", ID_FONT_CLEARALLFORMATTING
+ END
+ POPUP "Dummy", INACTIVE
+ BEGIN
+ MENUITEM "No Message Sessions opened", ID_DUMMY_NOMESSAGESESSIONSOPENED
+ END
+ POPUP "Favorites"
+ BEGIN
+ MENUITEM "Add Contact to Favorites", ID_FAVORITES_ADDCONTACTTOFAVORITES
+ MENUITEM "Remove Contact from Favorites", ID_FAVORITES_REMOVECONTACTFROMFAVORITES
+ END
+ POPUP "Apparentmenu"
+ BEGIN
+ MENUITEM "dummy", 65535
+ END
+ POPUP "Panelpicmenu"
+ BEGIN
+ MENUITEM SEPARATOR
+ MENUITEM "Contact Picture Settings...", ID_PICMENU_SETTINGS
+ MENUITEM "Save this Picture As...", ID_PANELPICMENU_SAVETHISPICTUREAS
+ END
+ POPUP "Splitter context"
+ BEGIN
+ MENUITEM "Set Position for this Session", ID_SPLITTERCONTEXT_SETPOSITIONFORTHISSESSION
+ MENUITEM SEPARATOR
+ MENUITEM "Set and Save for all Sessions", ID_SPLITTERCONTEXT_SAVEGLOBALFORALLSESSIONS
+ MENUITEM "Set and Save for this Contact only", ID_SPLITTERCONTEXT_SAVEFORTHISCONTACTONLY
+ MENUITEM SEPARATOR
+ MENUITEM "Revert to old Position", ID_SPLITTERCONTEXT_FORGETTHECHANGES
+ END
+ POPUP "Queue manager"
+ BEGIN
+ MENUITEM "Mark Selected for Removal", ID_QUEUEMANAGER_MARKSELECTEDFORREMOVAL
+ MENUITEM "Reset Selected", ID_QUEUEMANAGER_RESETSELECTED
+ MENUITEM SEPARATOR
+ MENUITEM "Hold Selected", ID_QUEUEMANAGER_HOLDSELECTED
+ MENUITEM "Resume Selected", ID_QUEUEMANAGER_RESUMESELECTED
+ MENUITEM SEPARATOR
+ MENUITEM "Cancel all Multisend Jobs", ID_QUEUEMANAGER_CANCELALLMULTISENDJOBS
+ MENUITEM SEPARATOR
+ MENUITEM "Copy Message to Clipboard", ID_QUEUEMANAGER_COPYMESSAGETOCLIPBOARD, INACTIVE
+ END
+END
+
+IDR_MENUBAR MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "Save Message Log As...", 40109
+ MENUITEM SEPARATOR
+ MENUITEM "Close Message Session\tCtrl-W", 40086
+ MENUITEM "Close Container\tAlt-F4", 40085
+ END
+ POPUP "&View"
+ BEGIN
+ MENUITEM "Show Menu Bar", 40076
+ MENUITEM "Show Status Bar", 40077
+ MENUITEM "Info Panel...", 40208
+ POPUP "Tool Bar"
+ BEGIN
+ MENUITEM "Show Tool Bar", 40078
+ MENUITEM "Place ToolBar at bottom", 40171
+ END
+ MENUITEM "Title Bar", 40083
+ MENUITEM "Tabs at Bottom", 40093
+ MENUITEM "Vertical maximize", 40143
+ MENUITEM SEPARATOR
+ POPUP "Window Flashing"
+ BEGIN
+ MENUITEM "Use default Value", 40106
+ MENUITEM "Flash until focused", 40107
+ MENUITEM "Disable Flashing", 40108
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Show Multisend Contact List", 40087
+ MENUITEM SEPARATOR
+ MENUITEM "Stay on Top", 40095
+ END
+ POPUP "Message &Log"
+ BEGIN
+ POPUP "&Message Log Settings"
+ BEGIN
+ MENUITEM "&Global...", ID_MESSAGELOGSETTINGS_GLOBAL
+ MENUITEM "&For this Contact...", ID_MESSAGELOGSETTINGS_FORTHISCONTACT
+ END
+ END
+ POPUP "&Container"
+ BEGIN
+ MENUITEM "Container Options...", 40114
+ MENUITEM SEPARATOR
+ POPUP "Event Popups"
+ BEGIN
+ MENUITEM "Disable all Event Popups", 40098
+ MENUITEM SEPARATOR
+ MENUITEM "Show Popups if Window is minimized", 40110
+ MENUITEM "Show Popups if Window is unfocused", 40111
+ MENUITEM "Show Popups if Window is focused", 40120
+ MENUITEM "Show Popups for all inactive sessions", 40112
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Save current Window Position as Default", 40113
+ END
+ POPUP "Help"
+ BEGIN
+ MENUITEM "About tabSRMM...", ID_HELP_ABOUTTABSRMM
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_FEATURE_DISABLED ICON "res/overlay_disabled.ico"
+IDI_ENABLED ICON "res/res_TN/popup.ico"
+IDI_DISABLED ICON "res/res_TN/popup_no.ico"
+IDI_FEATURE_ENABLED ICON "res/overlay_enabled.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_EXCEPTION, DIALOG
+ BEGIN
+ END
+
+ IDD_USERPREFS, DIALOG
+ BEGIN
+ END
+
+ IDD_CONTAINEROPTIONS, DIALOG
+ BEGIN
+ END
+
+ IDD_OPT_MSGDLG, DIALOG
+ BEGIN
+ END
+
+ IDD_OPT_CONTAINERS, DIALOG
+ BEGIN
+ END
+
+ IDD_TABCONFIG, DIALOG
+ BEGIN
+ END
+
+ IDD_ABOUT, DIALOG
+ BEGIN
+ END
+
+ IDD_OPT_SKIN, DIALOG
+ BEGIN
+ END
+
+ IDD_USERPREFS_FRAME, DIALOG
+ BEGIN
+ END
+
+ IDD_USERPREFS1, DIALOG
+ BEGIN
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// German (Germany) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_SENDLATER_QMGR DIALOGEX 0, 0, 484, 258
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Queued send jobs"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Close",IDOK,391,239,86,14
+ CONTROL "",IDC_QMGR_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,6,33,471,183
+ GROUPBOX "Queued jobs",IDC_STATIC,3,24,477,198
+ RTEXT "Filter by contact:",IDC_STATIC,9,8,324,12
+ COMBOBOX IDC_QMGR_FILTER,345,6,132,15,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Help on this",IDC_QMGR_HELP,"Hyperlink",WS_TABSTOP,246,240,141,12
+ CONTROL "Display popups for failed jobs",IDC_QMGR_ERRORPOPUPS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,228,210,12
+ CONTROL "Display popups for completed jobs",IDC_QMGR_SUCCESSPOPUPS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,242,210,12
+END
+
+IDD_WARNING DIALOGEX 0, 0, 298, 105
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC,0,0,298,76
+ CONTROL "Do not show this message again",IDC_DONTSHOWAGAIN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,77,277,11
+ CONTROL "",IDC_WARNTEXT,"RichEdit20W",WS_VSCROLL | 0x1944,36,23,250,51
+ ICON "",IDC_WARNICON,6,8,24,24,SS_CENTERIMAGE
+ LTEXT "Static",IDC_CAPTION,36,5,252,16
+ DEFPUSHBUTTON "OK",IDOK,245,88,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,241,88,50,14
+ PUSHBUTTON "Yes",IDYES,136,88,50,14
+ PUSHBUTTON "No",IDNO,189,88,50,14
+ CONTROL "",IDC_WARNGROUP,"Static",SS_ENHMETAFILE,0,74,297,2
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_SENDLATER_QMGR, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 477
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 254
+ END
+
+ IDD_WARNING, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 291
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 98
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // German (Germany) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MODERNOPTS DIALOGEX 0, 0, 369, 210
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Message sending:",IDC_TXT_TITLE2,0,64,185,8
+ LTEXT "Window:",IDC_TXT_TITLE1,1,0,182,8
+ CONTROL "Esc closes sessions (minimizes window, if disabled)",IDC_CLOSEONESC,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,13,174,10
+ CONTROL "Always pop up and activate new windows",IDC_ALWAYSPOPUP,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,25,174,10
+ CONTROL "Create new windows in minimized state",IDC_CREATEMIN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,37,174,10
+ CONTROL "Check1",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,10,49,174,10
+ CONTROL "Send on Shift+Enter",IDC_SENDSHIFTENTER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,89,174,10
+ CONTROL "Send message on Enter",IDC_SENDENTER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,101,174,10
+ CONTROL "Send message on double Enter",IDC_SENDDBLENTER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,113,174,10
+ CONTROL "Minimize the message window on send",IDC_MINSEND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,125,174,10
+ LTEXT "Tabs:",IDC_TXT_TITLE4,184,0,183,8
+ CONTROL "Use tabbed interface",IDC_USETABS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,13,173,10
+ CONTROL "Create new tabs without activating them",IDC_CREATENOACTIVATE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,25,173,10
+ CONTROL "Pop up minimized window when a new tab is created",IDC_POPUPONCREATE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,37,173,10
+ CONTROL "Automatically switch tabs in minimized windows",IDC_AUTOSWITCHTABS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,49,173,10
+ LTEXT "History:",IDC_TXT_TITLE5,1,140,367,8
+ CONTROL "Load unread events only",IDC_LOADUNREAD,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,10,153,135,10
+ CONTROL "Load number of previous events",IDC_LOADCOUNT,"Button",BS_AUTORADIOBUTTON,10,166,138,10
+ CONTROL "Load previous events less than",IDC_LOADTIME,"Button",BS_AUTORADIOBUTTON,10,179,138,10
+ CONTROL "Always trim message log to",IDC_ALWAYSTRIM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,192,146,10
+ EDITTEXT IDC_LOADCOUNTN,164,164,39,12,ES_RIGHT | ES_NUMBER | WS_DISABLED
+ CONTROL "",IDC_LOADCOUNTSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,203,163,10,14
+ EDITTEXT IDC_LOADTIMEN,164,177,39,12,ES_RIGHT | ES_NUMBER | WS_DISABLED
+ CONTROL "",IDC_LOADTIMESPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK | WS_DISABLED,200,175,10,14
+ EDITTEXT IDC_TRIM,164,190,39,12,ES_RIGHT | ES_NUMBER | WS_DISABLED
+ CONTROL "",IDC_TRIMSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK | WS_DISABLED,200,189,10,14
+ LTEXT "Events",IDC_STATIC,215,192,82,8
+ LTEXT "minutes old",IDC_STMINSOLD,215,179,83,8,WS_DISABLED
+ LTEXT "Notifications:",IDC_TXT_TITLE3,184,64,183,8
+ CONTROL "Don't announce when dialog is open",IDC_NOOPENNOTIFY,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,77,173,10
+ CONTROL "Message events",IDC_NOTIFYMSG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,89,173,10
+ CONTROL "File events",IDC_NOTIFYFILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,101,173,10
+ CONTROL "URL events",IDC_NOTIFYURL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,113,173,10
+ CONTROL "Other events",IDC_NOTIFYOTHER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,125,173,10
+ CONTROL "Send message on Ctrl+Enter (always enabled)",IDC_SENDCTRLENTER,
+ "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,10,77,174,10
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_MODERNOPTS, DIALOG
+ BEGIN
+ VERTGUIDE, 10
+ VERTGUIDE, 184
+ VERTGUIDE, 194
+ BOTTOMMARGIN, 207
+ HORZGUIDE, 59
+ HORZGUIDE, 64
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "include\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include <windows.h>\r\n"
+ "#include <winres.h>\r\n"
+ "#include ""../../include/statusmodes.h""\r\n"
+ "\r\r\n"
+ "\r\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// SKIN_GLYPH
+//
+
+IDR_SKIN_AERO SKIN_GLYPH "res\\SKIN\\tabskin_aero.png"
+IDR_SKIN_AERO_GLOW SKIN_GLYPH "res\\SKIN\\tabskin_aero_glow.png"
+IDR_SKIN_AERO_SWITCHBAR SKIN_GLYPH "res\\SKIN\\tabskin_aero_button.png"
+IDR_SKIN_LOGO SKIN_GLYPH "res\\SKIN\\unknown.png"
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
diff --git a/plugins/TabSRMM/sdkbuild.bat b/plugins/TabSRMM/sdkbuild.bat
new file mode 100644
index 0000000000..4f8d762dbd
--- /dev/null
+++ b/plugins/TabSRMM/sdkbuild.bat
@@ -0,0 +1,13 @@
+@echo off
+
+echo * *
+echo ------------------------------------------------
+echo build tabSRMM with vcbuild.exe from Windows SDK
+echo requires a Windows PSDK (Version 7 or later)
+echo must be run from the SDK cmd shell with properly
+echo configured environment.
+echo ------------------------------------------------
+echo * *
+
+vcbuild.exe tabsrmm_9.vcproj "Release Unicode" /platform:Win32 /r
+vcbuild.exe tabsrmm_9.vcproj "Release Unicode" /platform:x64 /r
diff --git a/plugins/TabSRMM/skin/Back1.png b/plugins/TabSRMM/skin/Back1.png
new file mode 100644
index 0000000000..a26787c4ce
--- /dev/null
+++ b/plugins/TabSRMM/skin/Back1.png
Binary files differ
diff --git a/plugins/TabSRMM/skin/Back1Inactive.png b/plugins/TabSRMM/skin/Back1Inactive.png
new file mode 100644
index 0000000000..d68a175f2f
--- /dev/null
+++ b/plugins/TabSRMM/skin/Back1Inactive.png
Binary files differ
diff --git a/plugins/TabSRMM/skin/button.png b/plugins/TabSRMM/skin/button.png
new file mode 100644
index 0000000000..5b7e36fdc8
--- /dev/null
+++ b/plugins/TabSRMM/skin/button.png
Binary files differ
diff --git a/plugins/TabSRMM/skin/button_hover.png b/plugins/TabSRMM/skin/button_hover.png
new file mode 100644
index 0000000000..42978749e3
--- /dev/null
+++ b/plugins/TabSRMM/skin/button_hover.png
Binary files differ
diff --git a/plugins/TabSRMM/skin/buttonpressed.png b/plugins/TabSRMM/skin/buttonpressed.png
new file mode 100644
index 0000000000..db0212b6e9
--- /dev/null
+++ b/plugins/TabSRMM/skin/buttonpressed.png
Binary files differ
diff --git a/plugins/TabSRMM/skin/close.ico b/plugins/TabSRMM/skin/close.ico
new file mode 100644
index 0000000000..ddb5404bd0
--- /dev/null
+++ b/plugins/TabSRMM/skin/close.ico
Binary files differ
diff --git a/plugins/TabSRMM/skin/frames.png b/plugins/TabSRMM/skin/frames.png
new file mode 100644
index 0000000000..b14d31079b
--- /dev/null
+++ b/plugins/TabSRMM/skin/frames.png
Binary files differ
diff --git a/plugins/TabSRMM/skin/maximize.ico b/plugins/TabSRMM/skin/maximize.ico
new file mode 100644
index 0000000000..0aa6781335
--- /dev/null
+++ b/plugins/TabSRMM/skin/maximize.ico
Binary files differ
diff --git a/plugins/TabSRMM/skin/minimize.ico b/plugins/TabSRMM/skin/minimize.ico
new file mode 100644
index 0000000000..dad985d2c2
--- /dev/null
+++ b/plugins/TabSRMM/skin/minimize.ico
Binary files differ
diff --git a/plugins/TabSRMM/skin/panel.png b/plugins/TabSRMM/skin/panel.png
new file mode 100644
index 0000000000..e9c66e74cd
--- /dev/null
+++ b/plugins/TabSRMM/skin/panel.png
Binary files differ
diff --git a/plugins/TabSRMM/skin/tab.png b/plugins/TabSRMM/skin/tab.png
new file mode 100644
index 0000000000..908a3862c9
--- /dev/null
+++ b/plugins/TabSRMM/skin/tab.png
Binary files differ
diff --git a/plugins/TabSRMM/skin/tabhover.png b/plugins/TabSRMM/skin/tabhover.png
new file mode 100644
index 0000000000..b520898d54
--- /dev/null
+++ b/plugins/TabSRMM/skin/tabhover.png
Binary files differ
diff --git a/plugins/TabSRMM/skin/tabsrmm.tsk b/plugins/TabSRMM/skin/tabsrmm.tsk
new file mode 100644
index 0000000000..95db064216
--- /dev/null
+++ b/plugins/TabSRMM/skin/tabsrmm.tsk
@@ -0,0 +1,530 @@
+; skinning tabSRMM - how it works
+; this is a sample skin definition file for tabSRMM. It needs tabSRMM 0.9.9.99
+; or later
+
+; tabSRMM skin files are simple .ini - style text files. You can use any text
+; editor you want to edit them.
+
+; image path names are *RELATIVE* to the directory in which the skin file is
+; located. The best way is to put all images and this skin definition file
+; into a single directory.
+
+; The FORMAT
+; ==========
+
+; there are basically 2 types of entries in this file.
+
+; 1) item definitions
+; 2) image items
+
+; Item definitions MUST start with a % character and the name must be one of
+; the rcognized item names. Currently, tabsrmm knows the following item types:
+
+; items which are not configured in the skin definition file are ignored by
+; the skinning engine (that is, these items are then rendered unskinned)
+
+; The following items are known at the moment:
+
+; Container -> container background
+; Button
+; Buttonpressed
+; Buttonmouseover
+; Infopanelfield
+; Titlebutton
+; Titlebuttonpressed
+; Titlebuttonmouseover
+; Tabpage
+; Tabitem
+; Tabitem_bottom
+; Tabitem_active
+; Tabitem_active_bottom
+; MessageLog -> can be used to define a frame around the message log area
+; InputArea -> same for the input box.
+; Frame -> Window Frame (titlebar + border)
+
+; Item records contain information about the item itself. It offers similar options
+; like the skinning sytem in clist_nicer+
+
+; COLOR1: First color
+; COLOR2: 2nd color
+; TEXTCOLOR: color for the text - note only useful for a few items like buttons. The text
+; color for Tab items can be set in tabSRMM directly with more flexibility.
+; TOP/LEFT/RIGHT/BOTTOM: the item margins (in pixels)
+; ALPHA: The transparency value (alpha). Values go from 0 (completely transparent)
+; to 100 (completely opaque - values are therefore in PERCENT).
+; GRADIENT: Set this to one of "up", "down", "right", "left" (without the quotes) to
+; specify the gradient direction.
+; CORNER: A string which may contain the values "tl", "tr", "bl", "br" (again, w/o
+; quotes). Separate multiple entries by commas.
+; tl = top left, tr = top right, bl = bottom left, br = bottom right.
+; Example: Corner=tl,tr (will result in rounded corners for the top left and
+; top right corner).
+; COLOR2_TRANSPARENT: Set it to 1 if you want to have the 2nd color transparent, so that
+ the gradient will blend with the background.
+; RADIUS: A numeric value specifying the corner radius when rounded corners are used.
+
+; It is possible to skin only some items and leave the others unskinned. If a skin is laoded,
+; items which are left out by the skin definition will be rendered in a standard way, so
+; they will look like ordinary windows screen elements.
+
+; For more, see the examples below.
+
+[%Container]
+ALPHA=100
+COLOR1=DCDACE
+COLOR2=DCDACE
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=0
+GRADIENT=none
+RADIUS=0
+
+[%Statusbarpanel]
+ALPHA=80
+COLOR1=9C9D92
+COLOR2=9C9D92
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=None
+GRADIENT=None
+
+[%InputArea]
+ALPHA=10
+COLOR1=9C9D92
+COLOR2=9C9D92
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=None
+GRADIENT=None
+Left=1
+Right=1
+Top=1
+Bottom=1
+
+[%MessageLog]
+ALPHA=100
+COLOR1=9C9D92
+COLOR2=9C9D92
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=None
+GRADIENT=None
+Left=1
+Right=1
+Top=1
+Bottom=1
+
+[%Frame]
+ALPHA=100
+COLOR1=202020
+COLOR2=808080
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=0
+GRADIENT=right
+RADIUS=0
+
+[%FrameInactive]
+ALPHA=100
+COLOR1=202020
+COLOR2=808080
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=0
+GRADIENT=right
+RADIUS=0
+
+; This is a special Item. %Default is read automatically and its values
+; are used as defaults when reading the other skin items later. With %Default, you
+; can set fallback values.
+
+[%Default]
+ALPHA=100
+COLOR1=ffffff
+COLOR2=ffffff
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=None
+GRADIENT=None
+BOTTOM=2
+LEFT=2
+RIGHT=2
+TOP=2
+BRDERSTYLE=0
+
+[%Tabpage]
+ALPHA=30
+COLOR1=cccccc
+COLOR2=cccccc
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=None
+GRADIENT=None
+BRDERSTYLE=0
+
+[%Tabitem_active_bottom]
+ALPHA=70
+COLOR1=cccccc
+COLOR2=a0a0a0
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=none
+GRADIENT=up
+radius=12
+
+[%Tabitem_bottom]
+ALPHA=70
+COLOR1=cccccc
+COLOR2=a0a0a0
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=none
+GRADIENT=up
+radius=12
+
+[%Tabitem_active]
+ALPHA=70
+COLOR1=f0f0f0
+COLOR2=e0e0e0
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=tl,tr
+GRADIENT=down
+radius=6
+
+[%Tabitem]
+ALPHA=70
+COLOR1=f0f0f0
+COLOR2=e0e0e0
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=tl,tr
+GRADIENT=up
+radius=6
+
+[%Tabitem_hottrack]
+ALPHA=100
+COLOR1=f0f0f0
+COLOR2=e0e0e0
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=tl,tr
+GRADIENT=up
+radius=6
+
+[%Tabitem_hottrack_bottom]
+ALPHA=100
+COLOR1=f0f0f0
+COLOR2=e0e0e0
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=tl,tr
+GRADIENT=up
+radius=6
+
+[%Buttonnotpressed]
+ALPHA=100
+COLOR1=bbbbbb
+COLOR2=dddddd
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=none
+GRADIENT=down
+RADIUS=6
+
+[%Buttonpressed]
+ALPHA=100
+COLOR1=888888
+COLOR2=888888
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=none
+GRADIENT=none
+RADIUS=6
+
+[%Buttonmouseover]
+ALPHA=100
+COLOR1=888888
+COLOR2=888888
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=tl,tr,br,bl
+GRADIENT=none
+RADIUS=6
+
+[%InfoPanelfield]
+ALPHA=100
+COLOR1=e0e0e0
+COLOR2=ffffff
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=tl,tr,br,bl
+GRADIENT=left
+RADIUS=8
+top=1
+bottom=1
+
+
+[%Titlebutton]
+ALPHA=100
+COLOR1=e8f1f8
+COLOR2=8faec6
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=none
+GRADIENT=down
+RADIUS=6
+
+[%Titlebuttonmouseover]
+ALPHA=100
+COLOR1=ecf5ff
+COLOR2=9fbed6
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=none
+GRADIENT=down
+RADIUS=6
+
+[%Titlebuttonpressed]
+ALPHA=100
+COLOR1=e8f1f8
+COLOR2=8faec6
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=none
+GRADIENT=down
+RADIUS=6
+
+[%Toolbar]
+ALPHA=100
+COLOR1=aaaaaa
+COLOR2=666666
+COLOR2_TRANSPARENT=0
+TEXTCOLOR=202020
+CORNER=tl,tr,br,bl
+GRADIENT=down
+RADIUS=6
+
+; 2. Image items
+; --------------
+;
+; image items are separated from the normal item definitions. This allows to
+; use a single image for multiple items. Images are optional, because the skinning
+; engine can work without them and draw skin items in a traditional way, using gradients
+; and such.
+;
+; images HAVE to be 32bit PNG images - other formats are not supported.
+; They can be ; partially transparent using per-pixel alpha values.
+;
+; imgdecoder.dll is REQUIRED and must be either in the \plugins or
+; mirandas main folder
+;
+; Image item definitions MUST start with a $ character. The name is free - you can use
+; any name you want.
+;
+; sizing margins:
+;
+; sizing margins have to be specified as Left, Right, Top and Bottom. These margins
+; divide the image into 9 parts. The corner parts are rendered without stretching
+; or shrinking, other parts of the image are stretched to make it fit the target
+; area. Sizing margins are only valid and used when ALL 4 margin values are specified.
+;
+; ALPHA is a constant alpha value which is applied AFTER per pixel alpha values- this
+; can be used to make a non-transparent image translucent. Alpha values are in percent,
+; so the valid range is from 0 (completely transparent) to 100 (completely opaque).
+;
+; assign images to actual skin item(s).
+;
+; This is done with the ItemX=Itemname value. X is a 0-based index number, so the first
+; assignment has to be Item0=foo, the 2nd Item1=bar and so on. Itemname refers to one of
+; the skin item names listed at the beginning of this document, WITHOUT the % character.
+;
+; ColorKey
+; this is a special color value which will be used to make areas of the containe transparent
+; (e.g. it can be used for rounded corners). The color key can be any value you want, but
+; remember that any pixel with this color will appear completely transparent.
+; the color key DOES ONLY MAKE SENSE for the container skin item and is ignored elsewhere.
+;
+; FillColor
+; This is a color value, which, if present, will be used to fill the inner part of the
+; target area. You can use this if you only "need" the margin areas of the image (one example
+; would be the Tabpage which is usually invisible (covered by the message log and other
+; message window elements). The advantage is that by using a fill color, rendering will
+; be faster. Only makes sense for a "divided" image item (all 4 sizing margins present).
+
+[$Tabitem]
+Image=tab.png
+Right=2
+Top=2
+Bottom=2
+Left=2
+Alpha=60
+Item0=Tabitem_bottom
+Item1=Tabitem_active_bottom
+Item2=Tabitem
+Item3=Tabitem_active
+Perpixel=1
+
+[$Tabitem_hover]
+Image=tabhover.png
+Right=2
+Top=2
+Bottom=2
+Left=2
+Alpha=60
+Item0=Tabitem_hottrack_bottom
+Item1=Tabitem_hottrack
+Perpixel=1
+
+[$Button]
+Image=button.png
+Right=3
+Top=3
+Bottom=3
+Left=3
+Alpha=60
+Item0=Buttonnotpressed
+Item1=Frame
+Perpixel=1
+
+[$Panel]
+Image=panel.png
+Right=2
+Top=2
+Bottom=2
+Left=2
+Alpha=60
+Item0=Statusbarpanel
+Perpixel=1
+
+[$Buttonhover]
+Image=button_hover.png
+Right=2
+Top=2
+Bottom=1
+Left=2
+Alpha=60
+Item0=Buttonmouseover
+Perpixel=1
+
+[$Buttonpressed]
+Image=buttonpressed.png
+Right=3
+Top=3
+Bottom=3
+Left=3
+Alpha=50
+Item0=Buttonpressed
+Item1=Infopanelfield
+Perpixel=1
+
+[$Frame]
+Image=Back1.png
+Right=8
+Top=26
+Bottom=8
+Left=8
+Alpha=100
+Item0=Frame
+FillColor=202020
+
+[$FrameInactive]
+Image=Back1Inactive.png
+Right=8
+Top=26
+Bottom=8
+Left=8
+Alpha=100
+Item0=FrameInactive
+FillColor=202020
+
+
+;[$EditFrame]
+;Image=TextBorder.png
+;Left=8
+;Right=8
+;Top=8
+;Bottom=8
+;Alpha=100
+;Item0=InputArea
+;Item1=MessageLog
+;FillColor=D4D4D4
+
+; the global section has some general settings for the skin.
+; the 3 glyphs are used for the min/max/close button on the title bar. Use icons for this
+; and put them in the skin directory.
+
+; SbarHeight = height of the status bar in pixels. Using this, you can override the systems
+; default status bar height and make your status bar "match" the background skin image for
+; the container window
+
+; FontColor is the color for text output in the message window which is normally printed
+; with the system text color (black).
+; this affects: the info panel labels, the status bar text, text on buttons and elsewhere.
+; Version=1 mandatory, don't remove or change, or the skin won't load !!!
+; Signature=101 same - don't remove or change. !!!
+
+; FrameLessMode If set to a value not equal to zero, containers will enter frameless mode.
+; That means, they do not have a window border or title bar. The entire back-
+; ground is then skinned by the container window background skin.
+;
+; TitlebuttonWidth & TitlebuttonHeight -> metrics for the titlebar buttons (minimize, maximize, close)
+; only used when FramelessMode = 1 and Frame skin item is valid
+; TabSkinning -> Set to 0 if you want tabs to appear with default look (visual styles)
+; default is 1 (so they will appear with the skins defined in this file
+; if no skins are defined, they will appear in "classic" look
+
+[Global]
+CloseGlyph=close.ico
+MinimizeGlyph=minimize.ico
+MaximizeGlyph=maximize.ico
+SbarHeight=22
+FontColor=0000BB
+Version=1
+Signature=101
+FrameLessMode=0
+TabSkinning=1
+LightShadow=F4F4F1
+DarkShadow=B0ACA0
+TabTextNormal=CCCC00
+TabTextActive=0000BB
+TabTextUnread=BB0000
+TabTextHottrack=00bb00
+
+; client area metrics
+;
+; Left, right, top and bottom are the padding values for the client area. The values are in pixels
+; and specify how much space will be left blank between the tab page and the window border
+
+; The "inner" value specifies how much of the tab page will be visible
+
+[ClientArea]
+Left=2
+Right=2
+Top=3
+Bottom=0
+Inner=1
+
+; Width of the window frame (only valid, when FrameLessMode = 1 and a valid skin item for the Frame
+; is available.
+; caption = height of the title bar.
+; clip frame = # of pixels clipped from the outer frame
+; Radius = radius of the rounded corners (usable values are from 8-12, don't set them higher, may
+; look strange.
+
+[WindowFrame]
+Left=4
+Right=4
+Bottom=4
+Caption=22
+ClipFrame=1
+RadiusTL=6
+TitleButtonWidth = 12
+TitleButtonHeight = 12
+TitleButtonTopOffset = 7
+CaptionOffset = 6
+
+[Avatars]
+BorderType=4
+BorderColor=202020
+
diff --git a/plugins/TabSRMM/skin/textborder.png b/plugins/TabSRMM/skin/textborder.png
new file mode 100644
index 0000000000..61af9e959b
--- /dev/null
+++ b/plugins/TabSRMM/skin/textborder.png
Binary files differ
diff --git a/plugins/TabSRMM/src/ImageDataObject.cpp b/plugins/TabSRMM/src/ImageDataObject.cpp
new file mode 100644
index 0000000000..762dbba537
--- /dev/null
+++ b/plugins/TabSRMM/src/ImageDataObject.cpp
@@ -0,0 +1,215 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * *
+ * $Id: ImageDataObject.cpp 11611 2010-04-22 12:36:29Z silvercircle $
+ *
+ * This inserts a bitmap into a rich edit control using OLE
+ * code partially taken from public example on the internet, source unknown.
+ *
+ * originally part of the smileyadd plugin for Miranda IM
+ *
+ */
+
+#include "commonheaders.h"
+#include "../include/ImageDataObject.h"
+
+extern void ReleaseRichEditOle(IRichEditOle *ole)
+{
+ ole->Release();
+}
+
+extern void ImageDataInsertBitmap(IRichEditOle *ole, HBITMAP hBm)
+{
+ CImageDataObject::InsertBitmap(ole, hBm);
+}
+
+int CacheIconToBMP(struct TLogIcon *theIcon, HICON hIcon, COLORREF backgroundColor, int sizeX, int sizeY)
+{
+ bool succeeded = false;
+
+ int IconSizeX = sizeX;
+ int IconSizeY = sizeY;
+
+ if ((IconSizeX == 0) || (IconSizeY == 0)) {
+ Utils::getIconSize(hIcon, IconSizeX, IconSizeY);
+ if (sizeX != 0)
+ IconSizeX = sizeX;
+ if (sizeY != 0)
+ IconSizeY = sizeY;
+ }
+ RECT rc;
+ BITMAPINFOHEADER bih = {0};
+ int widthBytes;
+ theIcon->hBkgBrush = CreateSolidBrush(backgroundColor);
+ bih.biSize = sizeof(bih);
+ bih.biBitCount = 24;
+ bih.biPlanes = 1;
+ bih.biCompression = BI_RGB;
+ bih.biHeight = IconSizeY;
+ bih.biWidth = IconSizeX;
+ widthBytes = ((bih.biWidth * bih.biBitCount + 31) >> 5) * 4;
+ rc.top = rc.left = 0;
+ rc.right = bih.biWidth;
+ rc.bottom = bih.biHeight;
+ theIcon->hdc = GetDC(0);
+ theIcon->hBmp = CreateCompatibleBitmap(theIcon->hdc, bih.biWidth, bih.biHeight);
+ theIcon->hdcMem = CreateCompatibleDC(theIcon->hdc);
+ theIcon->hoBmp = (HBITMAP)SelectObject(theIcon->hdcMem, theIcon->hBmp);
+ FillRect(theIcon->hdcMem, &rc, theIcon->hBkgBrush);
+ DrawIconEx(theIcon->hdcMem, 0, 0, hIcon, bih.biWidth, bih.biHeight, 0, NULL, DI_NORMAL);
+ SelectObject(theIcon->hdcMem, theIcon->hoBmp);
+ return TRUE;
+}
+
+void DeleteCachedIcon(struct TLogIcon *theIcon)
+{
+ DeleteDC(theIcon->hdcMem);
+ DeleteObject(theIcon->hBmp);
+ ReleaseDC(NULL, theIcon->hdc);
+ DeleteObject(theIcon->hBkgBrush);
+}
+
+// returns true on success, false on failure
+bool CImageDataObject::InsertBitmap(IRichEditOle* pRichEditOle, HBITMAP hBitmap)
+{
+ SCODE sc;
+ BITMAP bminfo;
+
+ // Get the image data object
+ //
+ CImageDataObject *pods = new CImageDataObject;
+ LPDATAOBJECT lpDataObject;
+ pods->QueryInterface(IID_IDataObject, (void **)&lpDataObject);
+
+ GetObject(hBitmap, sizeof(bminfo), &bminfo);
+ pods->SetBitmap(hBitmap);
+
+ // Get the RichEdit container site
+ //
+ IOleClientSite *pOleClientSite;
+ pRichEditOle->GetClientSite(&pOleClientSite);
+
+ // Initialize a Storage Object
+ //
+ IStorage *pStorage;
+
+ LPLOCKBYTES lpLockBytes = NULL;
+ sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
+ if (sc != S_OK) {
+ pOleClientSite->Release();
+ return false;
+ }
+ sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
+ STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE, 0, &pStorage);
+ if (sc != S_OK) {
+ lpLockBytes = NULL;
+ pOleClientSite->Release();
+ return false;
+ }
+ // The final ole object which will be inserted in the richedit control
+ //
+ IOleObject *pOleObject;
+ pOleObject = pods->GetOleObject(pOleClientSite, pStorage);
+ if (pOleObject == NULL) {
+ pStorage->Release();
+ pOleClientSite->Release();
+ return false;
+ }
+
+ // all items are "contained" -- this makes our reference to this object
+ // weak -- which is needed for links to embedding silent update.
+ OleSetContainedObject(pOleObject, TRUE);
+
+ // Now Add the object to the RichEdit
+ //
+ REOBJECT reobject;
+ ZeroMemory(&reobject, sizeof(REOBJECT));
+ reobject.cbStruct = sizeof(REOBJECT);
+
+ CLSID clsid;
+ sc = pOleObject->GetUserClassID(&clsid);
+ if (sc != S_OK) {
+ pOleObject->Release();
+ pStorage->Release();
+ pOleClientSite->Release();
+ return false;
+ }
+
+ reobject.clsid = clsid;
+ reobject.cp = REO_CP_SELECTION ;
+ reobject.dvaspect = DVASPECT_CONTENT;
+ reobject.poleobj = pOleObject;
+ reobject.polesite = pOleClientSite;
+ reobject.pstg = pStorage;
+ reobject.dwFlags = bminfo.bmHeight <= 12 ? 0 : REO_BELOWBASELINE;
+
+ // Insert the bitmap at the current location in the richedit control
+ //
+ sc = pRichEditOle->InsertObject(&reobject);
+
+ // Release all unnecessary interfaces
+ //
+ pOleObject->Release();
+ pOleClientSite->Release();
+ lpLockBytes->Release();
+ pStorage->Release();
+ lpDataObject->Release();
+ if (sc != S_OK)
+ return false;
+ else
+ return true;
+}
+
+
+void CImageDataObject::SetBitmap(HBITMAP hBitmap)
+{
+ STGMEDIUM stgm;
+ stgm.tymed = TYMED_GDI; // Storage medium = HBITMAP handle
+ stgm.hBitmap = hBitmap;
+ stgm.pUnkForRelease = NULL; // Use ReleaseStgMedium
+
+ FORMATETC fm;
+ fm.cfFormat = CF_BITMAP; // Clipboard format = CF_BITMAP
+ fm.ptd = NULL; // Target Device = Screen
+ fm.dwAspect = DVASPECT_CONTENT; // Level of detail = Full content
+ fm.lindex = -1; // Index = Not applicaple
+ fm.tymed = TYMED_GDI; // Storage medium = HBITMAP handle
+
+ this->SetData(&fm, &stgm, TRUE);
+}
+
+
+IOleObject *CImageDataObject::GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage)
+{
+ SCODE sc;
+ IOleObject *pOleObject;
+ sc = ::OleCreateStaticFromData(this, IID_IOleObject, OLERENDER_FORMAT,
+ &m_format, pOleClientSite, pStorage, (void **) & pOleObject);
+ if (sc != S_OK)
+ pOleObject = NULL;
+ return pOleObject;
+}
diff --git a/plugins/TabSRMM/src/TSButton.cpp b/plugins/TabSRMM/src/TSButton.cpp
new file mode 100644
index 0000000000..57c3221f38
--- /dev/null
+++ b/plugins/TabSRMM/src/TSButton.cpp
@@ -0,0 +1,738 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: TSButton.cpp 11848 2010-05-27 14:57:22Z silvercircle $
+ *
+ * A skinnable button class for tabSRMM.
+ *
+ */
+
+#include "commonheaders.h"
+#include <ctype.h>
+
+#define PBS_PUSHDOWNPRESSED 6
+
+static LRESULT CALLBACK TSButtonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// External theme methods and properties
+
+static CRITICAL_SECTION csTips;
+static HWND hwndToolTips = NULL;
+static BLENDFUNCTION bf_buttonglyph;
+static HDC hdc_buttonglyph = 0;
+static HBITMAP hbm_buttonglyph, hbm_buttonglyph_old;
+
+// Used for our own cheap TrackMouseEvent
+#define BUTTON_POLLID 100
+#define BUTTON_POLLDELAY 50
+
+#define MGPROC(x) GetProcAddress(themeAPIHandle,x)
+
+int TSAPI UnloadTSButtonModule()
+{
+ DeleteCriticalSection(&csTips);
+ if (hdc_buttonglyph) {
+ SelectObject(hdc_buttonglyph, hbm_buttonglyph_old);
+ DeleteObject(hbm_buttonglyph);
+ DeleteDC(hdc_buttonglyph);
+ }
+ return 0;
+}
+
+int TSAPI LoadTSButtonModule(void)
+{
+ WNDCLASSEX wc;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = _T("TSButtonClass");
+ wc.lpfnWndProc = TSButtonWndProc;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(MButtonCtrl*);
+ wc.hbrBackground = 0;
+ wc.style = CS_GLOBALCLASS | CS_PARENTDC;
+ RegisterClassEx(&wc);
+ InitializeCriticalSection(&csTips);
+ return 0;
+}
+
+static void TSAPI DestroyTheme(MButtonCtrl *ctl)
+{
+ if (M->isVSAPIState()) {
+ if (ctl->hThemeButton) {
+ CMimAPI::m_pfnCloseThemeData(ctl->hThemeButton);
+ ctl->hThemeButton = NULL;
+ }
+ if (ctl->hThemeToolbar) {
+ CMimAPI::m_pfnCloseThemeData(ctl->hThemeToolbar);
+ ctl->hThemeToolbar = NULL;
+ }
+ }
+}
+
+static void TSAPI LoadTheme(MButtonCtrl *ctl)
+{
+ if (M->isVSAPIState()) {
+ DestroyTheme(ctl);
+ ctl->hThemeButton = CMimAPI::m_pfnOpenThemeData(ctl->hwnd, L"BUTTON");
+ ctl->hThemeToolbar = (M->isAero() || IsWinVerVistaPlus()) ? CMimAPI::m_pfnOpenThemeData(ctl->hwnd, L"MENU") : CMimAPI::m_pfnOpenThemeData(ctl->hwnd, L"TOOLBAR");
+ ctl->bThemed = TRUE;
+ }
+}
+
+int TSAPI TBStateConvert2Flat(int state)
+{
+ switch (state) {
+ case PBS_NORMAL:
+ return TS_NORMAL;
+ case PBS_HOT:
+ return TS_HOT;
+ case PBS_PRESSED:
+ return TS_PRESSED;
+ case PBS_DISABLED:
+ return TS_DISABLED;
+ case PBS_DEFAULTED:
+ return TS_NORMAL;
+ }
+ return TS_NORMAL;
+}
+
+
+/**
+ * convert button state (hot, pressed, normal) to REBAR part state ids
+ *
+ * @param state int: button state
+ *
+ * @return int: state item id
+ */
+int TSAPI RBStateConvert2Flat(int state)
+{
+ switch (state) {
+ case PBS_NORMAL:
+ return 1;
+ case PBS_HOT:
+ return 2;
+ case PBS_PRESSED:
+ return 3;
+ case PBS_DISABLED:
+ return 1;
+ case PBS_DEFAULTED:
+ return 1;
+ }
+ return 1;
+}
+
+static void PaintWorker(MButtonCtrl *ctl, HDC hdcPaint)
+{
+ if (hdc_buttonglyph == 0) {
+ hdc_buttonglyph = CreateCompatibleDC(hdcPaint);
+ hbm_buttonglyph = CreateCompatibleBitmap(hdcPaint, 16, 16);
+ hbm_buttonglyph_old = (HBITMAP)SelectObject(hdc_buttonglyph, hbm_buttonglyph);
+ bf_buttonglyph.BlendFlags = 0;
+ bf_buttonglyph.SourceConstantAlpha = 120;
+ bf_buttonglyph.BlendOp = AC_SRC_OVER;
+ bf_buttonglyph.AlphaFormat = 0;
+ }
+ if (hdcPaint) {
+ HDC hdcMem;
+ HBITMAP hbmMem, hOld;
+ RECT rcClient;
+ RECT rcContent;
+ bool fAero = M->isAero();
+ bool fVSThemed = (!CSkin::m_skinEnabled && M->isVSThemed());
+ HANDLE hbp = 0;
+
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(GetParent(ctl->hwnd), GWLP_USERDATA);
+ GetClientRect(ctl->hwnd, const_cast<RECT *>(&rcClient));
+ CopyRect(&rcContent, &rcClient);
+
+ if(CMimAPI::m_haveBufferedPaint)
+ hbp = CMimAPI::m_pfnBeginBufferedPaint(hdcPaint, &rcContent, BPBF_TOPDOWNDIB, NULL, &hdcMem);
+ else {
+ hdcMem = CreateCompatibleDC(hdcPaint);
+ hbmMem = CreateCompatibleBitmap(hdcPaint, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
+ hOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
+ }
+
+ CSkin::FillBack(hdcMem, &rcContent);
+
+ if (ctl->pushBtn && ctl->pbState)
+ ctl->stateId = PBS_PRESSED;
+
+ if (ctl->flatBtn) {
+ if (ctl->pContainer && CSkin::m_skinEnabled) {
+ CSkinItem *item, *realItem = 0;
+ if (ctl->bTitleButton)
+ item = &SkinItems[ctl->stateId == PBS_NORMAL ? ID_EXTBKTITLEBUTTON : (ctl->stateId == PBS_HOT ? ID_EXTBKTITLEBUTTONMOUSEOVER : ID_EXTBKTITLEBUTTONPRESSED)];
+ else {
+ item = &SkinItems[(ctl->stateId == PBS_NORMAL || ctl->stateId == PBS_DISABLED) ? ID_EXTBKBUTTONSNPRESSED : (ctl->stateId == PBS_HOT ? ID_EXTBKBUTTONSMOUSEOVER : ID_EXTBKBUTTONSPRESSED)];
+ realItem = item;
+ }
+ CSkin::SkinDrawBG(ctl->hwnd, ctl->pContainer->hwnd, ctl->pContainer, &rcContent, hdcMem);
+ if (!item->IGNORED) {
+ RECT rc1 = rcClient;
+ rc1.left += item->MARGIN_LEFT;
+ rc1.right -= item->MARGIN_RIGHT;
+ rc1.top += item->MARGIN_TOP;
+ rc1.bottom -= item->MARGIN_BOTTOM;
+ CSkin::DrawItem(hdcMem, &rc1, item);
+ } else
+ goto flat_themed;
+ } else {
+flat_themed:
+ int state = IsWindowEnabled(ctl->hwnd) ? (ctl->stateId == PBS_NORMAL && ctl->defbutton ? PBS_DEFAULTED : ctl->stateId) : PBS_DISABLED;
+
+ if (ctl->bToolbarButton) {
+ if(dat) {
+ RECT rcWin;
+ GetWindowRect(ctl->hwnd, &rcWin);
+ POINT pt;
+ pt.x = rcWin.left;
+ ScreenToClient(dat->hwnd, &pt);
+ BitBlt(hdcMem, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
+ dat->pContainer->cachedToolbarDC, pt.x, 1, SRCCOPY);
+ }
+ }
+ if (ctl->hThemeToolbar && ctl->bThemed && 1 == dat->pContainer->bTBRenderingMode) {
+ if(fAero || PluginConfig.m_WinVerMajor >= 6)
+ CMimAPI::m_pfnDrawThemeBackground(ctl->hThemeToolbar, hdcMem, 8, RBStateConvert2Flat(state), &rcClient, &rcClient);
+ else
+ CMimAPI::m_pfnDrawThemeBackground(ctl->hThemeToolbar, hdcMem, TP_BUTTON, TBStateConvert2Flat(state), &rcClient, &rcClient);
+ } else {
+ CSkin::m_switchBarItem->setAlphaFormat(AC_SRC_ALPHA, state == PBS_HOT ? 220 : 180);
+ if(state == PBS_HOT || state == PBS_PRESSED) {
+ if(state == PBS_PRESSED) {
+ RECT rc = rcClient;
+ InflateRect(&rc, -1, -1);
+ HBRUSH bBack = CreateSolidBrush(PluginConfig.m_tbBackgroundLow ? PluginConfig.m_tbBackgroundLow : GetSysColor(COLOR_3DDKSHADOW));
+ FillRect(hdcMem, &rc, bBack);
+ DeleteObject(bBack);
+ }
+ CSkin::m_switchBarItem->Render(hdcMem, &rcClient, true);
+ }
+ }
+ }
+ } else {
+ if (ctl->pContainer && CSkin::m_skinEnabled) {
+ CSkinItem *item, *realItem = 0;
+ if (ctl->bTitleButton)
+ item = &SkinItems[ctl->stateId == PBS_NORMAL ? ID_EXTBKTITLEBUTTON : (ctl->stateId == PBS_HOT ? ID_EXTBKTITLEBUTTONMOUSEOVER : ID_EXTBKTITLEBUTTONPRESSED)];
+ else {
+ item = &SkinItems[(ctl->stateId == PBS_NORMAL || ctl->stateId == PBS_DISABLED) ? ID_EXTBKBUTTONSNPRESSED : (ctl->stateId == PBS_HOT ? ID_EXTBKBUTTONSMOUSEOVER : ID_EXTBKBUTTONSPRESSED)];
+ realItem = item;
+ }
+ CSkin::SkinDrawBG(ctl->hwnd, ctl->pContainer->hwnd, ctl->pContainer, &rcClient, hdcMem);
+ if (!item->IGNORED) {
+ RECT rc1 = rcClient;
+ rc1.left += item->MARGIN_LEFT;
+ rc1.right -= item->MARGIN_RIGHT;
+ rc1.top += item->MARGIN_TOP;
+ rc1.bottom -= item->MARGIN_BOTTOM;
+ CSkin::DrawItem(hdcMem, &rc1, item);
+ } else
+ goto nonflat_themed;
+ } else {
+nonflat_themed:
+ int state = IsWindowEnabled(ctl->hwnd) ? (ctl->stateId == PBS_NORMAL && ctl->defbutton ? PBS_DEFAULTED : ctl->stateId) : PBS_DISABLED;
+
+ if (ctl->hThemeButton && ctl->bThemed && 0 == PluginConfig.m_fillColor) {
+ CMimAPI::m_pfnDrawThemeBackground(ctl->hThemeButton, hdcMem, BP_PUSHBUTTON, state, &rcClient, &rcClient);
+ CMimAPI::m_pfnGetThemeBackgroundContentRect(ctl->hThemeToolbar, hdcMem, BP_PUSHBUTTON, PBS_NORMAL, &rcClient, &rcContent);
+ } else {
+ CSkin::m_switchBarItem->setAlphaFormat(AC_SRC_ALPHA, state == PBS_NORMAL ? 140 : 240);
+ if(state == PBS_PRESSED) {
+ RECT rc = rcClient;
+ InflateRect(&rc, -1, -1);
+ HBRUSH bBack = CreateSolidBrush(PluginConfig.m_tbBackgroundLow ? PluginConfig.m_tbBackgroundLow : GetSysColor(COLOR_3DDKSHADOW));
+ FillRect(hdcMem, &rc, bBack);
+ DeleteObject(bBack);
+ }
+ CSkin::m_switchBarItem->Render(hdcMem, &rcClient, true);
+ }
+
+ // Draw focus rectangle if button has focus
+ if (ctl->focus) {
+ RECT focusRect = rcClient;
+ InflateRect(&focusRect, -3, -3);
+ DrawFocusRect(hdcMem, &focusRect);
+ }
+ }
+ }
+
+ /*
+ * render content
+ */
+ if (ctl->arrow) {
+ rcContent.top += 2;
+ rcContent.bottom -= 2;
+ rcContent.left = rcClient.right - 12;
+ rcContent.right = rcContent.left;
+
+ DrawIconEx(hdcMem, rcClient.right - 15, (rcClient.bottom - rcClient.top) / 2 - (PluginConfig.m_smcyicon / 2),
+ PluginConfig.g_buttonBarIcons[ICON_DEFAULT_PULLDOWN], 16, 16, 0, 0, DI_NORMAL);
+ }
+
+ if (ctl->hIcon || ctl->hIconPrivate) {
+ int ix = (rcClient.right - rcClient.left) / 2 - 8;
+ int iy = (rcClient.bottom - rcClient.top) / 2 - 8;
+ HICON hIconNew = ctl->hIconPrivate != 0 ? ctl->hIconPrivate : ctl->hIcon;
+
+ if (ctl->stateId == PBS_PRESSED) {
+ ix++;
+ iy++;
+ }
+
+ if (ctl->arrow)
+ ix -= 4;
+
+ if (ctl->dimmed && PluginConfig.m_IdleDetect)
+ CSkin::DrawDimmedIcon(hdcMem, ix, iy, PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, hIconNew, 180);
+ else {
+ if (ctl->stateId != PBS_DISABLED || CMimAPI::m_MyAlphaBlend == 0) {
+ DrawIconEx(hdcMem, ix, iy, hIconNew, 16, 16, 0, 0, DI_NORMAL);
+ if(ctl->overlay)
+ DrawIconEx(hdcMem, ix, iy, ctl->overlay, 16, 16, 0, 0, DI_NORMAL);
+ }
+ else {
+ BitBlt(hdc_buttonglyph, 0, 0, 16, 16, hdcMem, ix, iy, SRCCOPY);
+ DrawIconEx(hdc_buttonglyph, 0, 0, hIconNew, 16, 16, 0, 0, DI_NORMAL);
+ if(ctl->overlay)
+ DrawIconEx(hdc_buttonglyph, 0, 0, ctl->overlay, 16, 16, 0, 0, DI_NORMAL);
+ CMimAPI::m_MyAlphaBlend(hdcMem, ix, iy, PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, hdc_buttonglyph, 0, 0, 16, 16, bf_buttonglyph);
+ }
+ }
+ } else if (GetWindowTextLength(ctl->hwnd)) {
+ // Draw the text and optinally the arrow
+ TCHAR szText[MAX_PATH];
+ SIZE sz;
+ RECT rcText;
+ HFONT hOldFont;
+
+ CopyRect(&rcText, &rcClient);
+ GetWindowText(ctl->hwnd, szText, MAX_PATH - 1);
+ SetBkMode(hdcMem, TRANSPARENT);
+ hOldFont = (HFONT)SelectObject(hdcMem, ctl->hFont);
+ if (ctl->pContainer && CSkin::m_skinEnabled)
+ SetTextColor(hdcMem, IsWindowEnabled(ctl->hwnd) ? CSkin::m_DefaultFontColor : GetSysColor(COLOR_GRAYTEXT));
+ else {
+ if(PluginConfig.m_genericTxtColor)
+ SetTextColor(hdcMem, PluginConfig.m_genericTxtColor);
+ else
+ SetTextColor(hdcMem, IsWindowEnabled(ctl->hwnd) || !ctl->hThemeButton ? GetSysColor(COLOR_BTNTEXT) : GetSysColor(COLOR_GRAYTEXT));
+ }
+ GetTextExtentPoint32(hdcMem, szText, lstrlen(szText), &sz);
+ if (ctl->cHot) {
+ SIZE szHot;
+
+ GetTextExtentPoint32A(hdcMem, "&", 1, &szHot);
+ sz.cx -= szHot.cx;
+ }
+ if (ctl->arrow)
+ DrawState(hdcMem, NULL, NULL, (LPARAM)ctl->arrow, 0, rcClient.right - rcClient.left - 5 - PluginConfig.m_smcxicon + (!ctl->hThemeButton && ctl->stateId == PBS_PRESSED ? 1 : 0), (rcClient.bottom - rcClient.top) / 2 - PluginConfig.m_smcyicon / 2 + (!ctl->hThemeButton && ctl->stateId == PBS_PRESSED ? 1 : 0), PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, IsWindowEnabled(ctl->hwnd) ? DST_ICON : DST_ICON | DSS_DISABLED);
+ SelectObject(hdcMem, ctl->hFont);
+ DrawState(hdcMem, NULL, NULL, (LPARAM)szText, lstrlen(szText), (rcText.right - rcText.left - sz.cx) / 2 + (!ctl->hThemeButton && ctl->stateId == PBS_PRESSED ? 1 : 0), ctl->hThemeButton ? (rcText.bottom - rcText.top - sz.cy) / 2 : (rcText.bottom - rcText.top - sz.cy) / 2 - (ctl->stateId == PBS_PRESSED ? 0 : 1), sz.cx, sz.cy, IsWindowEnabled(ctl->hwnd) || ctl->hThemeButton ? DST_PREFIXTEXT | DSS_NORMAL : DST_PREFIXTEXT | DSS_DISABLED);
+ SelectObject(hdcMem, hOldFont);
+ }
+ if(hbp)
+ CMimAPI::m_pfnEndBufferedPaint(hbp, TRUE);
+ else {
+ BitBlt(hdcPaint, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hOld);
+ DeleteObject(hbmMem);
+ DeleteDC(hdcMem);
+ }
+
+ }
+}
+
+static LRESULT CALLBACK TSButtonWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MButtonCtrl* bct = (MButtonCtrl *)GetWindowLongPtr(hwndDlg, 0);
+ switch (msg) {
+ case WM_NCCREATE: {
+ SetWindowLongPtr(hwndDlg, GWL_STYLE, GetWindowLongPtr(hwndDlg, GWL_STYLE) | BS_OWNERDRAW);
+ bct = (MButtonCtrl *)malloc(sizeof(MButtonCtrl));
+ if (bct == NULL)
+ return FALSE;
+ ZeroMemory(bct, sizeof(MButtonCtrl));
+ bct->hwnd = hwndDlg;
+ bct->stateId = PBS_NORMAL;
+ bct->hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+ LoadTheme(bct);
+ SetWindowLongPtr(hwndDlg, 0, (LONG_PTR)bct);
+ if (((CREATESTRUCT *)lParam)->lpszName)
+ SetWindowText(hwndDlg, ((CREATESTRUCT *)lParam)->lpszName);
+ return TRUE;
+ }
+ case WM_DESTROY: {
+ if (bct) {
+ EnterCriticalSection(&csTips);
+ if (hwndToolTips) {
+ TOOLINFO ti;
+
+ ZeroMemory(&ti, sizeof(ti));
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = bct->hwnd;
+ ti.uId = (UINT_PTR)bct->hwnd;
+ if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
+ SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
+ }
+ if (SendMessage(hwndToolTips, TTM_GETTOOLCOUNT, 0, (LPARAM)&ti) == 0) {
+ DestroyWindow(hwndToolTips);
+ hwndToolTips = NULL;
+ }
+ }
+ if (bct->hIconPrivate)
+ DestroyIcon(bct->hIconPrivate);
+ LeaveCriticalSection(&csTips);
+ DestroyTheme(bct);
+ }
+ break; // DONT! fall thru
+ }
+
+ case WM_NCDESTROY:
+ free(bct);
+ SetWindowLongPtr(hwndDlg, 0, (LONG_PTR)NULL);
+ break;
+
+ case WM_SETTEXT: {
+ bct->cHot = 0;
+ if ((TCHAR *)lParam) {
+ TCHAR *tmp = (TCHAR *)lParam;
+ while (*tmp) {
+ if (*tmp == (TCHAR)'&' && *(tmp + 1)) {
+ bct->cHot = _totlower(*(tmp + 1));
+ break;
+ }
+ tmp++;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ }
+ case WM_KEYUP:
+ if (bct->stateId != PBS_DISABLED && wParam == VK_SPACE && !(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000)) {
+ if (bct->pushBtn) {
+ if (bct->pbState) bct->pbState = 0;
+ else bct->pbState = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM)hwndDlg);
+ return 0;
+ }
+ break;
+ case WM_SYSKEYUP:
+ if (bct->stateId != PBS_DISABLED && bct->cHot && bct->cHot == tolower((int)wParam)) {
+ if (bct->pushBtn) {
+ if (bct->pbState) bct->pbState = 0;
+ else bct->pbState = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM)hwndDlg);
+ return 0;
+ }
+ break;
+ case WM_THEMECHANGED: {
+ // themed changed, reload theme object
+ if (bct->bThemed)
+ LoadTheme(bct);
+ InvalidateRect(bct->hwnd, NULL, TRUE); // repaint it
+ break;
+ }
+ case WM_SETFONT: { // remember the font so we can use it later
+ bct->hFont = (HFONT)wParam; // maybe we should redraw?
+ break;
+ }
+ case WM_NCPAINT:
+ return(0);
+
+ case WM_PAINT: {
+ PAINTSTRUCT ps;
+ HDC hdcPaint;
+
+ hdcPaint = BeginPaint(hwndDlg, &ps);
+ if (hdcPaint) {
+ if(bct->sitem)
+ bct->sitem->RenderThis(hdcPaint);
+ else
+ PaintWorker(bct, hdcPaint);
+ EndPaint(hwndDlg, &ps);
+ }
+ return(0);
+ }
+ case BM_SETIMAGE:
+ if (wParam == IMAGE_ICON) {
+ ICONINFO ii;
+ BITMAP bm;
+
+ if (bct->hIconPrivate)
+ DestroyIcon(bct->hIconPrivate);
+
+ GetIconInfo((HICON)lParam, &ii);
+ GetObject(ii.hbmColor, sizeof(bm), &bm);
+ if (bm.bmWidth != PluginConfig.m_smcxicon || bm.bmHeight != PluginConfig.m_smcyicon) {
+ HIMAGELIST hImageList;
+ hImageList = ImageList_Create(PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, PluginConfig.m_bIsXP ? ILC_COLOR32 | ILC_MASK : ILC_COLOR16 | ILC_MASK, 1, 0);
+ ImageList_AddIcon(hImageList, (HICON)lParam);
+ bct->hIconPrivate = ImageList_GetIcon(hImageList, 0, ILD_NORMAL);
+ ImageList_RemoveAll(hImageList);
+ ImageList_Destroy(hImageList);
+ bct->hIcon = 0;
+ } else {
+ bct->hIcon = (HICON)lParam;
+ bct->hIconPrivate = 0;
+ }
+
+ DeleteObject(ii.hbmMask);
+ DeleteObject(ii.hbmColor);
+ bct->hBitmap = NULL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ } else if (wParam == IMAGE_BITMAP) {
+ bct->hBitmap = (HBITMAP)lParam;
+ if (bct->hIconPrivate)
+ DestroyIcon(bct->hIconPrivate);
+ bct->hIcon = bct->hIconPrivate = NULL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ case BM_SETCHECK:
+ if (!bct->pushBtn) break;
+ if (wParam == BST_CHECKED) {
+ bct->pbState = 1;
+ bct->stateId = PBS_PRESSED;
+ } else if (wParam == BST_UNCHECKED) {
+ bct->pbState = 0;
+ bct->stateId = PBS_NORMAL;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BM_GETCHECK:
+ if (bct->pushBtn) {
+ return bct->pbState ? BST_CHECKED : BST_UNCHECKED;
+ }
+ return 0;
+ case BUTTONSETARROW: // turn arrow on/off
+ bct->arrow = (HICON)wParam;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETDEFAULT:
+ bct->defbutton = wParam ? 1 : 0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETASPUSHBTN:
+ bct->pushBtn = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETASFLATBTN:
+ bct->flatBtn = lParam == 0 ? 1 : 0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETASFLATBTN + 10:
+ bct->bThemed = lParam ? TRUE : FALSE;
+ break;
+ case BUTTONSETASFLATBTN + 11:
+ bct->dimmed = lParam ? TRUE : FALSE;
+ break;
+ case BUTTONSETASFLATBTN + 12:
+ bct->pContainer = (struct TContainerData *)lParam;
+ break;
+ case BUTTONSETASFLATBTN + 13:
+ bct->bTitleButton = TRUE;
+ break;
+ case BUTTONSETASFLATBTN + 14:
+ bct->stateId = (wParam) ? PBS_NORMAL : PBS_DISABLED;
+ InvalidateRect(bct->hwnd, NULL, FALSE);
+ break;
+ case BUTTONSETASFLATBTN + 15:
+ return bct->stateId;
+ case BUTTONSETASTOOLBARBUTTON:
+ bct->bToolbarButton = lParam;
+ break;
+ case BUTTONSETASSIDEBARBUTTON:
+ bct->sitem = reinterpret_cast<CSideBarButton *>(lParam);
+ break;
+ case BUTTONSETOVERLAYICON:
+ bct->overlay = (HICON)lParam;
+ break;
+ case BUTTONADDTOOLTIP: {
+ TOOLINFO ti;
+
+ if (!(char*)wParam)
+ break;
+ EnterCriticalSection(&csTips);
+ if (!hwndToolTips) {
+ hwndToolTips = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
+ }
+ ZeroMemory(&ti, sizeof(ti));
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = bct->hwnd;
+ ti.uId = (UINT_PTR)bct->hwnd;
+ if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
+ SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
+ }
+ ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
+ ti.uId = (UINT_PTR)bct->hwnd;
+ ti.lpszText = (TCHAR *)wParam;
+ SendMessage(hwndToolTips, TTM_ADDTOOL, 0, (LPARAM)&ti);
+ SendMessage(hwndToolTips, TTM_SETMAXTIPWIDTH, 0, 300);
+ LeaveCriticalSection(&csTips);
+ break;
+ }
+ case WM_SETFOCUS: // set keybord focus and redraw
+ bct->focus = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case WM_KILLFOCUS: // kill focus and redraw
+ bct->focus = 0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case WM_ENABLE: { // windows tells us to enable/disable
+ bct->stateId = wParam ? PBS_NORMAL : PBS_DISABLED;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ }
+ case WM_MOUSELEAVE: { // faked by the WM_TIMER
+ if (bct->stateId != PBS_DISABLED) { // don't change states if disabled
+ bct->stateId = PBS_NORMAL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ }
+
+ case WM_CONTEXTMENU:
+ if(bct->sitem)
+ bct->sitem->invokeContextMenu();
+ break;
+
+ case WM_MBUTTONUP:
+ if(bct->sitem) {
+ if(bct->sitem->getDat())
+ SendMessage(bct->sitem->getDat()->hwnd, WM_CLOSE, 1, 0);
+ }
+ break;
+
+ case WM_LBUTTONDOWN: {
+ RECT rc;
+
+ if(bct->sitem) {
+ if(bct->sitem->testCloseButton() != -1)
+ return(TRUE);
+ bct->stateId = PBS_PRESSED;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ bct->sitem->activateSession();
+ }
+
+ if (bct->arrow) {
+ GetClientRect(bct->hwnd, &rc);
+ if (LOWORD(lParam) < rc.right - 12 && bct->stateId != PBS_DISABLED)
+ bct->stateId = PBS_PRESSED;
+ else if(LOWORD(lParam) > rc.right - 12) {
+ if(GetDlgCtrlID(hwndDlg) == IDOK || bct->stateId != PBS_DISABLED) {
+ WORD w = (WORD)((int)bct->arrow & 0x0000ffff);
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(w, BN_CLICKED), (LPARAM)hwndDlg);
+ }
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ } else if (bct->stateId != PBS_DISABLED) {
+ bct->stateId = PBS_PRESSED;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ }
+ case WM_LBUTTONUP: {
+ int showClick = 0;
+
+ if (bct->sitem) {
+ if(bct->sitem->testCloseButton() != -1) {
+ SendMessage(bct->sitem->getDat()->hwnd, WM_CLOSE, 1, 0);
+ return(TRUE);
+ }
+ }
+ if (bct->pushBtn) {
+ if (bct->pbState) bct->pbState = 0;
+ else bct->pbState = 1;
+ }
+ if (bct->stateId != PBS_DISABLED) { // don't change states if disabled
+ if(bct->stateId == PBS_PRESSED)
+ showClick = 1;
+ if (msg == WM_LBUTTONUP)
+ bct->stateId = PBS_HOT;
+ else
+ bct->stateId = PBS_NORMAL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ if(showClick)
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM)hwndDlg);
+ break;
+ }
+ case WM_MOUSEMOVE:
+ if (bct->stateId == PBS_NORMAL) {
+ bct->stateId = PBS_HOT;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ } else if (bct->arrow && bct->stateId == PBS_HOT) {
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ // Call timer, used to start cheesy TrackMouseEvent faker
+ SetTimer(hwndDlg, BUTTON_POLLID, BUTTON_POLLDELAY, NULL);
+ if(bct->sitem) {
+ if(bct->sitem->testCloseButton() != -1) {
+ if(bct->sitem->m_sideBar->getHoveredClose() != bct->sitem) {
+ bct->sitem->m_sideBar->setHoveredClose(bct->sitem);
+ InvalidateRect(hwndDlg, 0, FALSE);
+ }
+ }
+ else {
+ bct->sitem->m_sideBar->setHoveredClose(0);
+ InvalidateRect(hwndDlg, 0, FALSE);
+ }
+ }
+ break;
+ case WM_TIMER: { // use a timer to check if they have did a mouseout
+ if (wParam == BUTTON_POLLID) {
+ RECT rc;
+ POINT pt;
+ GetWindowRect(hwndDlg, &rc);
+ GetCursorPos(&pt);
+ if (!PtInRect(&rc, pt)) { // mouse must be gone, trigger mouse leave
+ PostMessage(hwndDlg, WM_MOUSELEAVE, 0, 0L);
+ KillTimer(hwndDlg, BUTTON_POLLID);
+ if(bct->sitem) {
+ bct->sitem->m_sideBar->setHoveredClose(0);
+ InvalidateRect(hwndDlg, 0, FALSE);
+ }
+ }
+ }
+ break;
+ }
+ case WM_ERASEBKGND:
+ return(1);
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
diff --git a/plugins/TabSRMM/src/buttonsbar.cpp b/plugins/TabSRMM/src/buttonsbar.cpp
new file mode 100644
index 0000000000..fb50f7b576
--- /dev/null
+++ b/plugins/TabSRMM/src/buttonsbar.cpp
@@ -0,0 +1,1622 @@
+#include "commonheaders.h"
+#pragma hdrstop
+
+static HANDLE hButtonsBarAddButton;
+static HANDLE hButtonsBarRemoveButton;
+static HANDLE hButtonsBarGetButtonState;
+static HANDLE hButtonsBarSetButtonState;
+static HANDLE hButtonsBarModifyButton;
+
+HANDLE hHookButtonPressedEvt;
+HANDLE hHookToolBarLoadedEvt;
+
+static SortedList * RButtonsList;
+static SortedList * LButtonsList;
+
+DWORD LastCID = 4000;
+DWORD dwSepCount = 0;
+BOOL bNeedResort = FALSE;
+
+CRITICAL_SECTION ToolBarCS;
+
+typedef void (*ItemDestuctor)(void*);
+
+
+//////////////////////////////////////////////////////////////////////////////////
+//
+//some code parts from ClistModern toolbar by FYR
+//
+/////////////////////////////////////////////////////////////////////////////////
+static int sstSortButtons(const void * vmtbi1, const void * vmtbi2)
+{
+ CustomButtonData * mtbi1 = (CustomButtonData *) * ((CustomButtonData **)vmtbi1);
+ CustomButtonData * mtbi2 = (CustomButtonData *) * ((CustomButtonData **)vmtbi2);
+ if (mtbi1 == NULL || mtbi2 == NULL) return (mtbi1 - mtbi2);
+ return mtbi1->dwPosition - mtbi2->dwPosition;
+}
+
+
+static void li_ListDestruct(SortedList *pList, ItemDestuctor pItemDestructor)
+{
+ int i = 0;
+ if (!pList) return;
+ for (i = 0; i < pList->realCount; i++) pItemDestructor(pList->items[i]);
+ li.List_Destroy(pList);
+ mir_free(pList);
+}
+
+static void li_RemoveDestruct(SortedList *pList, int index, ItemDestuctor pItemDestructor)
+{
+ if (index >= 0 && index < pList->realCount) {
+ pItemDestructor(pList->items[index]);
+ li.List_Remove(pList, index);
+ }
+}
+
+static void li_RemovePtrDestruct(SortedList *pList, void * ptr, ItemDestuctor pItemDestructor)
+{
+ if (li.List_RemovePtr(pList, ptr))
+ pItemDestructor(ptr);
+}
+
+static void li_SortList(SortedList *pList, FSortFunc pSortFunct)
+{
+ FSortFunc pOldSort = pList->sortFunc;
+ int i;
+ if (!pSortFunct) pSortFunct = pOldSort;
+ pList->sortFunc = NULL;
+ for (i = 0; i < pList->realCount - 1; i++)
+ if (pOldSort(pList->items[i], pList->items[i+1]) < 0) {
+ void * temp = pList->items[i];
+ pList->items[i] = pList->items[i+1];
+ pList->items[i+1] = temp;
+ i--;
+ if (i > 0) i--;
+ }
+ pList->sortFunc = pOldSort;
+}
+
+static void listdestructor(void * input)
+{
+ CustomButtonData * cbdi = (CustomButtonData *)input;
+ if (cbdi->pszModuleName) mir_free(cbdi->pszModuleName);
+ if (cbdi->ptszTooltip) mir_free(cbdi->ptszTooltip);
+ mir_free(cbdi);
+}
+
+//from "advanced auto away" plugin by P. Boon
+struct RemoveSettings {
+ char *szPrefix;
+ int count;
+ char **szSettings;
+};
+
+static int DBRemoveEnumProc(const char *szSetting, LPARAM lParam)
+{
+ struct RemoveSettings *rs = (struct RemoveSettings *)lParam;
+
+ if (!rs->szPrefix || !strncmp(szSetting, rs->szPrefix, strlen(rs->szPrefix))) {
+ rs->szSettings = (char **)realloc(rs->szSettings, (rs->count + 1) * sizeof(char *));
+ rs->szSettings[rs->count] = _strdup(szSetting);
+ rs->count += 1;
+ }
+ return 0;
+}
+
+static int Hlp_RemoveDatabaseSettings(HANDLE hContact, char *szModule, char *szPrefix)
+{
+ DBCONTACTENUMSETTINGS dbces;
+ struct RemoveSettings rs;
+ int i, count;
+
+ ZeroMemory(&rs, sizeof(struct RemoveSettings));
+ rs.szPrefix = szPrefix;
+ ZeroMemory(&dbces, sizeof(DBCONTACTENUMSETTINGS));
+ dbces.pfnEnumProc = DBRemoveEnumProc;
+ dbces.lParam = (LPARAM) & rs;
+ dbces.szModule = szModule;
+ if (CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)(HANDLE)hContact, (LPARAM)&dbces) == -1) {
+
+ return -1;
+ }
+ count = 0;
+ if (rs.szSettings != NULL) {
+ for (i = 0; i < rs.count; i++) {
+ if (rs.szSettings[i] != NULL) {
+ if (!DBDeleteContactSetting(hContact, szModule, rs.szSettings[i])) {
+ count += 1;
+ }
+ free(rs.szSettings[i]);
+ }
+ }
+ free(rs.szSettings);
+ }
+
+ return count;
+}
+
+void CB_InitCustomButtons()
+{
+ LButtonsList = li.List_Create(0, 1);
+ RButtonsList = li.List_Create(0, 1);
+ InitializeCriticalSection(&ToolBarCS);
+ dwSepCount = M->GetDword("TabSRMM_Toolbar", "SeparatorsCount", 0);
+
+ //dwSepCount = DBGetContactSettingDword(NULL, "TabSRMM_Toolbar", "SeparatorsCount", 0);
+
+ hButtonsBarAddButton = CreateServiceFunction(MS_BB_ADDBUTTON, CB_AddButton);
+ hButtonsBarRemoveButton = CreateServiceFunction(MS_BB_REMOVEBUTTON, CB_RemoveButton);
+ hButtonsBarModifyButton = CreateServiceFunction(MS_BB_MODIFYBUTTON, CB_ModifyButton);
+ hButtonsBarGetButtonState = CreateServiceFunction(MS_BB_GETBUTTONSTATE, CB_GetButtonState);
+ hButtonsBarSetButtonState = CreateServiceFunction(MS_BB_SETBUTTONSTATE, CB_SetButtonState);
+
+ hHookToolBarLoadedEvt = CreateHookableEvent(ME_MSG_TOOLBARLOADED);
+ hHookButtonPressedEvt = CreateHookableEvent(ME_MSG_BUTTONPRESSED);
+}
+
+void CB_DeInitCustomButtons()
+{
+ DeleteCriticalSection(&ToolBarCS);
+ li_ListDestruct(LButtonsList, listdestructor);
+ li_ListDestruct(RButtonsList, listdestructor);
+ DestroyHookableEvent(hHookToolBarLoadedEvt);
+ DestroyHookableEvent(hHookButtonPressedEvt);
+ DestroyServiceFunction(hButtonsBarAddButton);
+ DestroyServiceFunction(hButtonsBarRemoveButton);
+ DestroyServiceFunction(hButtonsBarModifyButton);
+ DestroyServiceFunction(hButtonsBarGetButtonState);
+ DestroyServiceFunction(hButtonsBarSetButtonState);
+}
+
+void CB_DestroyAllButtons(HWND hwndDlg, struct TWindowData *dat)
+{
+ int i;
+ HWND hwndBtn = NULL;
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)LButtonsList->items[i];
+ {
+ hwndBtn = GetDlgItem(hwndDlg, cbd->dwButtonCID);
+ if (hwndBtn) DestroyWindow(hwndBtn);
+ }
+ }
+
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)RButtonsList->items[i];
+ {
+ hwndBtn = GetDlgItem(hwndDlg, cbd->dwButtonCID);
+ if (hwndBtn) DestroyWindow(hwndBtn);
+ }
+ }
+}
+
+void CB_DestroyButton(HWND hwndDlg, struct TWindowData *dat, DWORD dwButtonCID, DWORD dwFlags)
+{
+ HWND hwndBtn = GetDlgItem(hwndDlg, dwButtonCID);
+ RECT rc = {0};
+ if (hwndBtn) {
+ GetClientRect(hwndBtn, &rc);
+ if (dwFlags&BBBF_ISLSIDEBUTTON)
+ dat->bbLSideWidth -= rc.right;
+ else if (dwFlags&BBBF_ISRSIDEBUTTON)
+ dat->bbRSideWidth -= rc.right;
+
+ DestroyWindow(hwndBtn);
+ BB_SetButtonsPos(dat);
+ }
+}
+
+void CB_ChangeButton(HWND hwndDlg, struct TWindowData *dat, CustomButtonData* cbd)
+{
+ HWND hwndBtn = GetDlgItem(hwndDlg, cbd->dwButtonCID);
+ if (hwndBtn) {
+ if (cbd->hIcon)
+ SendMessage(hwndBtn, BM_SETIMAGE, IMAGE_ICON, (LPARAM)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)cbd->hIcon));
+ if (cbd->ptszTooltip)
+ SendMessage(hwndBtn, BUTTONADDTOOLTIP, (WPARAM)TranslateTS(cbd->ptszTooltip), 0);
+ SendMessage(hwndBtn, BUTTONSETASFLATBTN + 12, 0, (LPARAM)dat->pContainer);
+ }
+}
+
+void CB_ReInitCustomButtons()
+{
+ int i;
+
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)LButtonsList->items[i];
+ //GetButtonSettings(NULL,cbd);
+ if (cbd->opFlags&BBSF_NTBSWAPED || cbd->opFlags&BBSF_NTBDESTRUCT) {
+ cbd->opFlags ^= BBSF_NTBSWAPED;
+
+ if (!(cbd->opFlags&BBSF_NTBDESTRUCT))
+ li.List_InsertPtr(RButtonsList, cbd);
+
+ li.List_Remove(LButtonsList, i);
+ i--;
+ }
+ }
+
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)RButtonsList->items[i];
+ if (cbd->opFlags&BBSF_NTBSWAPED || cbd->opFlags&BBSF_NTBDESTRUCT) {
+ cbd->opFlags ^= BBSF_NTBSWAPED;
+
+ if (!(cbd->opFlags&BBSF_NTBDESTRUCT))
+ li.List_InsertPtr(LButtonsList, cbd);
+
+ li.List_Remove(RButtonsList, i);
+ i--;
+ }
+ }
+ M->BroadcastMessage(DM_BBNEEDUPDATE, 0, 0);
+ M->BroadcastMessage(DM_LOADBUTTONBARICONS, 0, 0);
+}
+
+void CB_HardReInit()
+{
+ M->BroadcastMessage(DM_CBDESTROY, 0, 0);
+ EnterCriticalSection(&ToolBarCS);
+ li_ListDestruct(LButtonsList, listdestructor);
+ li_ListDestruct(RButtonsList, listdestructor);
+ LButtonsList = li.List_Create(0, 1);
+ RButtonsList = li.List_Create(0, 1);
+ LeaveCriticalSection(&ToolBarCS);
+ LastCID = 4000;
+ dwSepCount = 0;
+
+ CB_InitDefaultButtons();
+ NotifyEventHooks(hHookToolBarLoadedEvt, (WPARAM)0, (LPARAM)0);
+}
+
+static INT_PTR CB_AddButton(WPARAM wParam, LPARAM lParam)
+{
+ BBButton * bbdi = (BBButton *)lParam;
+ bNeedResort = TRUE;
+ if (bbdi->cbSize != sizeof(BBButton))
+ return 1;
+ {
+ CustomButtonData *cbd = (CustomButtonData *)mir_alloc(sizeof(CustomButtonData));
+ memset(cbd, 0, sizeof(CustomButtonData));
+
+
+ if (!bbdi->iButtonWidth && (bbdi->bbbFlags&BBBF_ISARROWBUTTON))
+ cbd->iButtonWidth = DPISCALEX_S(34);
+ else if (!bbdi->iButtonWidth)
+ cbd->iButtonWidth = DPISCALEX_S(22);
+ else cbd->iButtonWidth = DPISCALEX_S(bbdi->iButtonWidth);
+
+ cbd->pszModuleName = mir_strdup(bbdi->pszModuleName);
+
+ if (bbdi->ptszTooltip) {
+ if (bbdi->bbbFlags&BBBF_ANSITOOLTIP)
+ cbd->ptszTooltip = mir_a2u(bbdi->pszTooltip);
+ else
+ cbd->ptszTooltip = mir_tstrdup(bbdi->ptszTooltip);
+ } else cbd->ptszTooltip = NULL;
+
+
+ cbd->dwButtonOrigID = bbdi->dwButtonID;
+ cbd->hIcon = bbdi->hIcon;
+ cbd->dwPosition = bbdi->dwDefPos;
+ cbd->dwButtonCID = (bbdi->bbbFlags & BBBF_CREATEBYID) ? bbdi->dwButtonID : LastCID;
+ //ugly workaround for smileys plugins
+ cbd->dwArrowCID = (bbdi->bbbFlags & BBBF_ISARROWBUTTON) ? (cbd->dwButtonCID == IDOK ? IDC_SENDMENU : (cbd->dwButtonCID + 1)) : 0 ;
+ cbd->bHidden = (bbdi->bbbFlags & BBBF_HIDDEN) ? 1 : 0;
+ cbd->bLSided = (bbdi->bbbFlags & BBBF_ISLSIDEBUTTON) ? 1 : 0;
+ cbd->bRSided = (bbdi->bbbFlags & BBBF_ISRSIDEBUTTON) ? 1 : 0;
+ cbd->bCanBeHidden = (bbdi->bbbFlags & BBBF_CANBEHIDDEN) ? 1 : 0;
+ cbd->bDummy = (bbdi->bbbFlags & BBBF_ISDUMMYBUTTON) ? 1 : 0;
+ cbd->bChatButton = (bbdi->bbbFlags & BBBF_ISCHATBUTTON) ? 1 : 0;
+ cbd->bIMButton = (bbdi->bbbFlags & BBBF_ISIMBUTTON) ? 1 : 0;
+ cbd->bDisabled = (bbdi->bbbFlags & BBBF_DISABLED) ? 1 : 0;
+ cbd->bPushButton = (bbdi->bbbFlags & BBBF_ISPUSHBUTTON) ? 1 : 0;
+
+ CB_GetButtonSettings(NULL, cbd);
+
+ if (cbd->bLSided)
+ li.List_InsertPtr(LButtonsList, cbd);
+ else if (cbd->bRSided)
+ li.List_InsertPtr(RButtonsList, cbd);
+ else return 1;
+
+ if (cbd->dwButtonCID != cbd->dwButtonOrigID)
+ LastCID++;
+ if (cbd->dwArrowCID == LastCID)
+ LastCID++;
+
+ M->BroadcastMessage(DM_BBNEEDUPDATE, 0, 0);
+ }
+ return 0;
+}
+
+static INT_PTR CB_GetButtonState(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndDlg = NULL;
+ int i;
+ DWORD tempCID = 0;
+ BOOL realbutton = 0;
+ BBButton * bbdi = (BBButton *)lParam;
+ bbdi->bbbFlags = 0;
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)LButtonsList->items[i];
+ if (!strcmp(cbd->pszModuleName, bbdi->pszModuleName) && (cbd->dwButtonOrigID == bbdi->dwButtonID)) {
+ realbutton = 1;
+ tempCID = cbd->dwButtonCID;
+ }
+ }
+ if (!realbutton)
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)RButtonsList->items[i];
+ if (!strcmp(cbd->pszModuleName, bbdi->pszModuleName) && (cbd->dwButtonOrigID == bbdi->dwButtonID)) {
+ realbutton = 1;
+ tempCID = cbd->dwButtonCID;
+ }
+ }
+
+ if (!realbutton) return 1;
+ hwndDlg = M->FindWindow((HANDLE)wParam);
+ bbdi->bbbFlags = (IsDlgButtonChecked(hwndDlg, tempCID) ? BBSF_PUSHED : BBSF_RELEASED) | (IsWindowVisible(GetDlgItem(hwndDlg, tempCID)) ? 0 : BBSF_HIDDEN) | (IsWindowEnabled(GetDlgItem(hwndDlg, tempCID)) ? 0 : BBSF_DISABLED);
+ return 0;
+}
+
+static INT_PTR CB_SetButtonState(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndDlg;
+ int i;
+ BOOL realbutton = 0;
+ DWORD tempCID = 0;
+ BBButton * bbdi = (BBButton *)lParam;
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)LButtonsList->items[i];
+ if (!strcmp(cbd->pszModuleName, bbdi->pszModuleName) && (cbd->dwButtonOrigID == bbdi->dwButtonID)) {
+ realbutton = 1;
+ tempCID = cbd->dwButtonCID;
+ }
+ }
+ if (!realbutton)
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)RButtonsList->items[i];
+ if (!strcmp(cbd->pszModuleName, bbdi->pszModuleName) && (cbd->dwButtonOrigID == bbdi->dwButtonID)) {
+ realbutton = 1;
+ tempCID = cbd->dwButtonCID;
+ }
+ }
+
+ if (!realbutton || !wParam) return 1;
+
+
+ hwndDlg = M->FindWindow((HANDLE)wParam);
+ if (hwndDlg && realbutton && bbdi->hIcon)
+ SendMessage(GetDlgItem(hwndDlg, tempCID), BM_SETIMAGE, IMAGE_ICON, (LPARAM)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)bbdi->hIcon));
+ if (hwndDlg && realbutton && bbdi->pszTooltip) {
+ if (bbdi->bbbFlags&BBBF_ANSITOOLTIP)
+ SendMessage(GetDlgItem(hwndDlg, tempCID), BUTTONADDTOOLTIP, (WPARAM)mir_a2u(bbdi->pszTooltip), 0);
+ else
+ SendMessage(GetDlgItem(hwndDlg, tempCID), BUTTONADDTOOLTIP, (WPARAM)bbdi->ptszTooltip, 0);
+ }
+ if (hwndDlg && realbutton && bbdi->bbbFlags) {
+ Utils::showDlgControl(hwndDlg, tempCID, (bbdi->bbbFlags&BBSF_HIDDEN) ? SW_HIDE : SW_SHOW);
+ Utils::enableDlgControl(hwndDlg, tempCID, (bbdi->bbbFlags&BBSF_DISABLED) ? 0 : 1);
+ CheckDlgButton(hwndDlg, tempCID, (bbdi->bbbFlags&BBSF_PUSHED) ? 1 : 0);
+ CheckDlgButton(hwndDlg, tempCID, (bbdi->bbbFlags&BBSF_RELEASED) ? 0 : 1);
+ }
+ return 0;
+}
+
+static INT_PTR CB_RemoveButton(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+ DWORD tempCID = 0;
+ DWORD dwFlags = 0;
+ BBButton * bbdi = (BBButton *)lParam;
+
+ EnterCriticalSection(&ToolBarCS);
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)LButtonsList->items[i];
+ if (!strcmp(cbd->pszModuleName, bbdi->pszModuleName) && (cbd->dwButtonOrigID == bbdi->dwButtonID)) {
+ tempCID = cbd->dwButtonCID;
+ dwFlags = cbd->bLSided ? BBBF_ISLSIDEBUTTON : BBBF_ISRSIDEBUTTON;
+ li.List_Remove(LButtonsList, i);
+ i--;
+ }
+ }
+ if (tempCID) qsort(LButtonsList->items, LButtonsList->realCount, sizeof(CustomButtonData *), sstSortButtons);
+
+ if (!tempCID) {
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)RButtonsList->items[i];
+ if (!strcmp(cbd->pszModuleName, bbdi->pszModuleName) && (cbd->dwButtonOrigID == bbdi->dwButtonID)) {
+ tempCID = cbd->dwButtonCID;
+ dwFlags = cbd->bLSided ? BBBF_ISLSIDEBUTTON : BBBF_ISRSIDEBUTTON;
+ li.List_Remove(RButtonsList, i);
+ i--;
+ }
+ }
+ if (tempCID) qsort(RButtonsList->items, RButtonsList->realCount, sizeof(CustomButtonData *), sstSortButtons);
+ }
+
+ LeaveCriticalSection(&ToolBarCS);
+ if (tempCID)
+ M->BroadcastMessage(DM_CBDESTROY, (WPARAM)tempCID, (LPARAM)dwFlags);
+ return 0;
+}
+
+static INT_PTR CB_ModifyButton(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+ BOOL bFound = 0;
+ CustomButtonData* cbd = NULL;
+ BBButton * bbdi = (BBButton *)lParam;
+
+ EnterCriticalSection(&ToolBarCS);
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ cbd = (CustomButtonData *)LButtonsList->items[i];
+ if (!strcmp(cbd->pszModuleName, bbdi->pszModuleName) && (cbd->dwButtonOrigID == bbdi->dwButtonID)) {
+ bFound = 1;
+ break;
+ }
+ }
+
+ if (!bFound) {
+ cbd = NULL;
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ cbd = (CustomButtonData *)RButtonsList->items[i];
+ if (!strcmp(cbd->pszModuleName, bbdi->pszModuleName) && (cbd->dwButtonOrigID == bbdi->dwButtonID)) {
+ bFound = 1;
+ break;
+ }
+ }
+ }
+
+ if (bFound) {
+ if (bbdi->pszTooltip) {
+ if (cbd->ptszTooltip) mir_free(cbd->ptszTooltip);
+ if (bbdi->bbbFlags&BBBF_ANSITOOLTIP)
+ cbd->ptszTooltip = mir_a2u(bbdi->pszTooltip);
+ else
+ cbd->ptszTooltip = mir_tstrdup(bbdi->ptszTooltip);
+ }
+ if (bbdi->hIcon) cbd->hIcon = bbdi->hIcon;
+ if (bbdi->bbbFlags) {
+ cbd->bHidden = (bbdi->bbbFlags & BBBF_HIDDEN) ? 1 : 0;
+ cbd->bLSided = (bbdi->bbbFlags & BBBF_ISLSIDEBUTTON) ? 1 : 0;
+ cbd->bRSided = (bbdi->bbbFlags & BBBF_ISRSIDEBUTTON) ? 1 : 0;
+ cbd->bCanBeHidden = (bbdi->bbbFlags & BBBF_CANBEHIDDEN) ? 1 : 0;
+ cbd->bChatButton = (bbdi->bbbFlags & BBBF_ISCHATBUTTON) ? 1 : 0;
+ cbd->bIMButton = (bbdi->bbbFlags & BBBF_ISIMBUTTON) ? 1 : 0;
+ cbd->bDisabled = (bbdi->bbbFlags & BBBF_DISABLED) ? 1 : 0;
+ }
+ }
+ LeaveCriticalSection(&ToolBarCS);
+ if (bFound)
+ M->BroadcastMessage(DM_BBNEEDUPDATE, 0, (LPARAM)cbd);
+ return 0;
+}
+
+void BB_UpdateIcons(HWND hdlg, struct TWindowData *dat)
+{
+ int i;
+ HWND hwndBtn = NULL;
+
+ qsort(LButtonsList->items, LButtonsList->realCount, sizeof(CustomButtonData *), sstSortButtons);
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)LButtonsList->items[i];
+ if (cbd) {
+ if (!cbd->bDummy)
+ hwndBtn = GetDlgItem(hdlg, cbd->dwButtonCID);
+
+ if (hwndBtn && cbd->hIcon)
+ SendMessage(hwndBtn, BM_SETIMAGE, IMAGE_ICON, (LPARAM)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)cbd->hIcon));
+ }
+ }
+
+ hwndBtn = NULL;
+ qsort(RButtonsList->items, RButtonsList->realCount, sizeof(CustomButtonData *), sstSortButtons);
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)RButtonsList->items[i];
+ if (cbd) {
+ if (!cbd->bDummy)
+ hwndBtn = GetDlgItem(hdlg, cbd->dwButtonCID);
+
+ if (hwndBtn && cbd->hIcon)
+ SendMessage(hwndBtn, BM_SETIMAGE, IMAGE_ICON, (LPARAM)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)cbd->hIcon));
+ }
+
+ }
+}
+
+void TSAPI BB_InitDlgButtons(TWindowData *dat)
+{
+ RECT rect;
+ int i;
+ int lwidth = 0, rwidth = 0;
+ HWND hwndBtn = NULL;
+ RECT rcSplitter;
+ POINT ptSplitter;
+ int splitterY;
+ BYTE gap = DPISCALEX_S(PluginConfig.g_iButtonsBarGap);
+ BOOL isThemed = PluginConfig.m_bIsXP;
+ int cx = 0, cy = 0;
+ int lcount = LButtonsList->realCount;
+ int rcount = RButtonsList->realCount;
+ HWND hdlg = dat->hwnd;
+
+ if (dat == 0 || hdlg == 0) {return;}
+ if (CSkin::m_skinEnabled && !SkinItems[ID_EXTBKBUTTONSNPRESSED].IGNORED &&
+ !SkinItems[ID_EXTBKBUTTONSPRESSED].IGNORED && !SkinItems[ID_EXTBKBUTTONSMOUSEOVER].IGNORED) {
+ isThemed = FALSE;
+ }
+
+ GetWindowRect(GetDlgItem(hdlg, (dat->bType == SESSIONTYPE_IM) ? IDC_SPLITTER : IDC_SPLITTERY), &rcSplitter);
+ ptSplitter.x = 0;
+ ptSplitter.y = rcSplitter.top;
+ ScreenToClient(hdlg, &ptSplitter);
+
+ GetClientRect(hdlg, &rect);
+ splitterY = ptSplitter.y - DPISCALEY_S(1);
+
+ hwndBtn = NULL;
+ qsort(RButtonsList->items, RButtonsList->realCount, sizeof(CustomButtonData *), sstSortButtons);
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)RButtonsList->items[i];
+ if (((dat->bType == SESSIONTYPE_IM && cbd->bIMButton)
+ || (dat->bType == SESSIONTYPE_CHAT && cbd->bChatButton))) {
+ if (!cbd->bHidden)
+ rwidth += cbd->iButtonWidth + gap;
+ if (!cbd->bHidden && !cbd->bCanBeHidden)
+ dat->iButtonBarReallyNeeds += cbd->iButtonWidth + gap;
+ if (!cbd->bDummy && !GetDlgItem(hdlg, cbd->dwButtonCID))
+ hwndBtn = CreateWindowEx(0, _T("TSButtonClass"), _T(""), WS_CHILD | WS_VISIBLE | WS_TABSTOP, rect.right - rwidth + gap, splitterY, cbd->iButtonWidth, DPISCALEY_S(22), hdlg, (HMENU) cbd->dwButtonCID, g_hInst, NULL);
+ if (!cbd->bDummy && hwndBtn) {
+ SendMessage(hwndBtn, BUTTONSETASFLATBTN, 0, 0);
+ SendMessage(hwndBtn, BUTTONSETASFLATBTN + 10, 0, isThemed ? 1 : 0);
+ if (cbd->hIcon)
+ SendMessage(hwndBtn, BM_SETIMAGE, IMAGE_ICON, (LPARAM)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)cbd->hIcon));
+ if (cbd->ptszTooltip)
+ SendMessage(hwndBtn, BUTTONADDTOOLTIP, (WPARAM)TranslateTS(cbd->ptszTooltip), 0);
+ SendMessage(hwndBtn, BUTTONSETASFLATBTN + 12, 0, (LPARAM)dat->pContainer);
+ SendMessage(hwndBtn, BUTTONSETASTOOLBARBUTTON, 0, 1);
+
+ if (hwndBtn && cbd->dwArrowCID)
+ SendMessage(hwndBtn, BUTTONSETARROW, cbd->dwArrowCID, 0);
+ if (hwndBtn && cbd->bPushButton)
+ SendMessage(hwndBtn, BUTTONSETASPUSHBTN, 0, 0);
+ }
+ } else if (GetDlgItem(hdlg, cbd->dwButtonCID))
+ DestroyWindow(GetDlgItem(hdlg, cbd->dwButtonCID));
+
+ if (cbd->bDisabled)
+ EnableWindow(hwndBtn, 0);
+ if (cbd->bHidden)
+ ShowWindow(hwndBtn, SW_HIDE);
+
+ }
+
+ hwndBtn = NULL;
+ qsort(LButtonsList->items, LButtonsList->realCount, sizeof(CustomButtonData *), sstSortButtons);
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)LButtonsList->items[i];
+ if (((dat->bType == SESSIONTYPE_IM && cbd->bIMButton)
+ || (dat->bType == SESSIONTYPE_CHAT && cbd->bChatButton))) {
+ if (!cbd->bDummy && !GetDlgItem(hdlg, cbd->dwButtonCID))
+ hwndBtn = CreateWindowEx(0, _T("TSButtonClass"), _T(""), WS_CHILD | WS_VISIBLE | WS_TABSTOP, 2 + lwidth, splitterY,
+ cbd->iButtonWidth, DPISCALEY_S(22), hdlg, (HMENU) cbd->dwButtonCID, g_hInst, NULL);
+ if (!cbd->bHidden)
+ lwidth += cbd->iButtonWidth + gap;
+ if (!cbd->bHidden && !cbd->bCanBeHidden)
+ dat->iButtonBarReallyNeeds += cbd->iButtonWidth + gap;
+ if (!cbd->bDummy && hwndBtn) {
+ SendMessage(hwndBtn, BUTTONSETASFLATBTN, 0, 0);
+ SendMessage(hwndBtn, BUTTONSETASFLATBTN + 10, 0, isThemed ? 1 : 0);
+ if (cbd->hIcon)
+ SendMessage(hwndBtn, BM_SETIMAGE, IMAGE_ICON, (LPARAM)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)cbd->hIcon));
+ if (cbd->ptszTooltip)
+ SendMessage(hwndBtn, BUTTONADDTOOLTIP, (WPARAM)TranslateTS(cbd->ptszTooltip), 0);
+ SendMessage(hwndBtn, BUTTONSETASFLATBTN + 12, 0, (LPARAM)dat->pContainer);
+ SendMessage(hwndBtn, BUTTONSETASTOOLBARBUTTON, 0, 1);
+
+ if (hwndBtn && cbd->dwArrowCID)
+ SendMessage(hwndBtn, BUTTONSETARROW, cbd->dwArrowCID, 0);
+ if (hwndBtn && cbd->bPushButton)
+ SendMessage(hwndBtn, BUTTONSETASPUSHBTN, 0, 0);
+ }
+ } else if (GetDlgItem(hdlg, cbd->dwButtonCID))
+ DestroyWindow(GetDlgItem(hdlg, cbd->dwButtonCID));
+
+ if (cbd->bDisabled)
+ EnableWindow(hwndBtn, 0);
+ if (cbd->bHidden)
+ ShowWindow(hwndBtn, SW_HIDE);
+ }
+
+ dat->bbLSideWidth = lwidth;
+ dat->bbRSideWidth = rwidth;
+}
+
+void TSAPI BB_RedrawButtons(TWindowData *dat)
+{
+ int i;
+ CustomButtonData* cbd;
+ HWND hwnd;
+
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ cbd = reinterpret_cast<CustomButtonData *>(LButtonsList->items[i]);
+ if(cbd) {
+ hwnd = GetDlgItem(dat->hwnd, cbd->dwButtonCID);
+ if(hwnd)
+ InvalidateRect(hwnd, 0, TRUE);
+ }
+ }
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ cbd = reinterpret_cast<CustomButtonData *>(RButtonsList->items[i]);
+ if(cbd) {
+ hwnd = GetDlgItem(dat->hwnd, cbd->dwButtonCID);
+ if(hwnd)
+ InvalidateRect(hwnd, 0, TRUE);
+ }
+ }
+ HWND hwndToggleSideBar = GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_TOGGLESIDEBAR : IDC_CHAT_TOGGLESIDEBAR);
+ if(hwndToggleSideBar && IsWindow(hwndToggleSideBar))
+ InvalidateRect(hwndToggleSideBar, 0, TRUE);
+}
+
+BOOL TSAPI BB_SetButtonsPos(TWindowData *dat)
+{
+ RECT rect;
+ int i;
+ HWND hwndBtn = 0;
+ int lwidth = 0, rwidth = 0;
+ RECT rcSplitter;
+ POINT ptSplitter;
+ int splitterY, iOff;
+ BYTE gap = DPISCALEX_S(PluginConfig.g_iButtonsBarGap);
+ int foravatar = 0;
+ BOOL showToolbar = dat->pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1;
+ BOOL bBottomToolbar = dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR ? 1 : 0;
+ int tempL = dat->bbLSideWidth;
+ int tempR = dat->bbRSideWidth;
+ HWND hwnd = dat->hwnd;
+ HDWP hdwp = BeginDeferWindowPos(LButtonsList->realCount + RButtonsList->realCount + 1);
+ HWND hwndToggleSideBar = GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_TOGGLESIDEBAR : IDC_CHAT_TOGGLESIDEBAR);
+
+ if (!dat || !IsWindowVisible(hwnd))
+ return 0;
+
+ ShowWindow(hwndToggleSideBar, (showToolbar && dat->pContainer->SideBar->isActive()) ? SW_SHOW : SW_HIDE);
+
+ EnterCriticalSection(&ToolBarCS);
+
+ GetWindowRect(GetDlgItem(hwnd, (dat->bType == SESSIONTYPE_IM) ? IDC_SPLITTER : IDC_SPLITTERY), &rcSplitter);
+ ptSplitter.x = 0;
+ ptSplitter.y = rcSplitter.top;
+ ScreenToClient(hwnd, &ptSplitter);
+ if (PluginConfig.g_DPIscaleY > 1.0)
+ iOff = dat->bType == SESSIONTYPE_IM ? DPISCALEY_S(22) : DPISCALEY_S(23);
+ else
+ iOff = DPISCALEY_S(22);
+
+ GetClientRect(hwnd, &rect);
+
+ if (!bBottomToolbar) splitterY = ptSplitter.y - DPISCALEY_S(1);
+ else splitterY = rect.bottom;
+
+ if ((rect.bottom - ptSplitter.y - (rcSplitter.bottom - rcSplitter.top) /*- DPISCALEY(2)*/ - (bBottomToolbar ? DPISCALEY_S(24) : 0) < dat->pic.cy - DPISCALEY_S(2)) && dat->showPic && !PluginConfig.m_AlwaysFullToolbarWidth)
+ foravatar = dat->pic.cx + gap;
+
+ if (bNeedResort)
+ qsort(LButtonsList->items, LButtonsList->realCount, sizeof(BBButton *), sstSortButtons);
+
+ if((dat->pContainer->dwFlags & CNT_SIDEBAR) && (dat->pContainer->SideBar->getFlags() & CSideBar::SIDEBARORIENTATION_LEFT)) {
+ DeferWindowPos(hdwp, hwndToggleSideBar , NULL, 4, 2 + splitterY - iOff,
+ 0, 0, SWP_NOZORDER | SWP_NOSIZE);// | SWP_NOCOPYBITS);
+ lwidth += 10;
+ tempL -= 10;
+ }
+
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)LButtonsList->items[i];
+ if (((dat->bType == SESSIONTYPE_IM) && cbd->bIMButton)
+ || ((dat->bType == SESSIONTYPE_CHAT) && cbd->bChatButton)) {
+
+ hwndBtn = GetDlgItem(hwnd, cbd->dwButtonCID);
+
+ if (!showToolbar) {
+ ShowWindow(hwndBtn, SW_HIDE);
+ DeferWindowPos(hdwp, hwndBtn , NULL, lwidth, splitterY - iOff,
+ 0, 0, SWP_NOZORDER | SWP_NOSIZE);// | SWP_NOCOPYBITS);
+ if (IsWindowVisible(hwndBtn) || (cbd->bDummy && !(cbd->bAutoHidden || cbd->bHidden)))
+ lwidth += cbd->iButtonWidth + gap;
+ if (!IsWindowEnabled(hwndBtn) && !IsWindowVisible(hwndBtn) && !cbd->bAutoHidden)
+ cbd->bAutoHidden = 1;
+ continue;
+ } else if (!cbd->bCanBeHidden && !cbd->bHidden && !(!IsWindowEnabled(hwndBtn) && !IsWindowVisible(hwndBtn) && !cbd->bAutoHidden)) {
+ ShowWindow(hwndBtn, SW_SHOW);
+ cbd->bAutoHidden = 0;
+ }
+
+ if (!cbd->bDummy && !IsWindowVisible(hwndBtn) && !IsWindowEnabled(hwndBtn) && !cbd->bAutoHidden)
+ tempL -= cbd->iButtonWidth + gap;
+
+ if (cbd->bCanBeHidden && !cbd->bHidden && (cbd->bDummy || !((!IsWindowEnabled(hwndBtn) && !IsWindowVisible(hwndBtn)) && !cbd->bAutoHidden))) {
+ if (tempL + tempR > (rect.right - foravatar)) {
+ ShowWindow(hwndBtn, SW_HIDE);
+ cbd->bAutoHidden = 1;
+ tempL -= cbd->iButtonWidth + gap;
+ } else if (cbd->bAutoHidden) {
+ ShowWindow(hwndBtn, SW_SHOW);
+ cbd->bAutoHidden = 0;
+ }
+ }
+ DeferWindowPos(hdwp, hwndBtn , NULL, lwidth, splitterY - iOff,
+ 0, 0, SWP_NOZORDER | SWP_NOSIZE);// SWP_NOCOPYBITS);
+ if (IsWindowVisible(hwndBtn) || (cbd->bDummy && !(cbd->bAutoHidden || cbd->bHidden)))
+ lwidth += cbd->iButtonWidth + gap;
+ }
+ }
+
+ if (bNeedResort) {
+ qsort(RButtonsList->items, RButtonsList->realCount, sizeof(CustomButtonData *), sstSortButtons);
+ bNeedResort = FALSE;
+ }
+
+ if((dat->pContainer->dwFlags & CNT_SIDEBAR) && (dat->pContainer->SideBar->getFlags() & CSideBar::SIDEBARORIENTATION_RIGHT)) {
+ DeferWindowPos(hdwp, hwndToggleSideBar , NULL, rect.right - foravatar - 10, 2 + splitterY - iOff,
+ 0, 0, SWP_NOZORDER | SWP_NOSIZE);// | SWP_NOCOPYBITS);
+ rwidth += 12;
+ tempR -= 12;
+ }
+
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)RButtonsList->items[i];
+ if (((dat->bType == SESSIONTYPE_IM) && cbd->bIMButton)
+ || ((dat->bType == SESSIONTYPE_CHAT) && cbd->bChatButton)) {
+
+ hwndBtn = GetDlgItem(hwnd, cbd->dwButtonCID);
+
+ if (!showToolbar) {
+ ShowWindow(hwndBtn, SW_HIDE);
+ if (IsWindowVisible(hwndBtn) || (cbd->bDummy && !(cbd->bAutoHidden || cbd->bHidden)))
+ rwidth += cbd->iButtonWidth + gap;
+ DeferWindowPos(hdwp, hwndBtn , NULL, rect.right - foravatar - rwidth + gap, splitterY - iOff,
+ 0, 0, SWP_NOZORDER | SWP_NOSIZE);// SWP_NOCOPYBITS);
+ if (!IsWindowEnabled(hwndBtn) && !IsWindowVisible(hwndBtn) && !cbd->bAutoHidden)
+ cbd->bAutoHidden = 1;
+ continue;
+ } else if (!cbd->bCanBeHidden && !cbd->bHidden && !((!IsWindowEnabled(hwndBtn) && !IsWindowVisible(hwndBtn)) && !cbd->bAutoHidden)) {
+ ShowWindow(hwndBtn, SW_SHOW);
+ cbd->bAutoHidden = 0;
+ }
+
+ if (!cbd->bDummy && !IsWindowVisible(hwndBtn) && !IsWindowEnabled(hwndBtn) && !cbd->bAutoHidden)
+ tempR -= cbd->iButtonWidth + gap;
+
+ if (cbd->bCanBeHidden && !cbd->bHidden && (cbd->bDummy || !((!IsWindowEnabled(hwndBtn) && !IsWindowVisible(hwndBtn)) && !cbd->bAutoHidden))) {
+ if (tempL + tempR > (rect.right - foravatar)) {
+ ShowWindow(hwndBtn, SW_HIDE);
+ cbd->bAutoHidden = 1;
+ tempR -= cbd->iButtonWidth + gap;
+ } else if (cbd->bAutoHidden) {
+ ShowWindow(hwndBtn, SW_SHOW);
+ cbd->bAutoHidden = 0;
+ }
+ }
+
+ if (IsWindowVisible(hwndBtn) || (cbd->bDummy && !(cbd->bAutoHidden || cbd->bHidden)))
+ rwidth += cbd->iButtonWidth + gap;
+ DeferWindowPos(hdwp, hwndBtn , NULL, rect.right - foravatar - rwidth + gap, splitterY - iOff,
+ 0, 0, SWP_NOZORDER | SWP_NOSIZE);// SWP_NOCOPYBITS);
+ }
+ }
+
+ LeaveCriticalSection(&ToolBarCS);
+
+ return (EndDeferWindowPos(hdwp));
+}
+
+void TSAPI BB_CustomButtonClick(struct TWindowData *dat, DWORD idFrom, HWND hwndFrom, BOOL code)
+{
+ RECT rc;
+ int i;
+ BOOL bFromArrow = 0;
+ CustomButtonClickData cbcd = {0};
+
+ GetWindowRect(hwndFrom, &rc);
+ cbcd.pt.x = rc.left;
+ cbcd.pt.y = rc.bottom;
+
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)LButtonsList->items[i];
+ if (cbd->dwButtonCID == idFrom) {
+ cbcd.pszModule = cbd->pszModuleName;
+ cbcd.dwButtonId = cbd->dwButtonOrigID;
+ } else if (cbd->dwArrowCID == idFrom) {
+ bFromArrow = 1;
+ cbcd.pszModule = cbd->pszModuleName;
+ cbcd.dwButtonId = cbd->dwButtonOrigID;
+ }
+ }
+
+ if (!cbcd.pszModule)
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)RButtonsList->items[i];
+ if (cbd->dwButtonCID == idFrom) {
+ cbcd.pszModule = cbd->pszModuleName;
+ cbcd.dwButtonId = cbd->dwButtonOrigID;
+ } else if (cbd->dwArrowCID == idFrom) {
+ bFromArrow = 1;
+ cbcd.pszModule = cbd->pszModuleName;
+ cbcd.dwButtonId = cbd->dwButtonOrigID;
+ }
+ }
+
+ cbcd.cbSize = sizeof(CustomButtonClickData);
+ cbcd.hwndFrom = dat->hwnd;
+ cbcd.hContact = dat->hContact;
+ cbcd.flags = (code ? BBCF_RIGHTBUTTON : 0) | (GetKeyState(VK_SHIFT) & 0x8000 ? BBCF_SHIFTPRESSED : 0) | (GetKeyState(VK_CONTROL) & 0x8000 ? BBCF_CONTROLPRESSED : 0) | (bFromArrow ? BBCF_ARROWCLICKED : 0);
+
+ NotifyEventHooks(hHookButtonPressedEvt, (WPARAM)dat->hContact, (LPARAM)&cbcd);
+}
+
+
+void CB_GetButtonSettings(HANDLE hContact, CustomButtonData *cbd)
+{
+ DBVARIANT dbv = {0};
+ char SettingName[1024] = {'\0'};
+ char* token = NULL;
+
+ //modulename_buttonID, position_inIM_inCHAT_isLSide_isRSide_CanBeHidden
+
+ mir_snprintf(SettingName, sizeof(SettingName), "%s_%d", cbd->pszModuleName, cbd->dwButtonOrigID);
+
+ if (!DBGetContactSettingString(hContact, "TabSRMM_Toolbar", SettingName, &dbv)) {
+ token = strtok(dbv.pszVal, "_");
+ cbd->dwPosition = (DWORD)atoi(token);
+ token = strtok(NULL, "_");
+ cbd->bIMButton = (BOOL)atoi(token);
+ token = strtok(NULL, "_");
+ cbd->bChatButton = (BOOL)atoi(token);
+ token = strtok(NULL, "_");
+ cbd->bLSided = (BOOL)atoi(token);
+ token = strtok(NULL, "_");
+ cbd->bRSided = (BOOL)atoi(token);
+ token = strtok(NULL, "_");
+ cbd->bCanBeHidden = (BOOL)atoi(token);
+
+ DBFreeVariant(&dbv);
+ }
+}
+
+void CB_WriteButtonSettings(HANDLE hContact, CustomButtonData *cbd)
+{
+ char SettingName[1024] = {'\0'};
+ char SettingParameter[1024] = {'\0'};
+
+ //modulename_buttonID, position_inIM_inCHAT_isLSide_isRSide_CanBeHidden
+
+ mir_snprintf(SettingName, sizeof(SettingName), "%s_%d", cbd->pszModuleName, cbd->dwButtonOrigID);
+ mir_snprintf(SettingParameter, sizeof(SettingParameter), "%d_%u_%u_%u_%u_%u", cbd->dwPosition, cbd->bIMButton, cbd->bChatButton, cbd->bLSided, cbd->bRSided, cbd->bCanBeHidden);
+ if (!(cbd->opFlags&BBSF_NTBDESTRUCT))
+ DBWriteContactSettingString(hContact, "TabSRMM_Toolbar", SettingName, SettingParameter);
+ else
+ DBDeleteContactSetting(hContact, "TabSRMM_Toolbar", SettingName);
+}
+
+void BB_RegisterSeparators()
+{
+ BBButton bbd = {0};
+ DWORD i = 0;
+ bbd.cbSize = sizeof(BBButton);
+ bbd.pszModuleName = "Tabsrmm_sep";
+ for (; dwSepCount > i; i++) {
+ bbd.bbbFlags = BBBF_ISDUMMYBUTTON | BBBF_ISIMBUTTON | BBBF_ISLSIDEBUTTON;
+ bbd.dwButtonID = i + 1;
+ bbd.dwDefPos = 410 + i;
+ CB_AddButton(0, (LPARAM)&bbd);
+ }
+}
+
+void BB_RefreshTheme(const TWindowData *dat)
+{
+ int i;
+
+ for (i = 0; i < RButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)RButtonsList->items[i];
+ SendMessage(GetDlgItem(dat->hwnd, cbd->dwButtonCID), WM_THEMECHANGED, 0, 0);
+ }
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ CustomButtonData* cbd = (CustomButtonData *)LButtonsList->items[i];
+ SendMessage(GetDlgItem(dat->hwnd, cbd->dwButtonCID), WM_THEMECHANGED, 0, 0);
+ }
+}
+
+void CB_InitDefaultButtons()
+{
+ BBButton bbd = {0};
+ bbd.cbSize = sizeof(BBButton);
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISLSIDEBUTTON | BBBF_ISARROWBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_PROTOCOL;
+ bbd.dwDefPos = 10;
+ bbd.hIcon = LoadSkinnedIconHandle(SKINICON_OTHER_CONNECTING);
+ bbd.pszModuleName = "Tabsrmm";
+ bbd.ptszTooltip = _T("Protocol Button");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISLSIDEBUTTON | BBBF_ISARROWBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_NAME;
+ bbd.dwDefPos = 20;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[20];
+ bbd.ptszTooltip = _T("Info button");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ if (PluginConfig.g_SmileyAddAvail) {
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISCHATBUTTON | BBBF_ISLSIDEBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_SMILEYBTN;
+ bbd.iButtonWidth = 0;
+ bbd.dwDefPos = 30;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[9];
+ bbd.ptszTooltip = _T("Insert Emoticon");
+ CB_AddButton(0, (LPARAM)&bbd);
+ }
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISCHATBUTTON | BBBF_ISLSIDEBUTTON | BBBF_ISPUSHBUTTON | BBBF_CANBEHIDDEN | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_FONTBOLD;
+ bbd.dwDefPos = 40;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[10];
+ bbd.ptszTooltip = _T("Bold text");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISCHATBUTTON | BBBF_ISLSIDEBUTTON | BBBF_ISPUSHBUTTON | BBBF_CANBEHIDDEN | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_FONTITALIC;
+ bbd.dwDefPos = 50;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[11];
+ bbd.ptszTooltip = _T("Italic text");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISCHATBUTTON | BBBF_ISLSIDEBUTTON | BBBF_ISPUSHBUTTON | BBBF_CANBEHIDDEN | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_FONTUNDERLINE;
+ bbd.dwDefPos = 60;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[12];
+ bbd.ptszTooltip = _T("Underlined text");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISLSIDEBUTTON | BBBF_ISPUSHBUTTON | BBBF_CANBEHIDDEN | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_FONTSTRIKEOUT;
+ bbd.dwDefPos = 70;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[15];
+ bbd.ptszTooltip = _T("Strike-through text");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISCHATBUTTON | BBBF_ISLSIDEBUTTON | BBBF_CANBEHIDDEN | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_FONTFACE;
+ bbd.dwDefPos = 80;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[14];
+ bbd.ptszTooltip = _T("Select font color");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISCHATBUTTON | BBBF_ISRSIDEBUTTON | BBBF_ISARROWBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDOK;
+ bbd.dwDefPos = 10;
+ bbd.iButtonWidth = 51;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[6];
+ bbd.ptszTooltip = _T("Send message\nClick dropdown arrow for sending options");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISCHATBUTTON | BBBF_ISRSIDEBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_SAVE;
+ bbd.dwDefPos = 20;
+ bbd.iButtonWidth = 0;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[8];
+ bbd.ptszTooltip = _T("Close session");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISRSIDEBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_QUOTE;
+ bbd.dwDefPos = 30;
+ bbd.iButtonWidth = 0;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[4];
+ bbd.ptszTooltip = _T("Quote last message OR selected text");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISRSIDEBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_TIME;
+ bbd.dwDefPos = 40;
+ bbd.iButtonWidth = 0;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[2];
+ bbd.ptszTooltip = _T("Message Log Options");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISCHATBUTTON | BBBF_ISRSIDEBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_HISTORY;
+ bbd.dwDefPos = 50;
+ bbd.iButtonWidth = 0;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[0];
+ bbd.ptszTooltip = _T("View User's History");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISRSIDEBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_PIC;
+ bbd.dwDefPos = 60;
+ bbd.iButtonWidth = 0;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[7];
+ bbd.ptszTooltip = _T("Edit user notes");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ //chat buttons
+
+ bbd.bbbFlags = BBBF_ISCHATBUTTON | BBBF_ISLSIDEBUTTON | BBBF_ISDUMMYBUTTON;
+ bbd.dwButtonID = 1;
+ bbd.pszModuleName = "tb_splitter";
+ bbd.dwDefPos = 31;
+ bbd.iButtonWidth = 22;
+ bbd.hIcon = 0;
+ bbd.pszTooltip = 0;
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISCHATBUTTON | BBBF_ISLSIDEBUTTON | BBBF_ISDUMMYBUTTON;
+ bbd.dwButtonID = 2;
+ bbd.dwDefPos = 22;
+ bbd.iButtonWidth = 22;
+ bbd.hIcon = 0;
+ bbd.pszTooltip = 0;
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+
+ bbd.bbbFlags = BBBF_ISCHATBUTTON | BBBF_ISLSIDEBUTTON | BBBF_ISDUMMYBUTTON;
+ bbd.dwButtonID = 3;
+ bbd.dwDefPos = 71;
+ bbd.iButtonWidth = 22;
+ bbd.hIcon = 0;
+ bbd.pszTooltip = 0;
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISCHATBUTTON | BBBF_ISLSIDEBUTTON | BBBF_ISPUSHBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_BKGCOLOR;
+ bbd.pszModuleName = "Tabsrmm";
+ bbd.dwDefPos = 81;
+ bbd.iButtonWidth = 22;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[16];
+ bbd.ptszTooltip = _T("Change background color");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+ //
+
+ bbd.bbbFlags = BBBF_ISCHATBUTTON | BBBF_ISRSIDEBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_SHOWNICKLIST;
+ bbd.dwDefPos = 22;
+ bbd.iButtonWidth = 22;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[19];
+ bbd.ptszTooltip = _T("Toggle nick list");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISCHATBUTTON | BBBF_ISRSIDEBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_FILTER;
+ bbd.dwDefPos = 24;
+ bbd.iButtonWidth = 22;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[18];
+ bbd.ptszTooltip = _T("Event filter - right click to setup, left click to activate/deactivate");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+ bbd.bbbFlags = BBBF_ISCHATBUTTON | BBBF_ISRSIDEBUTTON | BBBF_CREATEBYID;
+ bbd.dwButtonID = IDC_CHANMGR;
+ bbd.dwDefPos = 33;
+ bbd.iButtonWidth = 22;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[17];
+ bbd.ptszTooltip = _T("Channel manager");
+
+ CB_AddButton(0, (LPARAM)&bbd);
+
+
+ BB_RegisterSeparators();
+}
+
+#define MIDDLE_SEPARATOR _T(">-------M-------<")
+
+static int SaveTree(HWND hToolBarTree)
+{
+ TVITEM tvi;
+ HTREEITEM hItem = NULL;
+ BOOL RSide = FALSE;
+ int count = 10;
+ DWORD loc_sepcout = 0;
+ TCHAR strbuf[128];
+ CustomButtonData* cbd = NULL;
+
+ tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_HANDLE;
+ tvi.hItem = TreeView_GetRoot(hToolBarTree);
+ tvi.pszText = strbuf;
+ tvi.cchTextMax = sizeof(strbuf);
+ EnterCriticalSection(&ToolBarCS);
+ while (tvi.hItem != NULL) {
+
+ TreeView_GetItem(hToolBarTree, &tvi);
+
+ if (_tcscmp(tvi.pszText, MIDDLE_SEPARATOR) == 0) {
+ RSide = TRUE;
+ count = TreeView_GetCount(hToolBarTree) * 10 - count;
+ tvi.hItem = TreeView_GetNextSibling(hToolBarTree, tvi.hItem);
+ continue;
+ }
+ cbd = (CustomButtonData*)tvi.lParam;
+ if (cbd) {
+ if (cbd->opFlags) {
+ cbd->bIMButton = (cbd->opFlags & BBSF_IMBUTTON) ? 1 : 0;
+ cbd->bChatButton = (cbd->opFlags & BBSF_CHATBUTTON) ? 1 : 0;
+ cbd->bCanBeHidden = (cbd->opFlags & BBSF_CANBEHIDDEN) ? 1 : 0;
+ }
+ if (RSide && cbd->bLSided) {
+ cbd->bLSided = FALSE;
+ cbd->bRSided = TRUE;
+ cbd->opFlags |= BBSF_NTBSWAPED;
+ } else if (!RSide && cbd->bRSided) {
+ cbd->bLSided = TRUE;
+ cbd->bRSided = FALSE;
+ cbd->opFlags |= BBSF_NTBSWAPED;
+ }
+ if (!TreeView_GetCheckState(hToolBarTree, tvi.hItem)) {
+ cbd->bIMButton = FALSE;
+ cbd->bChatButton = FALSE;
+
+ if (cbd->bDummy && !strcmp(cbd->pszModuleName, "Tabsrmm_sep"))
+ cbd->opFlags = BBSF_NTBDESTRUCT;
+ } else {
+ if (!cbd->bIMButton && !cbd->bChatButton)
+ cbd->bIMButton = TRUE;
+ if (cbd->bDummy && !strcmp(cbd->pszModuleName, "Tabsrmm_sep")) {
+ cbd->bHidden = 0;
+ cbd->opFlags &= ~BBSF_NTBDESTRUCT;
+ ++loc_sepcout;
+ }
+ }
+
+ cbd->dwPosition = (DWORD)count;
+ CB_WriteButtonSettings(NULL, cbd);
+
+ if (!(cbd->opFlags&BBSF_NTBDESTRUCT))
+ (RSide) ? (count -= 10) : (count += 10);
+ }
+ hItem = TreeView_GetNextSibling(hToolBarTree, tvi.hItem);
+ if (cbd->opFlags&BBSF_NTBDESTRUCT)
+ TreeView_DeleteItem(hToolBarTree, tvi.hItem);
+ tvi.hItem = hItem;
+ }
+ LeaveCriticalSection(&ToolBarCS);
+ M->WriteDword("TabSRMM_Toolbar", "SeparatorsCount", loc_sepcout);
+ dwSepCount = loc_sepcout;
+ bNeedResort = TRUE;
+ return 1;
+}
+
+HIMAGELIST himgl = NULL;
+
+static int BuildMenuObjectsTree(HWND hToolBarTree)
+{
+ TVINSERTSTRUCT tvis;
+ HTREEITEM hti;
+ int iImage = 0;
+ int i;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_SELECTEDIMAGE | TVIF_IMAGE;
+
+ TreeView_DeleteAllItems(hToolBarTree);
+
+ himgl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 2, 2);
+ ImageList_AddIcon(himgl, reinterpret_cast<HICON>(CallService(MS_SKIN2_GETICON, 0, (LPARAM)"core_main_24")));
+ HIMAGELIST himl = TreeView_GetImageList(hToolBarTree, TVSIL_NORMAL);
+ ImageList_Destroy(himl);
+ TreeView_SetImageList(hToolBarTree, himgl, TVSIL_NORMAL);
+
+
+ if ((RButtonsList->realCount + LButtonsList->realCount) == 0)
+ return FALSE;
+ EnterCriticalSection(&ToolBarCS);
+ qsort(LButtonsList->items, LButtonsList->realCount, sizeof(CustomButtonData *), sstSortButtons);
+
+ for (i = 0; i < LButtonsList->realCount; i++) {
+ CustomButtonData * cbd = (CustomButtonData *)LButtonsList->items[i];
+ tvis.item.lParam = (LPARAM)cbd;
+
+ if (cbd->bDummy) {
+ tvis.item.pszText = TranslateTS(_T("<Separator>"));
+ tvis.item.iImage = tvis.item.iSelectedImage = 0;
+ } else {
+ tvis.item.pszText = TranslateTS(cbd->ptszTooltip);
+ iImage = ImageList_AddIcon(himgl, (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)cbd->hIcon));
+ tvis.item.iImage = tvis.item.iSelectedImage = iImage;
+ }
+ cbd->opFlags = 0;
+ hti = TreeView_InsertItem(hToolBarTree, &tvis);
+
+ TreeView_SetCheckState(hToolBarTree, hti, (cbd->bIMButton || cbd->bChatButton));
+ }
+ if (TRUE) {
+ tvis.item.lParam = 0;
+ tvis.item.mask |= TVIF_STATE;
+ tvis.item.pszText = MIDDLE_SEPARATOR;
+ tvis.item.stateMask = TVIS_BOLD;
+ tvis.item.state = TVIS_BOLD;
+ tvis.item.iImage = tvis.item.iSelectedImage = -1;
+ hti = TreeView_InsertItem(hToolBarTree, &tvis);
+ TreeView_SetCheckState(hToolBarTree, hti, 1);
+ }
+
+ qsort(RButtonsList->items, RButtonsList->realCount, sizeof(CustomButtonData *), sstSortButtons);
+
+ for (i = RButtonsList->realCount; i > 0; i--) {
+ CustomButtonData * cbd = (CustomButtonData *)RButtonsList->items[i-1];
+ tvis.item.lParam = (LPARAM)cbd;
+
+ if (cbd->bDummy) {
+ tvis.item.pszText = TranslateTS(_T("<Separator>"));
+ tvis.item.iImage = tvis.item.iSelectedImage = -1;
+ } else {
+ tvis.item.pszText = TranslateTS(cbd->ptszTooltip);
+ iImage = ImageList_AddIcon(himgl, (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)cbd->hIcon));
+ tvis.item.iImage = tvis.item.iSelectedImage = iImage;
+ }
+ tvis.item.state = 0;
+ cbd->opFlags = 0;
+ hti = TreeView_InsertItem(hToolBarTree, &tvis);
+ TreeView_SetCheckState(hToolBarTree, hti, (cbd->bIMButton || cbd->bChatButton));
+ }
+ LeaveCriticalSection(&ToolBarCS);
+ return 1;
+}
+
+
+BOOL drag = FALSE, bOptionsInit = TRUE;
+HANDLE hDragItem = NULL;
+HWND hToolBarTree = NULL;
+
+
+INT_PTR CALLBACK DlgProcToolBar(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg) {
+ case WM_INITDIALOG: {
+ LONG_PTR style;
+ hToolBarTree = GetDlgItem(hwndDlg, IDC_TOOLBARTREE);
+
+ style = GetWindowLongPtr(hToolBarTree, GWL_STYLE);
+ style ^= TVS_CHECKBOXES;
+ SetWindowLongPtr(hToolBarTree, GWL_STYLE, style);
+ style |= TVS_CHECKBOXES;
+ style |= TVS_NOHSCROLL;
+ SetWindowLongPtr(hToolBarTree, GWL_STYLE, style);
+
+ EnterCriticalSection(&ToolBarCS);
+
+ BuildMenuObjectsTree((HWND)hToolBarTree);
+
+ LeaveCriticalSection(&ToolBarCS);
+
+ Utils::enableDlgControl(hwndDlg, IDC_IMCHECK, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_CHATCHECK, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_CANBEHIDDEN, FALSE);
+
+ SendDlgItemMessage(hwndDlg, IDC_SPIN1, UDM_SETRANGE, 0, MAKELONG(10, 0));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN1, UDM_SETPOS, 0, MAKELONG(PluginConfig.g_iButtonsBarGap, 0));
+ TranslateDialogDefault(hwndDlg);
+ bOptionsInit = FALSE;
+ }
+ break;
+
+ case WM_LBUTTONUP: {
+
+ if (!drag)
+ break;
+
+ TreeView_SetInsertMark(hToolBarTree, NULL, 0);
+ drag = 0;
+ ReleaseCapture();
+ {
+ TVHITTESTINFO hti;
+ TVITEM tvi;
+ hti.pt.x = (short)LOWORD(lParam);
+ hti.pt.y = (short)HIWORD(lParam);
+ ClientToScreen(hwndDlg, &hti.pt);
+ ScreenToClient(hToolBarTree, &hti.pt);
+ hti.pt.y -= TreeView_GetItemHeight(hToolBarTree) / 2;
+ TreeView_HitTest(hToolBarTree, &hti);
+ if (hDragItem == hti.hItem) break;
+ if (hti.flags&TVHT_ABOVE) hti.hItem = TVI_FIRST;
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = (HTREEITEM)hDragItem;
+ TreeView_GetItem(hToolBarTree, &tvi);
+ if (hti.flags&(TVHT_ONITEM | TVHT_ONITEMRIGHT) || (hti.hItem == TVI_FIRST)) {
+ TVINSERTSTRUCT tvis;
+ TCHAR strbuf[128];
+ tvis.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
+ tvis.item.stateMask = 0xFFFFFFFF;
+ tvis.item.pszText = strbuf;
+ tvis.item.cchTextMax = sizeof(strbuf);
+ tvis.item.hItem = (HTREEITEM)hDragItem;
+ TreeView_GetItem(hToolBarTree, &tvis.item);
+ TreeView_DeleteItem(hToolBarTree, hDragItem);
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = hti.hItem;
+ TreeView_SelectItem(hToolBarTree, TreeView_InsertItem(hToolBarTree, &tvis));
+ SendMessage((GetParent(hwndDlg)), PSM_CHANGED, 0, 0);
+ }
+ }
+ }
+ break;
+
+ case WM_MOUSEMOVE: {
+ TVHITTESTINFO hti;
+ if (!drag) break;
+
+ hti.pt.x = (short)LOWORD(lParam);
+ hti.pt.y = (short)HIWORD(lParam);
+ ClientToScreen(hwndDlg, &hti.pt);
+ ScreenToClient(hToolBarTree, &hti.pt);
+ TreeView_HitTest(hToolBarTree, &hti);
+ if (hti.flags&(TVHT_ONITEM | TVHT_ONITEMRIGHT)) {
+ HTREEITEM it = hti.hItem;
+ hti.pt.y -= TreeView_GetItemHeight(hToolBarTree) / 2;
+ TreeView_HitTest(hToolBarTree, &hti);
+ if (!(hti.flags&TVHT_ABOVE))
+ TreeView_SetInsertMark(hToolBarTree, hti.hItem, 1);
+ else
+ TreeView_SetInsertMark(hToolBarTree, it, 0);
+ } else {
+ if (hti.flags&TVHT_ABOVE) SendMessage(hToolBarTree, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0);
+ if (hti.flags&TVHT_BELOW) SendMessage(hToolBarTree, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0);
+ TreeView_SetInsertMark(hToolBarTree, NULL, 0);
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == BN_CLICKED && GetFocus() == (HWND)lParam && (HWND)lParam != hToolBarTree)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ if ((HIWORD(wParam) == EN_CHANGE) && ((HWND)lParam == GetFocus()))
+ if (!bOptionsInit)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+
+ switch (LOWORD(wParam)) {
+ case IDC_BBRESET: {
+ Hlp_RemoveDatabaseSettings(NULL, "TabSRMM_Toolbar", 0);
+ CB_HardReInit();
+ BuildMenuObjectsTree(hToolBarTree);
+ }
+ break;
+
+ case IDC_SEPARATOR: {
+ int i = 0;
+ HTREEITEM hti;
+ TVINSERTSTRUCT tvis;
+ CustomButtonData* cbd;
+
+ hti = TreeView_GetSelection(hToolBarTree);
+ if (!hti)
+ hti = TVI_FIRST;
+ cbd = (CustomButtonData *)mir_alloc(sizeof(CustomButtonData));
+ ZeroMemory(cbd, sizeof(CustomButtonData));
+
+ cbd->bDummy = 1;
+ cbd->bHidden = 1;
+ cbd->bIMButton = 1;
+ cbd->bLSided = 1;
+ cbd->dwButtonOrigID = ++dwSepCount;
+ cbd->pszModuleName = "Tabsrmm_sep";
+ cbd->iButtonWidth = 22;
+ cbd->opFlags = BBSF_NTBDESTRUCT;
+ li.List_InsertPtr(LButtonsList, cbd);
+
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = hti;
+ tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+
+ tvis.item.pszText = TranslateTS(_T("<Separator>"));
+ tvis.item.iImage = tvis.item.iSelectedImage = -1;
+ tvis.item.lParam = (LPARAM)cbd;
+
+ hti = TreeView_InsertItem(hToolBarTree, &tvis);
+
+ TreeView_SetCheckState(hToolBarTree, hti, (cbd->bIMButton || cbd->bChatButton));
+ }
+ break;
+ }
+ break;
+
+ case WM_NOTIFY: {
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY: {
+ TVITEM tvi;
+ HTREEITEM hti;
+ CustomButtonData* cbd;
+
+ hti = TreeView_GetSelection(hToolBarTree);
+
+ if (hti) {
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hti;
+ TreeView_GetItem(hToolBarTree, &tvi);
+
+ if (tvi.lParam) {
+ cbd = (CustomButtonData*)tvi.lParam;
+ if (cbd) {
+ cbd->bIMButton = IsDlgButtonChecked(hwndDlg, IDC_IMCHECK);
+ cbd->bChatButton = IsDlgButtonChecked(hwndDlg, IDC_CHATCHECK);
+ cbd->bCanBeHidden = IsDlgButtonChecked(hwndDlg, IDC_CANBEHIDDEN);
+ }
+ }
+ }
+
+ SaveTree(hToolBarTree);
+ CB_ReInitCustomButtons();
+ PluginConfig.g_iButtonsBarGap = (BYTE)SendDlgItemMessage(hwndDlg, IDC_SPIN1, UDM_GETPOS, 0, 0);
+
+ if (PluginConfig.g_iButtonsBarGap != M->GetByte("ButtonsBarGap", 1))
+ M->BroadcastMessageAsync(WM_SIZE, 0, 0);
+
+ M->WriteByte(SRMSGMOD_T, "ButtonsBarGap", PluginConfig.g_iButtonsBarGap);
+
+ BuildMenuObjectsTree((HWND)hToolBarTree);
+ Utils::enableDlgControl(hwndDlg, IDC_IMCHECK, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_CHATCHECK, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_CANBEHIDDEN, FALSE);
+ return 1;
+ }
+
+ case PSN_RESET: {
+ CB_ReInitCustomButtons();
+ dwSepCount = M->GetDword("TabSRMM_Toolbar", "SeparatorsCount", 0);
+ return 1;
+ }
+ }
+ break;
+
+
+ case IDC_TOOLBARTREE:
+ switch (((LPNMHDR)lParam)->code) {
+
+ case TVN_BEGINDRAGA:
+ case TVN_BEGINDRAGW:
+ SetCapture(hwndDlg);
+ drag = 1;
+ hDragItem = ((LPNMTREEVIEW)lParam)->itemNew.hItem;
+ TreeView_SelectItem(hToolBarTree, hDragItem);
+ break;
+
+ case TVN_SELCHANGINGA:
+ case TVN_SELCHANGINGW:
+ {
+ TVITEM tvi;
+ HTREEITEM hti;
+ TCHAR strbuf[128];
+ CustomButtonData* cbd;
+
+ hti = TreeView_GetSelection(hToolBarTree);
+
+ if (hti == NULL)
+ break;
+
+ tvi.hItem = hti;
+ tvi.pszText = strbuf;
+ tvi.cchTextMax = sizeof(strbuf);
+ tvi.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_PARAM;
+
+ TreeView_GetItem(hToolBarTree, &tvi);
+
+ if (tvi.lParam == 0 || !TreeView_GetCheckState(hToolBarTree, tvi.hItem) || !_tcscmp(tvi.pszText, MIDDLE_SEPARATOR))
+ break;
+
+ cbd = (CustomButtonData*)tvi.lParam;
+ if (cbd) {
+ cbd->opFlags = (IsDlgButtonChecked(hwndDlg, IDC_IMCHECK)) ? BBSF_IMBUTTON : 0;
+ cbd->opFlags |= (IsDlgButtonChecked(hwndDlg, IDC_CHATCHECK)) ? BBSF_CHATBUTTON : 0;
+ cbd->opFlags |= (IsDlgButtonChecked(hwndDlg, IDC_CANBEHIDDEN)) ? BBSF_CANBEHIDDEN : 0;
+
+ cbd->bIMButton = (IsDlgButtonChecked(hwndDlg, IDC_IMCHECK) ? TRUE : FALSE);
+ cbd->bChatButton = (IsDlgButtonChecked(hwndDlg, IDC_CHATCHECK) ? TRUE : FALSE);
+ cbd->bCanBeHidden = (IsDlgButtonChecked(hwndDlg, IDC_CANBEHIDDEN) ? TRUE : FALSE);
+ }
+ }
+ break;
+
+ case TVN_SELCHANGEDW:
+ case TVN_SELCHANGEDA: {
+ TVITEM tvi;
+ HTREEITEM hti;
+ TCHAR strbuf[128];
+ CustomButtonData* cbd;
+
+ hti = TreeView_GetSelection(hToolBarTree);
+
+ if (hti == NULL)
+ break;
+
+ tvi.pszText = strbuf;
+ tvi.cchTextMax = sizeof(strbuf);
+ tvi.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hti;
+ TreeView_GetItem(hToolBarTree, &tvi);
+
+
+ if (!TreeView_GetCheckState(hToolBarTree, tvi.hItem) || !_tcscmp(tvi.pszText, MIDDLE_SEPARATOR)) {
+ Utils::enableDlgControl(hwndDlg, IDC_IMCHECK, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_CHATCHECK, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_CANBEHIDDEN, FALSE);
+ break;
+ }
+
+ if (tvi.lParam == 0)
+ break;
+
+ cbd = (CustomButtonData*)tvi.lParam;
+ if (cbd) {
+ Utils::enableDlgControl(hwndDlg, IDC_IMCHECK, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_CHATCHECK, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_CANBEHIDDEN, TRUE);
+ CheckDlgButton(hwndDlg, IDC_IMCHECK, (cbd->bIMButton) ? 1 : 0);
+ CheckDlgButton(hwndDlg, IDC_CHATCHECK, (cbd->bChatButton) ? 1 : 0);
+ CheckDlgButton(hwndDlg, IDC_CANBEHIDDEN, (cbd->bCanBeHidden) ? 1 : 0);
+ }
+ }
+ break;
+
+ case NM_CLICK: {
+ TVHITTESTINFO hti = {0};
+ GetCursorPos(&hti.pt);
+ ScreenToClient(hToolBarTree, &hti.pt);
+ if (TreeView_HitTest(hToolBarTree, &hti)) {
+ if (hti.flags&TVHT_ONITEMSTATEICON) {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ if (TreeView_GetCheckState(hToolBarTree, hti.hItem)) {
+ Utils::enableDlgControl(hwndDlg, IDC_IMCHECK, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_CHATCHECK, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_CANBEHIDDEN, FALSE);
+ CheckDlgButton(hwndDlg, IDC_IMCHECK, 1);
+ } else {
+ Utils::enableDlgControl(hwndDlg, IDC_IMCHECK, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_CHATCHECK, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_CANBEHIDDEN, TRUE);
+ }
+ TreeView_SelectItem(hToolBarTree, hti.hItem);
+ }
+ }
+ }
+ break;
+
+ }
+ break;
+ }
+ }
+ break;
+
+ case WM_DESTROY: {
+ HIMAGELIST hIml = TreeView_GetImageList(GetDlgItem(hwndDlg, IDC_TOOLBARTREE), TVSIL_NORMAL);
+ ImageList_Destroy(hIml);
+ hIml = TreeView_GetImageList(GetDlgItem(hwndDlg, IDC_TOOLBARTREE), TVSIL_STATE);
+ ImageList_Destroy(hIml);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/plugins/TabSRMM/src/commonheaders.h b/plugins/TabSRMM/src/commonheaders.h
new file mode 100644
index 0000000000..7b40ad1117
--- /dev/null
+++ b/plugins/TabSRMM/src/commonheaders.h
@@ -0,0 +1,291 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: commonheaders.h 13596 2011-04-15 19:07:23Z george.hazan $
+ *
+ * global include file, used to build the precompiled header.
+ *
+ */
+
+
+#ifndef __COMMONHEADERS_H
+#define __COMMONHEADERS_H
+
+#define _UNICODE 1
+
+//#define __LOGDEBUG_ 1 // log some stuff to %profile_dir%/tabsrmm_debug.log
+//#define __FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER 1
+
+//#define __USE_EX_HANDLERS 1
+
+// #define __DELAYED_FOR_3_1 1 // features not going into 3.0.x and will be completed later
+
+#if !defined __DELAYED_FOR_3_1
+ #define __FEAT_EXP_AUTOSPLITTER 1
+#endif
+
+#define WINVER 0x0600
+#define _WIN32_WINNT 0x0600
+#define _WIN32_IE 0x0501
+#define WIN32_LEAN_AND_MEAN
+
+#define MIRANDA_VER 0x0A00
+
+#include <m_stdhdr.h>
+
+#include <windows.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include <shellapi.h>
+#include <uxtheme.h>
+#include <vsstyle.h>
+
+#define TSAPI __stdcall
+#define FASTCALL __fastcall
+
+ /*
+ * text shadow types (DrawThemeTextEx() / Vista+ uxtheme)
+ */
+ #define TST_NONE 0
+ #define TST_SINGLE 1
+ #define TST_CONTINUOUS 2
+
+ typedef struct _DWM_THUMBNAIL_PROPERTIES
+ {
+ DWORD dwFlags;
+ RECT rcDestination;
+ RECT rcSource;
+ BYTE opacity;
+ BOOL fVisible;
+ BOOL fSourceClientAreaOnly;
+ } DWM_THUMBNAIL_PROPERTIES, *PDWM_THUMBNAIL_PROPERTIES;
+
+ enum DWMWINDOWATTRIBUTE
+ {
+ DWMWA_NCRENDERING_ENABLED = 1, // [get] Is non-client rendering enabled/disabled
+ DWMWA_NCRENDERING_POLICY, // [set] Non-client rendering policy
+ DWMWA_TRANSITIONS_FORCEDISABLED, // [set] Potentially enable/forcibly disable transitions
+ DWMWA_ALLOW_NCPAINT, // [set] Allow contents rendered in the non-client area to be visible on the DWM-drawn frame.
+ DWMWA_CAPTION_BUTTON_BOUNDS, // [get] Bounds of the caption button area in window-relative space.
+ DWMWA_NONCLIENT_RTL_LAYOUT, // [set] Is non-client content RTL mirrored
+ DWMWA_FORCE_ICONIC_REPRESENTATION, // [set] Force this window to display iconic thumbnails.
+ DWMWA_FLIP3D_POLICY, // [set] Designates how Flip3D will treat the window.
+ DWMWA_EXTENDED_FRAME_BOUNDS, // [get] Gets the extended frame bounds rectangle in screen space
+ DWMWA_HAS_ICONIC_BITMAP, // [set] Indicates an available bitmap when there is no better thumbnail representation.
+ DWMWA_DISALLOW_PEEK, // [set] Don't invoke Peek on the window.
+ DWMWA_EXCLUDED_FROM_PEEK, // [set] LivePreview exclusion information
+ DWMWA_LAST
+ };
+
+ #define DWM_TNP_RECTDESTINATION 0x00000001
+ #define DWM_TNP_RECTSOURCE 0x00000002
+ #define DWM_TNP_OPACITY 0x00000004
+ #define DWM_TNP_VISIBLE 0x00000008
+ #define DWM_TNP_SOURCECLIENTAREAONLY 0x00000010
+
+ #define DWM_SIT_DISPLAYFRAME 0x00000001 // Display a window frame around the provided bitmap
+
+ typedef HANDLE HTHUMBNAIL;
+ typedef HTHUMBNAIL* PHTHUMBNAIL;
+
+#ifndef BPPF_ERASE
+ typedef enum _BP_BUFFERFORMAT
+ {
+ BPBF_COMPATIBLEBITMAP, // Compatible bitmap
+ BPBF_DIB, // Device-independent bitmap
+ BPBF_TOPDOWNDIB, // Top-down device-independent bitmap
+ BPBF_TOPDOWNMONODIB // Top-down monochrome device-independent bitmap
+ } BP_BUFFERFORMAT;
+
+
+ typedef struct _BP_PAINTPARAMS
+ {
+ DWORD cbSize;
+ DWORD dwFlags; // BPPF_ flags
+ const RECT * prcExclude;
+ const BLENDFUNCTION * pBlendFunction;
+ } BP_PAINTPARAMS, *PBP_PAINTPARAMS;
+
+ #define BPPF_ERASE 1
+ #define BPPF_NOCLIP 2
+ #define BPPF_NONCLIENT 4
+#endif
+
+ typedef struct _DWM_BLURBEHIND
+ {
+ DWORD dwFlags;
+ BOOL fEnable;
+ HRGN hRgnBlur;
+ BOOL fTransitionOnMaximized;
+ } DWM_BLURBEHIND, *PDWM_BLURBEHIND;
+
+ #define DWM_BB_ENABLE 1
+
+#ifndef LOCALE_SISO3166CTRYNAME2
+ #define LOCALE_SISO3166CTRYNAME2 0x00000068 // 3 character ISO country name, eg "USA Vista+
+ #define LOCALE_SISO639LANGNAME2 0x00000067 // 3 character ISO abbreviated language name, eg "eng"
+#endif
+
+#ifndef WM_DWMCOMPOSITIONCHANGED
+ #define WM_DWMCOMPOSITIONCHANGED 0x031E
+ #define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320
+#endif
+
+#ifndef WM_DWMSENDICONICTHUMBNAIL
+ #define WM_DWMSENDICONICTHUMBNAIL 0x0323
+ #define WM_DWMSENDICONICLIVEPREVIEWBITMAP 0x0326
+#endif
+
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <shlwapi.h>
+#include <shlobj.h>
+#include <richedit.h>
+#include <limits.h>
+#include <ctype.h>
+#include <string>
+#include <vector>
+#include <assert.h>
+
+#include "../include/resource.h"
+
+/* State of icon with such flag will not be saved, and you must set it manually */
+#define MBF_OWNERSTATE 0x04
+
+#include <win2k.h>
+#include <newpluginapi.h>
+#include <m_imgsrvc.h>
+#include <m_system.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_button.h>
+#include <m_clist.h>
+#include <m_options.h>
+#include <m_protosvc.h>
+#include <m_utils.h>
+#include <m_skin.h>
+#include <m_contacts.h>
+#include <m_icolib.h>
+#include <m_clc.h>
+#include <m_clui.h>
+#include <m_userinfo.h>
+#include <m_history.h>
+#include <m_addcontact.h>
+#include <m_file.h>
+#include <m_fontservice.h>
+#include <m_acc.h>
+#include <m_chat.h>
+#include <m_protomod.h>
+#include <m_hotkeys.h>
+#include <m_genmenu.h>
+#include <m_popup.h>
+#include <m_timezones.h>
+
+extern struct LIST_INTERFACE li;
+
+#define safe_sizeof(a) (unsigned int)((sizeof((a)) / sizeof((a)[0])))
+
+#include "../include/version.h"
+#include "m_ieview.h"
+#include "m_popup2.h"
+#include "m_metacontacts.h"
+#include "m_fingerprint.h"
+#include "m_nudge.h"
+#include "m_folders.h"
+#include "m_msg_buttonsbar.h"
+#include "m_cln_skinedit.h"
+#include "m_flash.h"
+#include "m_spellchecker.h"
+#include "m_mathmodule.h"
+#include "m_historyevents.h"
+#include "m_buttonbar.h"
+#include "m_updater.h"
+#include "m_smileyadd.h"
+
+#include "../include/msgs.h"
+#include "../include/msgdlgutils.h"
+#include "../include/typingnotify.h"
+#include "../include/generic_msghandlers.h"
+#include "../include/nen.h"
+extern NEN_OPTIONS nen_options;
+#include "../include/functions.h"
+#include "../chat/chat.h"
+
+#include "../include/contactcache.h"
+#include "../include/translator.h"
+#include "../include/themes.h"
+#include "../include/globals.h"
+#include "../include/mim.h"
+#include "../include/sendqueue.h"
+#include "../include/taskbar.h"
+#include "../include/controls.h"
+#include "../include/infopanel.h"
+#include "../include/sidebar.h"
+#include "../include/utils.h"
+#include "../include/sendlater.h"
+
+#include "../chat/muchighlight.h"
+
+#if !defined(_WIN64) && !defined(_USE_32BIT_TIME_T)
+ #define _USE_32BIT_TIME_T
+#else
+ #undef _USE_32BIT_TIME_T
+#endif
+
+#if defined(__GNUWIN32__)
+ #define wEffects wReserved
+#endif
+
+#if defined(__GNUG__)
+#define __except(x) if(x)
+#define __try
+#define __finally
+
+EXCEPTION_POINTERS* GetExceptionInformation()
+{
+ EXCEPTION_POINTERS e;
+ return(&e);
+}
+#endif
+
+/*
+ * tchar-like std::string
+ */
+
+typedef std::basic_string<TCHAR> tstring;
+
+extern HINSTANCE g_hInst;
+extern CSkinItem SkinItems[];
+extern TContainerData *pFirstContainer, *pLastActiveContainer;
+extern HANDLE hTypingNotify;
+
+#define IS_EXTKEY(a) (a & (1 << 24))
+
+#endif /* __COMMONHEADERS_H */
diff --git a/plugins/TabSRMM/src/contactcache.cpp b/plugins/TabSRMM/src/contactcache.cpp
new file mode 100644
index 0000000000..b30290d447
--- /dev/null
+++ b/plugins/TabSRMM/src/contactcache.cpp
@@ -0,0 +1,655 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This programm 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: contactcache.cpp 13336 2011-01-27 20:02:17Z george.hazan $
+ *
+ * contact cache implementation
+ *
+ * the contact cache provides various services to the message window(s)
+ * it also abstracts meta contacts.
+ *
+ */
+
+#include "commonheaders.h"
+
+CContactCache* CContactCache::m_cCache = 0;
+
+CContactCache::CContactCache(const HANDLE hContact)
+{
+ ZeroMemory(this, sizeof(CContactCache));
+
+ m_Valid = m_isMeta = false;
+ m_hContact = hContact;
+ m_wOldStatus = m_wStatus = m_wMetaStatus = ID_STATUS_OFFLINE;
+
+ m_szStatusMsg = m_ListeningInfo = m_xStatusMsg = 0;
+ m_nMax = 0;
+
+ if(hContact) {
+ m_szProto = reinterpret_cast<char *>(::CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)m_hContact, 0));
+ if(m_szProto)
+ m_tszProto = mir_a2t(m_szProto);
+ initPhaseTwo();
+ }
+ else {
+ m_szProto = C_INVALID_PROTO;
+ m_tszProto = C_INVALID_PROTO_T;
+ m_szAccount = C_INVALID_ACCOUNT;
+ m_isMeta = false;
+ m_Valid = false;
+ }
+}
+
+/**
+ * 2nd part of the object initialization that must be callable during the
+ * object's lifetime (not only on construction).
+ */
+void CContactCache::initPhaseTwo()
+{
+ PROTOACCOUNT* acc = 0;
+
+ m_szAccount = 0;
+ if(m_szProto) {
+ acc = reinterpret_cast<PROTOACCOUNT *>(::CallService(MS_PROTO_GETACCOUNT, (WPARAM)0, (LPARAM)m_szProto));
+ if(acc && acc->tszAccountName)
+ m_szAccount = acc->tszAccountName;
+ }
+
+ m_Valid = (m_szProto != 0 && m_szAccount != 0) ? true : false;
+ if(m_Valid) {
+ m_isMeta = (PluginConfig.bMetaEnabled && !strcmp(m_szProto, PluginConfig.szMetaName)) ? true : false;
+ m_isSubcontact = (M->GetByte(m_hContact, PluginConfig.szMetaName, "IsSubcontact", 0) ? true : false);
+ if(m_isMeta)
+ updateMeta(true);
+ updateState();
+ updateFavorite();
+ }
+ else {
+ m_szProto = C_INVALID_PROTO;
+ m_tszProto = C_INVALID_PROTO_T;
+ m_szAccount = C_INVALID_ACCOUNT;
+ m_isMeta = false;
+ }
+}
+
+/**
+ * reset meta contact information. Used when meta contacts are disabled
+ * on user's request.
+ */
+void CContactCache::resetMeta()
+{
+ m_isMeta = false;
+ m_szMetaProto = 0;
+ m_hSubContact = 0;
+ m_tszMetaProto[0] = 0;
+ initPhaseTwo();
+}
+
+/**
+ * if the contact has an open message window, close it.
+ * window procedure will use setWindowData() to reset m_hwnd to 0.
+ */
+void CContactCache::closeWindow()
+{
+ if(m_hwnd)
+ ::SendMessage(m_hwnd, WM_CLOSE, 1, 2);
+}
+
+void CContactCache::updateState()
+{
+ updateNick();
+ updateStatus();
+}
+
+/**
+ * update private copy of the nick name. Use contact list name cache
+ *
+ * @return bool: true if nick has changed.
+ */
+bool CContactCache::updateNick()
+{
+ bool fChanged = false;
+
+ if(m_Valid) {
+ TCHAR *tszNick = reinterpret_cast<TCHAR *>(::CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)m_hContact, GCDNF_TCHAR));
+ if(tszNick)
+ fChanged = (_tcscmp(m_szNick, tszNick) ? true : false);
+ mir_sntprintf(m_szNick, 80, _T("%s"), tszNick ? tszNick : _T("<undef>"));
+ }
+ return(fChanged);
+}
+
+/**
+ * update status mode
+ * @return bool: true if status mode has changed, false if not.
+ */
+bool CContactCache::updateStatus()
+{
+ if(m_Valid) {
+ m_wOldStatus = m_wStatus;
+ m_wStatus = (WORD)DBGetContactSettingWord(m_hContact, m_szProto, "Status", ID_STATUS_OFFLINE);
+
+ return(m_wOldStatus != m_wStatus);
+ }
+ else
+ return(false);
+}
+
+/**
+ * update meta (subcontact and -protocol) status. This runs when the
+ * MC protocol fires one of its events OR when a relevant database value changes
+ * in the master contact.
+ */
+void CContactCache::updateMeta(bool fForce)
+{
+ if(m_Valid) {
+ HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)m_hContact, 0);
+ if (hSubContact && (hSubContact != m_hSubContact || fForce)) {
+ m_hSubContact = hSubContact;
+ m_szMetaProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)m_hSubContact, 0);
+ if (m_szMetaProto) {
+ PROTOACCOUNT *acc = reinterpret_cast<PROTOACCOUNT *>(::CallService(MS_PROTO_GETACCOUNT, (WPARAM)0, (LPARAM)m_szMetaProto));
+ if(acc && acc->tszAccountName)
+ m_szAccount = acc->tszAccountName;
+ m_wMetaStatus = DBGetContactSettingWord(m_hSubContact, m_szMetaProto, "Status", ID_STATUS_OFFLINE);
+ MultiByteToWideChar(CP_ACP, 0, m_szMetaProto, -1, m_tszMetaProto, 40);
+ m_tszMetaProto[39] = 0;
+ }
+ else {
+ m_wMetaStatus = ID_STATUS_OFFLINE;
+ m_tszMetaProto[0] = 0;
+ }
+ }
+ }
+}
+
+/**
+ * obtain the UIN. This is only maintained for open message windows
+ * it also run when the subcontact for a MC changes.
+ */
+bool CContactCache::updateUIN()
+{
+ bool fChanged = false;
+
+ if(m_Valid) {
+ CONTACTINFO ci = {0};
+
+ ci.hContact = getActiveContact();
+ ci.szProto = const_cast<char *>(getActiveProto());
+ ci.cbSize = sizeof(ci);
+
+ ci.dwFlag = CNF_DISPLAYUID | CNF_TCHAR;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ switch (ci.type) {
+ case CNFT_ASCIIZ:
+ mir_sntprintf(m_szUIN, safe_sizeof(m_szUIN), _T("%s"), reinterpret_cast<TCHAR *>(ci.pszVal));
+ mir_free((void *)ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ mir_sntprintf(m_szUIN, safe_sizeof(m_szUIN), _T("%u"), ci.dVal);
+ break;
+ default:
+ m_szUIN[0] = 0;
+ break;
+ }
+ } else
+ m_szUIN[0] = 0;
+
+ }
+ else
+ m_szUIN[0] = 0;
+
+ return(fChanged);
+}
+
+void CContactCache::updateStats(int iType, size_t value)
+{
+ if(m_stats == 0)
+ allocStats();
+
+ switch(iType) {
+ case TSessionStats::UPDATE_WITH_LAST_RCV:
+ if(m_stats->lastReceivedChars) {
+ m_stats->iReceived++;
+ m_stats->messageCount++;
+ }
+ else
+ return;
+ m_stats->iReceivedBytes += m_stats->lastReceivedChars;
+ m_stats->lastReceivedChars = 0;
+ break;
+ case TSessionStats::INIT_TIMER:
+ m_stats->started = time(0);
+ return;
+ case TSessionStats::SET_LAST_RCV:
+ m_stats->lastReceivedChars = (unsigned int)value;
+ return;
+ case TSessionStats::BYTES_SENT:
+ m_stats->iSent++;
+ m_stats->messageCount++;
+ m_stats->iSentBytes += (unsigned int)value;
+ break;
+ }
+}
+
+void CContactCache::allocStats()
+{
+ if(m_stats == 0) {
+ m_stats = new TSessionStats;
+ ::ZeroMemory(m_stats, sizeof(TSessionStats));
+ }
+}
+
+/**
+ * set the window data for this contact. The window procedure of the message
+ * dialog will use this in WM_INITDIALOG and WM_DESTROY to tell the cache
+ * that a message window is open for this contact.
+ *
+ * @param hwnd: window handle
+ * @param dat: _MessageWindowData - window data structure
+ */
+void CContactCache::setWindowData(const HWND hwnd, TWindowData *dat)
+{
+ m_hwnd = hwnd;
+ m_dat = dat;
+ if(hwnd && dat && m_history == 0)
+ allocHistory();
+ if(hwnd)
+ updateStatusMsg();
+ else {
+ /* release memory - not needed when window isn't open */
+ if(m_szStatusMsg) {
+ mir_free(m_szStatusMsg);
+ m_szStatusMsg = 0;
+ }
+ if(m_ListeningInfo) {
+ mir_free(m_ListeningInfo);
+ m_ListeningInfo = 0;
+ }
+ if(m_xStatusMsg) {
+ mir_free(m_xStatusMsg);
+ m_xStatusMsg = 0;
+ }
+ }
+}
+
+/**
+ * saves message to the input history.
+ * it's using streamout in UTF8 format - no unicode "issues" and all RTF formatting is saved to the history.
+ */
+
+void CContactCache::saveHistory(WPARAM wParam, LPARAM lParam)
+{
+ size_t iLength = 0, iStreamLength = 0;
+ int oldTop = 0;
+ char* szFromStream = NULL;
+
+ if(m_hwnd == 0 || m_dat == 0)
+ return;
+
+ if (wParam) {
+ oldTop = m_iHistoryTop;
+ m_iHistoryTop = (int)wParam;
+ }
+
+ szFromStream = ::Message_GetFromStream(GetDlgItem(m_hwnd, IDC_MESSAGE), m_dat, (CP_UTF8 << 16) | (SF_RTFNOOBJS | SFF_PLAINRTF | SF_USECODEPAGE));
+
+ iLength = iStreamLength = (strlen(szFromStream) + 1);
+
+ if (iLength > 0 && m_history != NULL) {
+ if ((m_iHistoryTop == m_iHistorySize) && oldTop == 0) { // shift the stack down...
+ TInputHistory ihTemp = m_history[0];
+ m_iHistoryTop--;
+ ::MoveMemory((void *)&m_history[0], (void *)&m_history[1], (m_iHistorySize - 1) * sizeof(TInputHistory));
+ m_history[m_iHistoryTop] = ihTemp;
+ }
+ if (iLength > m_history[m_iHistoryTop].lLen) {
+ if (m_history[m_iHistoryTop].szText == NULL) {
+ if (iLength < HISTORY_INITIAL_ALLOCSIZE)
+ iLength = HISTORY_INITIAL_ALLOCSIZE;
+ m_history[m_iHistoryTop].szText = (TCHAR *)malloc(iLength);
+ m_history[m_iHistoryTop].lLen = iLength;
+ } else {
+ if (iLength > m_history[m_iHistoryTop].lLen) {
+ m_history[m_iHistoryTop].szText = (TCHAR *)realloc(m_history[m_iHistoryTop].szText, iLength);
+ m_history[m_iHistoryTop].lLen = iLength;
+ }
+ }
+ }
+ ::CopyMemory(m_history[m_iHistoryTop].szText, szFromStream, iStreamLength);
+ if (!oldTop) {
+ if (m_iHistoryTop < m_iHistorySize) {
+ m_iHistoryTop++;
+ m_iHistoryCurrent = m_iHistoryTop;
+ }
+ }
+ }
+ if (szFromStream)
+ free(szFromStream);
+ if (oldTop)
+ m_iHistoryTop = oldTop;
+}
+
+/**
+ * handle the input history scrolling for the message input area
+ * @param wParam: VK_ keyboard code (VK_UP or VK_DOWN)
+ */
+void CContactCache::inputHistoryEvent(WPARAM wParam)
+{
+ if(m_hwnd == 0 || m_dat == 0)
+ return;
+
+ if (m_history != NULL && m_history[0].szText != NULL) { // at least one entry needs to be alloced, otherwise we get a nice infinite loop ;)
+ HWND hwndEdit = ::GetDlgItem(m_hwnd, IDC_MESSAGE);
+ SETTEXTEX stx = {ST_DEFAULT, CP_UTF8};
+
+ if (m_dat->dwFlags & MWF_NEEDHISTORYSAVE) {
+ m_iHistoryCurrent = m_iHistoryTop;
+ if (::GetWindowTextLengthA(hwndEdit) > 0)
+ saveHistory((WPARAM)m_iHistorySize, 0);
+ else
+ m_history[m_iHistorySize].szText[0] = (TCHAR)'\0';
+ }
+ if (wParam == VK_UP) {
+ if (m_iHistoryCurrent == 0)
+ return;
+ m_iHistoryCurrent--;
+ } else {
+ m_iHistoryCurrent++;
+ if (m_iHistoryCurrent > m_iHistoryTop)
+ m_iHistoryCurrent = m_iHistoryTop;
+ }
+ if (m_iHistoryCurrent == m_iHistoryTop) {
+ if (m_history[m_iHistorySize].szText != NULL) { // replace the temp buffer
+ ::SetWindowText(hwndEdit, _T(""));
+ ::SendMessage(hwndEdit, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)m_history[m_iHistorySize].szText);
+ ::SendMessage(hwndEdit, EM_SETSEL, (WPARAM) - 1, (LPARAM) - 1);
+ }
+ } else {
+ if (m_history[m_iHistoryCurrent].szText != NULL) {
+ ::SetWindowText(hwndEdit, _T(""));
+ ::SendMessage(hwndEdit, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)m_history[m_iHistoryCurrent].szText);
+ ::SendMessage(hwndEdit, EM_SETSEL, (WPARAM) - 1, (LPARAM) - 1);
+ } else
+ ::SetWindowText(hwndEdit, _T(""));
+ }
+ ::SendMessage(m_hwnd, WM_COMMAND, MAKEWPARAM(::GetDlgCtrlID(hwndEdit), EN_CHANGE), (LPARAM)hwndEdit);
+ m_dat->dwFlags &= ~MWF_NEEDHISTORYSAVE;
+ }
+}
+
+/**
+ * allocate the input history (on-demand, when it is requested by
+ * opening a message window for this contact).
+ *
+ * note: it allocs historysize + 1 elements, because the + 1 is used
+ * for the temporary buffer which saves the current input line when
+ * using input history scrolling.
+ */
+void CContactCache::allocHistory()
+{
+ m_iHistorySize = M->GetByte("historysize", 15);
+ if (m_iHistorySize < 10)
+ m_iHistorySize = 10;
+ m_history = (TInputHistory *)malloc(sizeof(TInputHistory) * (m_iHistorySize + 1));
+ m_iHistoryCurrent = 0;
+ m_iHistoryTop = 0;
+ if (m_history)
+ ZeroMemory(m_history, sizeof(TInputHistory) * m_iHistorySize);
+ m_history[m_iHistorySize].szText = (TCHAR *)malloc((HISTORY_INITIAL_ALLOCSIZE + 1) * sizeof(TCHAR));
+ m_history[m_iHistorySize].lLen = HISTORY_INITIAL_ALLOCSIZE;
+}
+
+/**
+ * release additional memory resources
+ */
+void CContactCache::releaseAlloced()
+{
+ int i;
+
+ if(m_stats) {
+ delete m_stats;
+ m_stats = 0;
+ }
+
+ if (m_history) {
+ for (i = 0; i <= m_iHistorySize; i++) {
+ if (m_history[i].szText != 0) {
+ free(m_history[i].szText);
+ }
+ }
+ free(m_history);
+ m_history = 0;
+ }
+ if ( lstrcmp( m_tszProto, C_INVALID_PROTO_T ))
+ mir_free(m_tszProto);
+ m_tszProto = NULL;
+ mir_free(m_szStatusMsg);
+ m_szStatusMsg = NULL;
+}
+
+/**
+ * when a contact is deleted, mark it as invalid in the cache and release
+ * all memory it has allocated.
+ */
+void CContactCache::deletedHandler()
+{
+ m_Valid = false;
+ if(m_hwnd)
+ ::SendMessage(m_hwnd, WM_CLOSE, 1, 2);
+
+ releaseAlloced();
+ m_hContact = (HANDLE)-1;
+}
+
+/**
+ * udpate favorite or recent state. runs when user manually adds
+ * or removes a user from that list or when database setting is
+ * changed from elsewhere
+ */
+void CContactCache::updateFavorite()
+{
+ m_isFavorite = M->GetByte(m_hContact, SRMSGMOD_T, "isFavorite", 0) ? true : false;
+ m_isRecent = M->GetDword(m_hContact, "isRecent", 0) ? true : false;
+}
+
+/**
+ * update all or only the given status message information from the database
+ *
+ * @param szKey: char* database key name or 0 to reload all messages
+ */
+void CContactCache::updateStatusMsg(const char *szKey)
+{
+ DBVARIANT dbv = {0};
+ BYTE bStatusMsgValid = 0;
+ INT_PTR res = 0;
+
+ if(!m_Valid)
+ return;
+
+ if(szKey == 0 || (szKey && !strcmp("StatusMsg", szKey))) {
+ if(m_szStatusMsg)
+ mir_free(m_szStatusMsg);
+ m_szStatusMsg = 0;
+ res = M->GetTString(m_hContact, "CList", "StatusMsg", &dbv);
+ if(res == 0) {
+ m_szStatusMsg = (lstrlen(dbv.ptszVal) > 0 ? getNormalizedStatusMsg(dbv.ptszVal) : 0);
+ DBFreeVariant(&dbv);
+ }
+ }
+ if(szKey == 0 || (szKey && !strcmp("ListeningTo", szKey))) {
+ if(m_ListeningInfo)
+ mir_free(m_ListeningInfo);
+ m_ListeningInfo = 0;
+ res = M->GetTString(m_hContact, m_szProto, "ListeningTo", &dbv);
+ if(res == 0) {
+ m_ListeningInfo = (lstrlen(dbv.ptszVal) > 0 ? mir_tstrdup(dbv.ptszVal) : 0);
+ DBFreeVariant(&dbv);
+ }
+ }
+ if(szKey == 0 || (szKey && !strcmp("XStatusMsg", szKey))) {
+ if(m_xStatusMsg)
+ mir_free(m_xStatusMsg);
+ m_xStatusMsg = 0;
+ res = M->GetTString(m_hContact, m_szProto, "XStatusMsg", &dbv);
+ if(res == 0) {
+ m_xStatusMsg = (lstrlen(dbv.ptszVal) > 0 ? mir_tstrdup(dbv.ptszVal) : 0);
+ DBFreeVariant(&dbv);
+ }
+ }
+ m_xStatus = M->GetByte(m_hContact, m_szProto, "XStatusId", 0);
+}
+
+/**
+ * retrieve contact cache entry for the given contact. It _never_ returns zero, for a hContact
+ * 0, it retrieves a dummy object.
+ * Non-existing cache entries are created on demand.
+ *
+ * @param hContact: contact handle
+ * @return CContactCache* pointer to the cache entry for this contact
+ */
+
+CContactCache* CContactCache::getContactCache(const HANDLE hContact)
+{
+ CContactCache *c = m_cCache, *cTemp;
+
+ cTemp = c;
+
+ while(c) {
+ cTemp = c;
+ if(c->m_hContact == hContact) {
+ c->inc();
+ return(c);
+ }
+ c = c->m_next;
+ }
+ CContactCache* _c = new CContactCache(hContact);
+ if(cTemp) {
+ cTemp->m_next = _c;
+ return(_c);
+ }
+ m_cCache = _c;
+ return(_c);
+}
+
+/**
+ * normalize the status message with proper cr/lf sequences.
+ * @param src TCHAR*: original status message
+ * @param fStripAll bool: strip all cr/lf sequences and replace them with spaces (use for title bar)
+ * @return TCHAR*: converted status message. CALLER is responsible to free it, MUST use mir_free()
+ */
+TCHAR* CContactCache::getNormalizedStatusMsg(const TCHAR *src, bool fStripAll)
+{
+ size_t k = 0, i = 0;
+ TCHAR* tszResult = 0;
+
+ if(src == 0 || lstrlen(src) < 2)
+ return(0);
+
+ tstring dest;
+
+ for(i = 0; i < _tcslen(src); i++) {
+ if(src[i] == 0x0d || src[i] == '\t')
+ continue;
+ if(i && src[i] == (TCHAR)0x0a) {
+ if(fStripAll) {
+ dest.append(_T(" "));
+ continue;
+ }
+ dest.append(_T("\n"));
+ continue;
+ }
+ dest += src[i];
+ }
+
+ if(i) {
+ tszResult = (TCHAR *)mir_alloc((dest.length() + 1) * sizeof(TCHAR));
+ _tcscpy(tszResult, dest.c_str());
+ tszResult[dest.length()] = 0;
+ }
+ return(tszResult);
+}
+
+/**
+ * retrieve the tab/title icon for the corresponding session.
+ */
+HICON CContactCache::getIcon(int& iSize) const
+{
+ HICON hIcon;
+
+ if(m_dat && m_hwnd) {
+ if (m_dat->dwFlags & MWF_ERRORSTATE)
+ hIcon = PluginConfig.g_iconErr;
+ else if (m_dat->mayFlashTab)
+ hIcon = m_dat->iFlashIcon;
+ else {
+ if (m_dat->si && m_dat->iFlashIcon) {
+ int sizeX, sizeY;
+
+ hIcon = m_dat->iFlashIcon;
+ Utils::getIconSize(hIcon, sizeX, sizeY);
+ iSize = sizeX;
+ } else if (m_dat->hTabIcon == m_dat->hTabStatusIcon && m_dat->hXStatusIcon)
+ hIcon = m_dat->hXStatusIcon;
+ else
+ hIcon = m_dat->hTabIcon;
+ }
+ }
+ else
+ hIcon = LoadSkinnedProtoIcon(m_szProto, m_wStatus);
+ return(hIcon);
+}
+
+int CContactCache::getMaxMessageLength()
+{
+ HANDLE hContact;
+ const char* szProto;
+
+ hContact = getActiveContact();
+ szProto = getActiveProto();
+
+ if (szProto) {
+
+ m_nMax = CallProtoService(szProto, PS_GETCAPS, PFLAG_MAXLENOFMESSAGE, reinterpret_cast<LPARAM>(hContact));
+ if (m_nMax) {
+ if (M->GetByte("autosplit", 0)) {
+ if(m_hwnd)
+ ::SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_EXLIMITTEXT, 0, 20000);
+ }
+ else {
+ if(m_hwnd)
+ ::SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_EXLIMITTEXT, 0, (LPARAM)m_nMax);
+ }
+ } else {
+ if(m_hwnd)
+ ::SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_EXLIMITTEXT, 0, 20000);
+ m_nMax = 20000;
+ }
+ }
+ return(m_nMax);
+}
diff --git a/plugins/TabSRMM/src/container.cpp b/plugins/TabSRMM/src/container.cpp
new file mode 100644
index 0000000000..2edbca9281
--- /dev/null
+++ b/plugins/TabSRMM/src/container.cpp
@@ -0,0 +1,2734 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: container.cpp 13447 2011-03-14 19:55:07Z george.hazan $
+ *
+ * implements the "Container" window which acts as a toplevel window
+ * for message sessions.
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+extern SESSION_INFO* m_WndList;
+extern ButtonSet g_ButtonSet;
+
+TContainerData *pFirstContainer = 0; // the linked list of struct ContainerWindowData
+TContainerData *pLastActiveContainer = NULL;
+
+static WNDPROC OldContainerWndProc = 0;
+static bool fForceOverlayIcons = false;
+
+static int ServiceParamsOK(ButtonItem *item, WPARAM *wParam, LPARAM *lParam, HANDLE hContact)
+{
+ if (item->dwFlags & BUTTON_PASSHCONTACTW || item->dwFlags & BUTTON_PASSHCONTACTL || item->dwFlags & BUTTON_ISCONTACTDBACTION) {
+ if (hContact == 0)
+ return 0;
+ if (item->dwFlags & BUTTON_PASSHCONTACTW)
+ *wParam = (WPARAM)hContact;
+ else if (item->dwFlags & BUTTON_PASSHCONTACTL)
+ *lParam = (LPARAM)hContact;
+ return 1;
+ }
+ return 1; // doesn't need a paramter
+}
+
+/*
+ * Windows Vista+
+ * extend the glassy area to get aero look for the status bar, tab bar, info panel
+ * and outer margins.
+ */
+
+void TSAPI SetAeroMargins(TContainerData *pContainer)
+{
+ if(M->isAero() && pContainer && !CSkin::m_skinEnabled) {
+ MARGINS m;
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+ RECT rcWnd;
+ POINT pt;
+ LONG sbar_left = 0, sbar_right = 0;
+
+ if(dat) {
+ if(dat->bType == SESSIONTYPE_IM) {
+ if(dat->Panel->isActive())
+ GetWindowRect(GetDlgItem(dat->hwnd, IDC_LOG), &rcWnd);
+ else
+ GetWindowRect(dat->hwnd, &rcWnd);
+ }
+ else {
+ if(dat->Panel->isActive())
+ GetWindowRect(GetDlgItem(dat->hwnd, IDC_CHAT_LOG), &rcWnd);
+ else
+ GetWindowRect(dat->hwnd, &rcWnd);
+ }
+
+ pt.x = rcWnd.left;
+ pt.y = rcWnd.top;
+ ScreenToClient(pContainer->hwnd, &pt);
+ m.cyTopHeight = pt.y;
+ pContainer->MenuBar->setAero(true);
+
+ /*
+ * bottom part
+ */
+
+ GetWindowRect(dat->hwnd, &rcWnd);
+ pt.x = rcWnd.left;
+ if(!pContainer->SideBar->isActive())
+ pt.y = rcWnd.bottom + ((pContainer->iChilds > 1 || !(pContainer->dwFlags & CNT_HIDETABS)) ? pContainer->tBorder : 0);
+ else {
+ pt.y = rcWnd.bottom;
+ sbar_left = (pContainer->SideBar->getFlags() & CSideBar::SIDEBARORIENTATION_LEFT ? pContainer->SideBar->getWidth() : 0);
+ sbar_right = (pContainer->SideBar->getFlags() & CSideBar::SIDEBARORIENTATION_RIGHT ? pContainer->SideBar->getWidth() : 0);
+ }
+ ScreenToClient(pContainer->hwnd, &pt);
+ GetClientRect(pContainer->hwnd, &rcWnd);
+ m.cyBottomHeight = (rcWnd.bottom - pt.y);
+
+ if(m.cyBottomHeight < 0 || m.cyBottomHeight >= rcWnd.bottom)
+ m.cyBottomHeight = 0;
+
+ m.cxLeftWidth = pContainer->tBorder_outer_left;
+ m.cxRightWidth = pContainer->tBorder_outer_right;
+ m.cxLeftWidth += sbar_left;
+ m.cxRightWidth += sbar_right;
+
+ if(memcmp(&m, &pContainer->mOld, sizeof(MARGINS)) != 0) {
+ pContainer->mOld = m;
+ CMimAPI::m_pfnDwmExtendFrameIntoClientArea(pContainer->hwnd, &m);
+ }
+ }
+ }
+ else
+ pContainer->MenuBar->setAero(false);
+}
+
+/*
+ * CreateContainer MUST malloc() a struct ContainerWindowData and pass its address
+ * to CreateDialogParam() via the LPARAM. It also adds the struct to the linked list
+ * of containers.
+ *
+ * The WM_DESTROY handler of the container DlgProc is responsible for free()'ing the
+ * pointer and for removing the struct from the linked list.
+ */
+
+struct TContainerData* TSAPI CreateContainer(const TCHAR *name, int iTemp, HANDLE hContactFrom) {
+ DBVARIANT dbv;
+ char szCounter[10];
+ char *szKey = "TAB_ContainersW";
+ int i, iFirstFree = -1, iFound = FALSE;
+
+ struct TContainerData *pContainer = (struct TContainerData *)malloc(sizeof(struct TContainerData));
+ if (pContainer) {
+ ZeroMemory((void *)pContainer, sizeof(struct TContainerData));
+ _tcsncpy(pContainer->szName, name, CONTAINER_NAMELEN + 1);
+ AppendToContainerList(pContainer);
+
+ if (M->GetByte("limittabs", 0) && !_tcscmp(name, _T("default")))
+ iTemp |= CNT_CREATEFLAG_CLONED;
+ /*
+ * save container name to the db
+ */
+ i = 0;
+ if (!M->GetByte("singlewinmode", 0)) {
+ do {
+ _snprintf(szCounter, 8, "%d", i);
+ if (M->GetTString(NULL, szKey, szCounter, &dbv)) {
+ if (iFirstFree != -1) {
+ pContainer->iContainerIndex = iFirstFree;
+ _snprintf(szCounter, 8, "%d", iFirstFree);
+ }
+ else {
+ pContainer->iContainerIndex = i;
+ }
+ M->WriteTString(NULL, szKey, szCounter, name);
+ BuildContainerMenu();
+ break;
+ }
+ else {
+ if (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR) {
+ if (!_tcsncmp(dbv.ptszVal, name, CONTAINER_NAMELEN)) {
+ pContainer->iContainerIndex = i;
+ iFound = TRUE;
+ }
+ else if (!_tcsncmp(dbv.ptszVal, _T("**free**"), CONTAINER_NAMELEN))
+ iFirstFree = i;
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ while (++i && iFound == FALSE);
+ }
+ else {
+ iTemp |= CNT_CREATEFLAG_CLONED;
+ pContainer->iContainerIndex = 1;
+ }
+
+ if (iTemp & CNT_CREATEFLAG_MINIMIZED)
+ pContainer->dwFlags = CNT_CREATE_MINIMIZED;
+ if (iTemp & CNT_CREATEFLAG_CLONED) {
+ pContainer->dwFlags |= CNT_CREATE_CLONED;
+ pContainer->hContactFrom = hContactFrom;
+ }
+ pContainer->hwnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSGCONTAINER), NULL, DlgProcContainer, (LPARAM) pContainer);
+ return pContainer;
+ }
+ return NULL;
+}
+
+static BOOL CALLBACK ContainerWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bSkinned;
+
+ struct TContainerData *pContainer = (struct TContainerData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ bSkinned = CSkin::m_skinEnabled ? TRUE : FALSE;
+
+ switch (msg) {
+ case WM_NCPAINT: {
+ PAINTSTRUCT ps;
+ HDC hdcReal;
+ RECT rcClient;
+ LONG width, height;
+ HDC hdc;
+ CSkinItem *item = &SkinItems[0], *item_normal, *item_pressed, *item_hot;
+ HICON hIcon;
+ HFONT hOldFont = 0;
+ TEXTMETRIC tm;
+
+ if (!pContainer || !bSkinned)
+ break;
+
+ if (CSkin::m_frameSkins) {
+ RECT rcWindow, rcClient;
+ HDC dcFrame = GetDCEx(hwndDlg, 0, DCX_WINDOW|/*DCX_INTERSECTRGN|*/0x10000); // GetWindowDC(hwndDlg);
+ POINT pt, pt1;
+ LONG clip_top, clip_left;
+ HRGN rgn = 0;
+ CSkinItem *item;
+ TCHAR szWindowText[512];
+ RECT rcText;
+ HDC dcMem = CreateCompatibleDC(pContainer->cachedDC ? pContainer->cachedDC : dcFrame);
+ HBITMAP hbmMem, hbmOld;
+ int i;
+ DRAWITEMSTRUCT dis = {0};
+
+ GetWindowRect(hwndDlg, &rcWindow);
+ GetClientRect(hwndDlg, &rcClient);
+ pt.y = 0;
+ pt.x = 0;
+ ClientToScreen(hwndDlg, &pt);
+ pt1.x = rcClient.right;
+ pt1.y = rcClient.bottom;
+ ClientToScreen(hwndDlg, &pt1);
+ clip_top = pt.y - rcWindow.top;
+ clip_left = pt.x - rcWindow.left;
+
+ rcWindow.right = rcWindow.right - rcWindow.left;
+ rcWindow.bottom = rcWindow.bottom - rcWindow.top;
+ rcWindow.left = rcWindow.top = 0;
+
+ hbmMem = CreateCompatibleBitmap(dcFrame, rcWindow.right, rcWindow.bottom);
+ hbmOld = (HBITMAP)SelectObject(dcMem, hbmMem);
+
+ ExcludeClipRect(dcFrame, clip_left, clip_top, clip_left + (pt1.x - pt.x), clip_top + (pt1.y - pt.y));
+ ExcludeClipRect(dcMem, clip_left, clip_top, clip_left + (pt1.x - pt.x), clip_top + (pt1.y - pt.y));
+ item = pContainer->ncActive ? &SkinItems[ID_EXTBKFRAME] : &SkinItems[ID_EXTBKFRAMEINACTIVE];
+
+ CSkin::DrawItem(dcMem, &rcWindow, item);
+
+ GetWindowText(hwndDlg, szWindowText, 512);
+ szWindowText[511] = 0;
+ hOldFont = (HFONT)SelectObject(dcMem, PluginConfig.hFontCaption);
+ GetTextMetrics(dcMem, &tm);
+ SetTextColor(dcMem, CInfoPanel::m_ipConfig.clrs[IPFONTCOUNT - 1]);
+ SetBkMode(dcMem, TRANSPARENT);
+ rcText.left =20 + CSkin::m_SkinnedFrame_left + CSkin::m_bClipBorder + CSkin::m_titleBarLeftOff;//26;
+ rcText.right = rcWindow.right - 3 * CSkin::m_titleBarButtonSize.cx - 11 - CSkin::m_titleBarRightOff;
+ rcText.top = CSkin::m_captionOffset + CSkin::m_bClipBorder;
+ rcText.bottom = rcText.top + tm.tmHeight;
+ rcText.left += CSkin::m_captionPadding;
+ DrawText(dcMem, szWindowText, -1, &rcText, DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
+ SelectObject(dcMem, hOldFont);
+ /*
+ * icon
+ */
+
+ hIcon = (HICON)SendMessage(hwndDlg, WM_GETICON, ICON_SMALL, 0);
+ DrawIconEx(dcMem, 4 + CSkin::m_SkinnedFrame_left + CSkin::m_bClipBorder + CSkin::m_titleBarLeftOff, rcText.top + (rcText.bottom - rcText.top) / 2 - 8, hIcon, 16, 16, 0, 0, DI_NORMAL);
+
+ // title buttons;
+
+ pContainer->rcClose.top = pContainer->rcMin.top = pContainer->rcMax.top = CSkin::m_titleButtonTopOff;
+ pContainer->rcClose.bottom = pContainer->rcMin.bottom = pContainer->rcMax.bottom = CSkin::m_titleButtonTopOff + CSkin::m_titleBarButtonSize.cy;
+
+ pContainer->rcClose.right = rcWindow.right - 10 - CSkin::m_titleBarRightOff;
+ pContainer->rcClose.left = pContainer->rcClose.right - CSkin::m_titleBarButtonSize.cx;
+
+ pContainer->rcMax.right = pContainer->rcClose.left - 2;
+ pContainer->rcMax.left = pContainer->rcMax.right - CSkin::m_titleBarButtonSize.cx;
+
+ pContainer->rcMin.right = pContainer->rcMax.left - 2;
+ pContainer->rcMin.left = pContainer->rcMin.right - CSkin::m_titleBarButtonSize.cx;
+
+ item_normal = &SkinItems[ID_EXTBKTITLEBUTTON];
+ item_hot = &SkinItems[ID_EXTBKTITLEBUTTONMOUSEOVER];
+ item_pressed = &SkinItems[ID_EXTBKTITLEBUTTONPRESSED];
+
+ for (i = 0; i < 3; i++) {
+ RECT *rc = 0;
+ HICON hIcon;
+
+ switch (i) {
+ case 0:
+ rc = &pContainer->rcMin;
+ hIcon = CSkin::m_minIcon;
+ break;
+ case 1:
+ rc = &pContainer->rcMax;
+ hIcon = CSkin::m_maxIcon;
+ break;
+ case 2:
+ rc = &pContainer->rcClose;
+ hIcon = CSkin::m_closeIcon;
+ break;
+ }
+ if (rc) {
+ item = pContainer->buttons[i].isPressed ? item_pressed : (pContainer->buttons[i].isHot ? item_hot : item_normal);
+ CSkin::DrawItem(dcMem, rc, item);
+ DrawIconEx(dcMem, rc->left + ((rc->right - rc->left) / 2 - 8), rc->top + ((rc->bottom - rc->top) / 2 - 8), hIcon, 16, 16, 0, 0, DI_NORMAL);
+ }
+ }
+ SetBkMode(dcMem, TRANSPARENT);
+ BitBlt(dcFrame, 0, 0, rcWindow.right, rcWindow.bottom, dcMem, 0, 0, SRCCOPY);
+ SelectObject(dcMem, hbmOld);
+ DeleteObject(hbmMem);
+ DeleteDC(dcMem);
+ ReleaseDC(hwndDlg, dcFrame);
+ }
+ else
+ CallWindowProc(OldContainerWndProc, hwndDlg, msg, wParam, lParam);
+
+ hdcReal = BeginPaint(hwndDlg, &ps);
+
+ GetClientRect(hwndDlg, &rcClient);
+ width = rcClient.right - rcClient.left;
+ height = rcClient.bottom - rcClient.top;
+ if (width != pContainer->oldDCSize.cx || height != pContainer->oldDCSize.cy) {
+ CSkinItem *sbaritem = &SkinItems[ID_EXTBKSTATUSBAR];
+ BOOL statusBarSkinnd = !(pContainer->dwFlags & CNT_NOSTATUSBAR) && !sbaritem->IGNORED;
+ LONG sbarDelta = statusBarSkinnd ? pContainer->statusBarHeight : 0;
+
+ pContainer->oldDCSize.cx = width;
+ pContainer->oldDCSize.cy = height;
+
+ if (pContainer->cachedDC) {
+ SelectObject(pContainer->cachedDC, pContainer->oldHBM);
+ DeleteObject(pContainer->cachedHBM);
+ DeleteDC(pContainer->cachedDC);
+ }
+ pContainer->cachedDC = CreateCompatibleDC(hdcReal);
+ pContainer->cachedHBM = CreateCompatibleBitmap(hdcReal, width, height);
+ pContainer->oldHBM = (HBITMAP)SelectObject(pContainer->cachedDC, pContainer->cachedHBM);
+
+ hdc = pContainer->cachedDC;
+
+ if (!CSkin::DrawItem(hdc, &rcClient, item))
+ FillRect(hdc, &rcClient, GetSysColorBrush(COLOR_3DFACE));
+
+ if (sbarDelta) {
+ rcClient.top = rcClient.bottom - sbarDelta;
+ CSkin::DrawItem(hdc, &rcClient, sbaritem);
+ }
+ }
+ BitBlt(hdcReal, 0, 0, width, height, pContainer->cachedDC, 0, 0, SRCCOPY);
+ EndPaint(hwndDlg, &ps);
+ return 0;
+ }
+ case WM_NCLBUTTONDOWN:
+ case WM_NCLBUTTONUP:
+ case WM_NCMOUSEHOVER:
+ case WM_NCMOUSEMOVE:
+ if (pContainer && CSkin::m_frameSkins) {
+ POINT pt;
+ RECT rcWindow;
+ BOOL isMin, isMax, isClose;
+ int i;
+
+ GetCursorPos(&pt);
+ GetWindowRect(hwndDlg, &rcWindow);
+
+ CopyMemory(&pContainer->oldbuttons[0], &pContainer->buttons[0], sizeof(struct TitleBtn) * 3);
+ ZeroMemory(&pContainer->buttons[0], sizeof(struct TitleBtn) * 3);
+ isMin = isMax = isClose = FALSE;
+
+ if (pt.x >= (rcWindow.left + pContainer->rcMin.left) && pt.x <= (rcWindow.left + pContainer->rcClose.right) && pt.y < rcWindow.top + 24 && wParam != HTTOPRIGHT) {
+ LRESULT result = 0; //DefWindowProc(hwndDlg, msg, wParam, lParam);
+ HDC hdc = GetWindowDC(hwndDlg);
+ LONG left = rcWindow.left;
+
+ pt.y = 10;
+ isMin = pt.x >= left + pContainer->rcMin.left && pt.x <= left + pContainer->rcMin.right;
+ isMax = pt.x >= left + pContainer->rcMax.left && pt.x <= left + pContainer->rcMax.right;
+ isClose = pt.x >= left + pContainer->rcClose.left && pt.x <= left + pContainer->rcClose.right;
+
+ if (msg == WM_NCMOUSEMOVE) {
+ if (isMax)
+ pContainer->buttons[BTN_MAX].isHot = TRUE;
+ else if (isMin)
+ pContainer->buttons[BTN_MIN].isHot = TRUE;
+ else if (isClose)
+ pContainer->buttons[BTN_CLOSE].isHot = TRUE;
+ }
+ else if (msg == WM_NCLBUTTONDOWN) {
+ if (isMax)
+ pContainer->buttons[BTN_MAX].isPressed = TRUE;
+ else if (isMin)
+ pContainer->buttons[BTN_MIN].isPressed = TRUE;
+ else if (isClose)
+ pContainer->buttons[BTN_CLOSE].isPressed = TRUE;
+ }
+ else if (msg == WM_NCLBUTTONUP) {
+ if (isMin)
+ SendMessage(hwndDlg, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+ else if (isMax) {
+ if (IsZoomed(hwndDlg))
+ PostMessage(hwndDlg, WM_SYSCOMMAND, SC_RESTORE, 0);
+ else
+ PostMessage(hwndDlg, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
+ }
+ else if (isClose)
+ PostMessage(hwndDlg, WM_SYSCOMMAND, SC_CLOSE, 0);
+ }
+ for (i = 0; i < 3; i++) {
+ if (pContainer->buttons[i].isHot != pContainer->oldbuttons[i].isHot) {
+ RECT *rc = 0;
+ HICON hIcon;
+
+ switch (i) {
+ case 0:
+ rc = &pContainer->rcMin;
+ hIcon = CSkin::m_minIcon;
+ break;
+ case 1:
+ rc = &pContainer->rcMax;
+ hIcon = CSkin::m_maxIcon;
+ break;
+ case 2:
+ rc = &pContainer->rcClose;
+ hIcon = CSkin::m_closeIcon;
+ break;
+ }
+ if (rc) {
+ CSkinItem *item = &SkinItems[pContainer->buttons[i].isPressed ? ID_EXTBKTITLEBUTTONPRESSED : (pContainer->buttons[i].isHot ? ID_EXTBKTITLEBUTTONMOUSEOVER : ID_EXTBKTITLEBUTTON)];
+ CSkin::DrawItem(hdc, rc, item);
+ DrawIconEx(hdc, rc->left + ((rc->right - rc->left) / 2 - 8), rc->top + ((rc->bottom - rc->top) / 2 - 8), hIcon, 16, 16, 0, 0, DI_NORMAL);
+ }
+ }
+ }
+ ReleaseDC(hwndDlg, hdc);
+ return result;
+ }
+ else {
+ LRESULT result = DefWindowProc(hwndDlg, msg, wParam, lParam);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW | RDW_NOCHILDREN);
+ return result;
+ }
+ }
+ break;
+ case WM_SETCURSOR: {
+ if (CSkin::m_frameSkins && (HWND)wParam == hwndDlg) {
+ DefWindowProc(hwndDlg, msg, wParam, lParam);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW | RDW_NOCHILDREN);
+ return 1;
+ }
+ break;
+ }
+ case WM_NCCALCSIZE: {
+ if (!CSkin::m_frameSkins)
+ break;
+
+ if (wParam) {
+ RECT *rc;
+ NCCALCSIZE_PARAMS *ncsp = (NCCALCSIZE_PARAMS *)lParam;
+
+ DefWindowProc(hwndDlg, msg, wParam, lParam);
+ rc = &ncsp->rgrc[0];
+
+ rc->left += CSkin::m_realSkinnedFrame_left;
+ rc->right -= CSkin::m_realSkinnedFrame_right;
+ rc->bottom -= CSkin::m_realSkinnedFrame_bottom;
+ rc->top += CSkin::m_realSkinnedFrame_caption;
+ return TRUE;
+ }
+ else {
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+ }
+ }
+ case WM_NCACTIVATE:
+ if (pContainer) {
+ pContainer->ncActive = wParam;
+ if (bSkinned && CSkin::m_frameSkins) {
+ SendMessage(hwndDlg, WM_NCPAINT, 0, 0);
+ return 1;
+ }
+ }
+ break;
+ case WM_SETTEXT:
+ case WM_SETICON: {
+ if (CSkin::m_frameSkins) {
+ DefWindowProc(hwndDlg, msg, wParam, lParam);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
+ return 0;
+ }
+ break;
+ }
+ case WM_NCHITTEST: {
+ RECT r;
+ POINT pt;
+ int k = 0;
+ int clip = CSkin::m_bClipBorder;
+
+ if (!pContainer)
+ break;
+
+ if (!(pContainer->dwFlags & CNT_NOTITLE))
+ break;
+
+ GetWindowRect(hwndDlg, &r);
+ GetCursorPos(&pt);
+ if (pt.y <= r.bottom && pt.y >= r.bottom - clip - 6) {
+ if (pt.x > r.left + clip + 10 && pt.x < r.right - clip - 10)
+ return HTBOTTOM;
+ if (pt.x < r.left + clip + 10)
+ return HTBOTTOMLEFT;
+ if (pt.x > r.right - clip - 10)
+ return HTBOTTOMRIGHT;
+
+ }
+ else if (pt.y >= r.top && pt.y <= r.top + 6) {
+ if (pt.x > r.left + clip + 10 && pt.x < r.right - clip - 10)
+ return HTTOP;
+ if (pt.x < r.left + clip + 10)
+ return HTTOPLEFT;
+ if (pt.x > r.right - clip - 10)
+ return HTTOPRIGHT;
+ }
+ else if (pt.x >= r.left && pt.x <= r.left + clip + 6)
+ return HTLEFT;
+ else if (pt.x >= r.right - clip - 6 && pt.x <= r.right)
+ return HTRIGHT;
+
+ return(DefWindowProc(hwndDlg, WM_NCHITTEST, wParam, lParam));
+ }
+ case 0xae: // must be some undocumented message - seems it messes with the title bar...
+ if (CSkin::m_frameSkins)
+ return 0;
+ default:
+ break;
+ }
+ return CallWindowProc(OldContainerWndProc, hwndDlg, msg, wParam, lParam);
+}
+/*
+ * container window procedure...
+ */
+
+static BOOL fHaveTipper = FALSE;
+
+static INT_PTR CALLBACK DlgProcContainer(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct TContainerData *pContainer = 0; // pointer to our struct ContainerWindowData
+ int iItem = 0;
+ TCITEM item;
+ HWND hwndTab;
+ BOOL bSkinned;
+
+ pContainer = (struct TContainerData *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ bSkinned = CSkin::m_skinEnabled ? TRUE : FALSE;
+ hwndTab = GetDlgItem(hwndDlg, IDC_MSGTABS);
+
+ switch (msg) {
+ case WM_INITDIALOG: {
+ DWORD ws;
+ HMENU hSysmenu;
+ DWORD dwCreateFlags;
+ int iMenuItems;
+ int i = 0;
+ ButtonItem *pbItem;
+ HWND hwndButton = 0;
+ bool fAero = M->isAero();
+ BOOL isFlat = M->GetByte("tbflat", 1);
+ BOOL isThemed = !M->GetByte("nlflat", 0);
+
+ fHaveTipper = ServiceExists("mToolTip/ShowTip");
+ fForceOverlayIcons = M->GetByte("forceTaskBarStatusOverlays", 0) ? true : false;
+
+ OldContainerWndProc = (WNDPROC)SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)ContainerWndProc);
+
+ pContainer = (struct TContainerData *) lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) pContainer);
+
+ pContainer->hwnd = hwndDlg;
+ dwCreateFlags = pContainer->dwFlags;
+
+ pContainer->isCloned = (pContainer->dwFlags & CNT_CREATE_CLONED);
+ pContainer->fPrivateThemeChanged = FALSE;
+
+ SendMessage(hwndDlg, DM_OPTIONSAPPLIED, 0, 0); // set options...
+ pContainer->dwFlags |= dwCreateFlags;
+
+ LoadOverrideTheme(pContainer);
+ ws = GetWindowLongPtr(hwndTab, GWL_STYLE);
+ if(pContainer->dwFlagsEx & TCF_FLAT)
+ ws |= TCS_BUTTONS;
+
+ memset((void *)&pContainer->mOld, -1000, sizeof(MARGINS));
+
+ if (pContainer->dwFlagsEx & TCF_SINGLEROWTABCONTROL) {
+ ws &= ~TCS_MULTILINE;
+ ws |= TCS_SINGLELINE;
+ ws |= TCS_FIXEDWIDTH;
+ }
+ else {
+ ws &= ~TCS_SINGLELINE;
+ ws |= TCS_MULTILINE;
+ if (ws & TCS_BUTTONS)
+ ws |= TCS_FIXEDWIDTH;
+ }
+ SetWindowLongPtr(hwndTab, GWL_STYLE, ws);
+
+ pContainer->buttonItems = g_ButtonSet.items;
+
+ pContainer->dwFlags = ((pContainer->dwFlagsEx & (TCF_SBARLEFT | TCF_SBARRIGHT)) ?
+ pContainer->dwFlags | CNT_SIDEBAR : pContainer->dwFlags & ~CNT_SIDEBAR);
+
+ pContainer->SideBar = new CSideBar(pContainer);
+ pContainer->MenuBar = new CMenuBar(hwndDlg, pContainer);
+
+ pbItem = pContainer->buttonItems;
+
+ SetClassLongPtr(hwndDlg, GCL_STYLE, GetClassLongPtr(hwndDlg, GCL_STYLE) & ~(CS_VREDRAW | CS_HREDRAW));
+ SetClassLongPtr(hwndTab, GCL_STYLE, GetClassLongPtr(hwndTab, GCL_STYLE) & ~(CS_VREDRAW | CS_HREDRAW));
+
+ SetClassLongPtr(hwndDlg, GCL_STYLE, GetClassLongPtr(hwndDlg, GCL_STYLE) & ~CS_DROPSHADOW);
+
+ /*
+ * additional system menu items...
+ */
+
+ hSysmenu = GetSystemMenu(hwndDlg, FALSE);
+ iMenuItems = GetMenuItemCount(hSysmenu);
+
+ InsertMenu(hSysmenu, iMenuItems++ - 2, MF_BYPOSITION | MF_SEPARATOR, 0, _T(""));
+ InsertMenu(hSysmenu, iMenuItems++ - 2, MF_BYPOSITION | MF_STRING, IDM_STAYONTOP, CTranslator::get(CTranslator::CNT_MENU_STAYONTOP));
+ if (!CSkin::m_frameSkins)
+ InsertMenu(hSysmenu, iMenuItems++ - 2, MF_BYPOSITION | MF_STRING, IDM_NOTITLE, CTranslator::get(CTranslator::CNT_MENU_HIDETITLEBAR));
+ InsertMenu(hSysmenu, iMenuItems++ - 2, MF_BYPOSITION | MF_SEPARATOR, 0, _T(""));
+ InsertMenu(hSysmenu, iMenuItems++ - 2, MF_BYPOSITION | MF_STRING, IDM_MOREOPTIONS, CTranslator::get(CTranslator::CNT_MENU_CONTAINEROPTIONS));
+ SetWindowText(hwndDlg, CTranslator::get(CTranslator::CNT_TITLE_DEFAULT));
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PluginConfig.g_iconContainer);
+
+ /*
+ * make the tab control the controlling parent window for all message dialogs
+ */
+
+ ws = GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MSGTABS), GWL_EXSTYLE);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MSGTABS), GWL_EXSTYLE, ws | WS_EX_CONTROLPARENT);
+
+ LONG x_pad = M->GetByte("x-pad", 3) + (pContainer->dwFlagsEx & TCF_CLOSEBUTTON ? 7 : 0);
+ LONG y_pad = M->GetByte("y-pad", 3) + ((pContainer->dwFlags & CNT_TABSBOTTOM) ? 1 : 0);
+
+ if(pContainer->dwFlagsEx & TCF_FLAT)
+ y_pad += 1; //(pContainer->dwFlags & CNT_TABSBOTTOM ? 1 : 2);
+
+ TabCtrl_SetPadding(GetDlgItem(hwndDlg, IDC_MSGTABS), x_pad, y_pad);
+
+ TabCtrl_SetImageList(GetDlgItem(hwndDlg, IDC_MSGTABS), PluginConfig.g_hImageList);
+
+ SendMessage(hwndDlg, DM_CONFIGURECONTAINER, 0, 10);
+
+ /*
+ * context menu
+ */
+ pContainer->hMenuContext = PluginConfig.g_hMenuContext;
+ /*
+ * tab tooltips...
+ */
+ if (!fHaveTipper || M->GetByte("d_tooltips", 0) == 0) {
+ pContainer->hwndTip = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT, hwndDlg, NULL, g_hInst, (LPVOID) NULL);
+
+ if (pContainer->hwndTip) {
+ SetWindowPos(pContainer->hwndTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ TabCtrl_SetToolTips(GetDlgItem(hwndDlg, IDC_MSGTABS), pContainer->hwndTip);
+ }
+
+ }
+ else
+ pContainer->hwndTip = 0;
+
+ if (pContainer->dwFlags & CNT_CREATE_MINIMIZED) {
+ WINDOWPLACEMENT wp = {0};
+
+ wp.length = sizeof(wp);
+
+ SetWindowLongPtr(hwndDlg, GWL_STYLE, GetWindowLongPtr(hwndDlg, GWL_STYLE) & ~WS_VISIBLE);
+ ShowWindow(hwndDlg, SW_SHOWMINNOACTIVE);
+ SendMessage(hwndDlg, DM_RESTOREWINDOWPOS, 0, 0);
+ //GetClientRect(hwndDlg, &pContainer->rcSaved);
+ ShowWindow(hwndDlg, SW_SHOWMINNOACTIVE);
+ GetWindowPlacement(hwndDlg, &wp);
+ pContainer->rcSaved.left = pContainer->rcSaved.top = 0;
+ pContainer->rcSaved.right = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
+ pContainer->rcSaved.bottom = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
+ }
+ else {
+ SendMessage(hwndDlg, DM_RESTOREWINDOWPOS, 0, 0);
+ ShowWindow(hwndDlg, SW_SHOWNORMAL);
+ }
+
+ /*
+ * prevent ugly back background being visible while tabbed clients are created
+ */
+ if(M->isAero()) {
+ MARGINS m = {-1};
+ CMimAPI::m_pfnDwmExtendFrameIntoClientArea(hwndDlg, &m);
+ }
+ return TRUE;
+ }
+ case DM_RESTOREWINDOWPOS: {
+ char *szSetting = "CNTW_";
+ char szCName[CONTAINER_NAMELEN + 20];
+ /*
+ * retrieve the container window geometry information from the database.
+ */
+ if (pContainer->isCloned && pContainer->hContactFrom != 0 && !(pContainer->dwFlags & CNT_GLOBALSIZE)) {
+ if (Utils_RestoreWindowPosition(hwndDlg, pContainer->hContactFrom, SRMSGMOD_T, "split")) {
+ if (Utils_RestoreWindowPositionNoMove(hwndDlg, pContainer->hContactFrom, SRMSGMOD_T, "split"))
+ if (Utils_RestoreWindowPosition(hwndDlg, NULL, SRMSGMOD_T, "split"))
+ if (Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, SRMSGMOD_T, "split"))
+ SetWindowPos(hwndDlg, 0, 50, 50, 450, 300, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ }
+ else {
+ if (pContainer->dwFlags & CNT_GLOBALSIZE) {
+ if (Utils_RestoreWindowPosition(hwndDlg, NULL, SRMSGMOD_T, "split"))
+ if (Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, SRMSGMOD_T, "split"))
+ SetWindowPos(hwndDlg, 0, 50, 50, 450, 300, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ else {
+ mir_snprintf(szCName, sizeof(szCName), "%s%d", szSetting, pContainer->iContainerIndex);
+ if (Utils_RestoreWindowPosition(hwndDlg, NULL, SRMSGMOD_T, szCName)) {
+ if (Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, SRMSGMOD_T, szCName))
+ if (Utils_RestoreWindowPosition(hwndDlg, NULL, SRMSGMOD_T, "split"))
+ if (Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, SRMSGMOD_T, "split"))
+ SetWindowPos(hwndDlg, 0, 50, 50, 450, 300, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ }
+ }
+ return(0);
+ }
+
+ case WM_SIZE: {
+ RECT rcClient, rcUnadjusted;
+ int i = 0;
+ TCITEM item = {0};
+ POINT pt = {0};
+ LONG sbarWidth, sbarWidth_left;
+ BOOL sizeChanged = FALSE;
+
+ if (IsIconic(hwndDlg)) {
+ pContainer->dwFlags |= CNT_DEFERREDSIZEREQUEST;
+ break;
+ }
+
+ GetClientRect(hwndDlg, &rcClient);
+ pContainer->MenuBar->getClientRect();
+
+ if (pContainer->hwndStatus) {
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+ RECT rcs;
+
+ SendMessage(pContainer->hwndStatus, WM_USER + 101, 0, (LPARAM)dat);
+ GetWindowRect(pContainer->hwndStatus, &rcs);
+
+ pContainer->statusBarHeight = (rcs.bottom - rcs.top) + 1;
+ SendMessage(pContainer->hwndStatus, SB_SETTEXT, (WPARAM)(SBT_OWNERDRAW) | 2, (LPARAM)0);
+
+ }
+ else
+ pContainer->statusBarHeight = 0;
+
+ CopyRect(&pContainer->rcSaved, &rcClient);
+ rcUnadjusted = rcClient;
+
+ pContainer->MenuBar->Resize(LOWORD(lParam), HIWORD(lParam), sizeChanged ? TRUE : FALSE);
+ LONG rebarHeight = pContainer->MenuBar->getHeight();
+ pContainer->MenuBar->Show((pContainer->dwFlags & CNT_NOMENUBAR) ? SW_HIDE : SW_SHOW);
+
+ sbarWidth = pContainer->SideBar->getWidth();
+ sbarWidth_left = pContainer->SideBar->getFlags() & CSideBar::SIDEBARORIENTATION_LEFT ? sbarWidth : 0;
+
+ if (lParam) {
+ DWORD dwSWPFlags = SWP_NOACTIVATE|SWP_NOZORDER |SWP_DEFERERASE | SWP_NOCOPYBITS; // | SWP_NOSENDCHANGING | SWP_ASYNCWINDOWPOS;
+ if (pContainer->dwFlags & CNT_TABSBOTTOM)
+ SetWindowPos(hwndTab, 0, pContainer->tBorder_outer_left + sbarWidth_left, pContainer->tBorder_outer_top + rebarHeight,
+ (rcClient.right - rcClient.left) - (pContainer->tBorder_outer_left + pContainer->tBorder_outer_right + sbarWidth),
+ (rcClient.bottom - rcClient.top) - pContainer->statusBarHeight - (pContainer->tBorder_outer_top + pContainer->tBorder_outer_bottom) - rebarHeight, dwSWPFlags);
+ else
+ SetWindowPos(hwndTab, 0, pContainer->tBorder_outer_left + sbarWidth_left, pContainer->tBorder_outer_top + rebarHeight,
+ (rcClient.right - rcClient.left) - (pContainer->tBorder_outer_left + pContainer->tBorder_outer_right + sbarWidth),
+ (rcClient.bottom - rcClient.top) - pContainer->statusBarHeight - (pContainer->tBorder_outer_top + pContainer->tBorder_outer_bottom) - rebarHeight, dwSWPFlags);
+ }
+
+ pContainer->SideBar->resizeScrollWnd(sbarWidth_left ? pContainer->tBorder_outer_left : rcClient.right - pContainer->tBorder_outer_right - (sbarWidth - 2),
+ pContainer->tBorder_outer_top + rebarHeight,
+ 0,
+ (rcClient.bottom - rcClient.top) - pContainer->statusBarHeight - (pContainer->tBorder_outer_top + pContainer->tBorder_outer_bottom) - rebarHeight);
+
+ AdjustTabClientRect(pContainer, &rcClient);
+
+ sizeChanged = (((rcClient.right - rcClient.left) != pContainer->preSIZE.cx) ||
+ ((rcClient.bottom - rcClient.top) != pContainer->preSIZE.cy));
+ if (sizeChanged) {
+ pContainer->preSIZE.cx = rcClient.right - rcClient.left;
+ pContainer->preSIZE.cy = rcClient.bottom - rcClient.top;
+ }
+
+
+ /*
+ * we care about all client sessions, but we really resize only the active tab (hwndActive)
+ * we tell inactive tabs to resize theirselves later when they get activated (DM_CHECKSIZE
+ * just queues a resize request)
+ */
+ int nCount = TabCtrl_GetItemCount(hwndTab);
+
+ for (i = 0; i < nCount; i++) {
+ item.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, i, &item);
+ if ((HWND)item.lParam == pContainer->hwndActive) {
+ SetWindowPos((HWND)item.lParam, 0, rcClient.left, rcClient.top, (rcClient.right - rcClient.left), (rcClient.bottom - rcClient.top),
+ SWP_NOSENDCHANGING|SWP_NOACTIVATE/*|SWP_NOCOPYBITS*/);
+ if (!pContainer->bSizingLoop && sizeChanged) {
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+ DM_ScrollToBottom(dat, 0, 1);
+ }
+ }
+ else if (sizeChanged)
+ SendMessage((HWND)item.lParam, DM_CHECKSIZE, 0, 0);
+ }
+ pContainer->SideBar->scrollIntoView();
+
+ if(!M->isAero()) { // aero mode uses buffered paint, no forced redraw needed
+ RedrawWindow(hwndTab, NULL, NULL, RDW_INVALIDATE | (pContainer->bSizingLoop ? RDW_ERASE : 0));
+ RedrawWindow(hwndDlg, NULL, NULL, (bSkinned ? RDW_FRAME : 0) | RDW_INVALIDATE | ((pContainer->bSizingLoop || wParam == SIZE_RESTORED ) ? RDW_ERASE : 0));
+ }
+
+ if (pContainer->hwndStatus)
+ InvalidateRect(pContainer->hwndStatus, NULL, FALSE);
+
+ if (PluginConfig.m_MathModAvail) {
+ TMathWindowInfo mathWndInfo;
+
+ RECT windRect;
+ GetWindowRect(hwndDlg, &windRect);
+ mathWndInfo.top = windRect.top;
+ mathWndInfo.left = windRect.left;
+ mathWndInfo.right = windRect.right;
+ mathWndInfo.bottom = windRect.bottom;
+ CallService(MTH_RESIZE, 0, (LPARAM) &mathWndInfo);
+ }
+ if ((CSkin::m_bClipBorder != 0 || CSkin::m_bRoundedCorner) && CSkin::m_frameSkins) {
+ HRGN rgn;
+ RECT rcWindow;
+ int clip = CSkin::m_bClipBorder;
+
+ GetWindowRect(hwndDlg, &rcWindow);
+
+
+ if (CSkin::m_bRoundedCorner)
+ rgn = CreateRoundRectRgn(clip, clip, (rcWindow.right - rcWindow.left) - clip + 1,
+ (rcWindow.bottom - rcWindow.top) - clip + 1, CSkin::m_bRoundedCorner + clip, CSkin::m_bRoundedCorner + clip);
+ else
+ rgn = CreateRectRgn(clip, clip, (rcWindow.right - rcWindow.left) - clip, (rcWindow.bottom - rcWindow.top) - clip);
+ SetWindowRgn(hwndDlg, rgn, TRUE);
+ }
+ else if (CSkin::m_frameSkins)
+ SetWindowRgn(hwndDlg, NULL, TRUE);
+
+ break;
+ }
+
+ case WM_NOTIFY: {
+ if(pContainer->MenuBar) {
+ LRESULT processed = pContainer->MenuBar->processMsg(msg, wParam, lParam);
+ if(processed != -1) {
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, processed);
+ return(processed);
+ }
+ }
+ NMHDR* pNMHDR = (NMHDR*) lParam;
+ if (pContainer != NULL && pContainer->hwndStatus != 0 && ((LPNMHDR)lParam)->hwndFrom == pContainer->hwndStatus) {
+ switch (((LPNMHDR)lParam)->code) {
+ case NM_CLICK:
+ case NM_RCLICK: {
+ unsigned int nParts, nPanel;
+ NMMOUSE *nm = (NMMOUSE*)lParam;
+ RECT rc;
+
+ nParts = SendMessage(pContainer->hwndStatus, SB_GETPARTS, 0, 0);
+ if (nm->dwItemSpec == 0xFFFFFFFE) {
+ nPanel = 2;
+ SendMessage(pContainer->hwndStatus, SB_GETRECT, nPanel, (LPARAM)&rc);
+ if (nm->pt.x > rc.left && nm->pt.x < rc.right)
+ goto panel_found;
+ else
+ return FALSE;
+ }
+ else
+ nPanel = nm->dwItemSpec;
+panel_found:
+ if (nPanel == 2) {
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+ SendMessage(pContainer->hwndStatus, SB_GETRECT, nPanel, (LPARAM)&rc);
+ if (dat)
+ SI_CheckStatusIconClick(dat, pContainer->hwndStatus, nm->pt, rc, 2, ((LPNMHDR)lParam)->code);
+ }
+ else if (((LPNMHDR)lParam)->code == NM_RCLICK) {
+ POINT pt;
+ HANDLE hContact = 0;
+ HMENU hMenu;
+
+ GetCursorPos(&pt);
+ SendMessage(pContainer->hwndActive, DM_QUERYHCONTACT, 0, (LPARAM)&hContact);
+ if (hContact) {
+ int iSel = 0;
+ hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) hContact, 0);
+ iSel = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL);
+ if (iSel)
+ CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(iSel), MPCF_CONTACTMENU), (LPARAM) hContact);
+ DestroyMenu(hMenu);
+ }
+ }
+ return TRUE;
+ }
+ }
+ break;
+ }
+ switch (pNMHDR->code) {
+ case TCN_SELCHANGE: {
+ ZeroMemory((void *)&item, sizeof(item));
+ iItem = TabCtrl_GetCurSel(hwndTab);
+ item.mask = TCIF_PARAM;
+ if (TabCtrl_GetItem(hwndTab, iItem, &item)) {
+ if ((HWND)item.lParam != pContainer->hwndActive) {
+ if (pContainer->hwndActive && IsWindow(pContainer->hwndActive))
+ ShowWindow(pContainer->hwndActive, SW_HIDE);
+ }
+ pContainer->hwndActive = (HWND) item.lParam;
+ SendMessage((HWND)item.lParam, DM_SAVESIZE, 0, 1);
+ ShowWindow((HWND)item.lParam, SW_SHOW);
+ if (!IsIconic(hwndDlg))
+ SetFocus(pContainer->hwndActive);
+ }
+ SendMessage(hwndTab, EM_VALIDATEBOTTOM, 0, 0);
+ return 0;
+ }
+ /*
+ * tooltips
+ */
+ case NM_RCLICK: {
+ HMENU subMenu;
+ POINT pt, pt1;
+ int iSelection, iItem;
+ TCITEM item = {0};
+ struct TWindowData *dat = 0;
+ bool fFromSidebar = false;
+
+ GetCursorPos(&pt);
+ pt1 = pt;
+ subMenu = GetSubMenu(pContainer->hMenuContext, 0);
+
+ if(pNMHDR->idFrom == IDC_MSGTABS) {
+ if ((iItem = GetTabItemFromMouse(hwndTab, &pt)) == -1)
+ break;
+
+ item.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, iItem, &item);
+ if (item.lParam && IsWindow((HWND)item.lParam))
+ dat = (struct TWindowData *)GetWindowLongPtr((HWND)item.lParam, GWLP_USERDATA);
+ }
+ /*
+ * sent from a sidebar button (RMB click) instead of the tab control
+ */
+ else if(pNMHDR->idFrom == 5000) {
+ TSideBarNotify* n = reinterpret_cast<TSideBarNotify *>(lParam);
+ dat = const_cast<TWindowData *>(n->dat);
+ fFromSidebar = true;
+ }
+
+ if (dat)
+ MsgWindowUpdateMenu(dat, subMenu, MENU_TABCONTEXT);
+
+ iSelection = TrackPopupMenu(subMenu, TPM_RETURNCMD, pt1.x, pt1.y, 0, hwndDlg, NULL);
+ if (iSelection >= IDM_CONTAINERMENU) {
+ DBVARIANT dbv = {0};
+ char szIndex[10];
+ char *szKey = "TAB_ContainersW";
+ mir_snprintf(szIndex, 8, "%d", iSelection - IDM_CONTAINERMENU);
+ if (iSelection - IDM_CONTAINERMENU >= 0) {
+ if (!M->GetTString(NULL, szKey, szIndex, &dbv)) {
+ SendMessage((HWND)item.lParam, DM_CONTAINERSELECTED, 0, (LPARAM) dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ return 1;
+ }
+ switch (iSelection) {
+ case ID_TABMENU_CLOSETAB:
+ if(fFromSidebar)
+ SendMessage(dat->hwnd, WM_CLOSE, 1, 0);
+ else
+ SendMessage(hwndDlg, DM_CLOSETABATMOUSE, 0, (LPARAM)&pt1);
+ break;
+ case ID_TABMENU_SAVETABPOSITION:
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "tabindex", dat->iTabID * 100);
+ break;
+ case ID_TABMENU_CLEARSAVEDTABPOSITION:
+ DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "tabindex");
+ break;
+ case ID_TABMENU_LEAVECHATROOM: {
+ if (dat && dat->bType == SESSIONTYPE_CHAT) {
+ SESSION_INFO *si = (SESSION_INFO *)dat->si;
+ if (si && dat->hContact) {
+ char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) dat->hContact, 0);
+ if ( szProto )
+ CallProtoService( szProto, PS_LEAVECHAT, (WPARAM)dat->hContact, 0 );
+ }
+ }
+ break;
+ }
+ case ID_TABMENU_ATTACHTOCONTAINER:
+ if ((iItem = GetTabItemFromMouse(hwndTab, &pt1)) == -1)
+ break;
+ ZeroMemory((void *)&item, sizeof(item));
+ item.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, iItem, &item);
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_SELECTCONTAINER), hwndDlg, SelectContainerDlgProc, (LPARAM) item.lParam);
+ break;
+ case ID_TABMENU_CONTAINEROPTIONS: {
+ if (pContainer->hWndOptions == 0)
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CONTAINEROPTIONS), hwndDlg, DlgProcContainerOptions, (LPARAM) pContainer);
+ break;
+ case ID_TABMENU_CLOSECONTAINER:
+ SendMessage(hwndDlg, WM_CLOSE, 0, 0);
+ break;
+ }
+ }
+ InvalidateRect(hwndTab, NULL, FALSE);
+ return 1;
+ }
+ }
+ break;
+ }
+
+ case WM_COMMAND: {
+
+ bool fProcessContactMenu = pContainer->MenuBar->isContactMenu();
+ bool fProcessMainMenu = pContainer->MenuBar->isMainMenu();
+ pContainer->MenuBar->Cancel();
+
+ HANDLE hContact;
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+ DWORD dwOldFlags = pContainer->dwFlags;
+ int i = 0;
+ ButtonItem *pItem = pContainer->buttonItems;
+
+ if (dat) {
+ DWORD dwOldMsgWindowFlags = dat->dwFlags;
+ DWORD dwOldEventIsShown = dat->dwFlagsEx;
+
+ if(fProcessContactMenu)
+ return(CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)dat->hContact));
+ else if(fProcessMainMenu) {
+ return(CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_MAINMENU), 0));
+ }
+ else if (MsgWindowMenuHandler(dat, LOWORD(wParam), MENU_PICMENU) == 1)
+ break;
+ }
+ SendMessage(pContainer->hwndActive, DM_QUERYHCONTACT, 0, (LPARAM)&hContact);
+ if (LOWORD(wParam) == IDC_TBFIRSTUID - 1)
+ break;
+ /*
+ else if (LOWORD(wParam) >= IDC_TBFIRSTUID) { // skinnable buttons handling
+ ButtonItem *item = pContainer->buttonItems;
+ WPARAM wwParam = 0;
+ LPARAM llParam = 0;
+ HANDLE hContact = dat ? dat->hContact : 0;
+ int serviceFailure = FALSE;
+
+ while (item) {
+ if (item->uId == (DWORD)LOWORD(wParam)) {
+ int contactOK = ServiceParamsOK(item, &wwParam, &llParam, hContact);
+
+ if (item->dwFlags & BUTTON_ISSERVICE) {
+ if (ServiceExists(item->szService) && contactOK)
+ CallService(item->szService, wwParam, llParam);
+ else if (contactOK)
+ serviceFailure = TRUE;
+ }
+ else if (item->dwFlags & BUTTON_ISPROTOSERVICE) {
+ if (contactOK) {
+ char szFinalService[512];
+
+ mir_snprintf(szFinalService, 512, "%s/%s", (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0), item->szService);
+ if (ServiceExists(szFinalService))
+ CallService(szFinalService, wwParam, llParam);
+ else
+ serviceFailure = TRUE;
+ }
+ }
+ else if (item->dwFlags & BUTTON_ISDBACTION) {
+ BYTE *pValue;
+ char *szModule = item->szModule;
+ char *szSetting = item->szSetting;
+ HANDLE finalhContact = 0;
+
+ if (item->dwFlags & BUTTON_ISCONTACTDBACTION || item->dwFlags & BUTTON_DBACTIONONCONTACT) {
+ contactOK = ServiceParamsOK(item, &wwParam, &llParam, hContact);
+ if (contactOK && item->dwFlags & BUTTON_ISCONTACTDBACTION)
+ szModule = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ finalhContact = hContact;
+ }
+ else
+ contactOK = 1;
+
+ if (contactOK) {
+ BOOL fDelete = FALSE;
+
+ if (item->dwFlags & BUTTON_ISTOGGLE) {
+ BOOL fChecked = (SendMessage(item->hWnd, BM_GETCHECK, 0, 0) == BST_UNCHECKED);
+
+ pValue = fChecked ? item->bValueRelease : item->bValuePush;
+ if (fChecked && pValue[0] == 0)
+ fDelete = TRUE;
+ }
+ else
+ pValue = item->bValuePush;
+
+ if (fDelete)
+ DBDeleteContactSetting(finalhContact, szModule, szSetting);
+ else {
+ switch (item->type) {
+ case DBVT_BYTE:
+ M->WriteByte(finalhContact, szModule, szSetting, pValue[0]);
+ break;
+ case DBVT_WORD:
+ DBWriteContactSettingWord(finalhContact, szModule, szSetting, *((WORD *)&pValue[0]));
+ break;
+ case DBVT_DWORD:
+ M->WriteDword(finalhContact, szModule, szSetting, *((DWORD *)&pValue[0]));
+ break;
+ case DBVT_ASCIIZ:
+ DBWriteContactSettingString(finalhContact, szModule, szSetting, (char *)pValue);
+ break;
+ }
+ }
+ }
+ else if (item->dwFlags & BUTTON_ISTOGGLE)
+ SendMessage(item->hWnd, BM_SETCHECK, 0, 0);
+ }
+ if (!contactOK)
+ MessageBox(0, _T("The requested action requires a valid contact selection. Please select a contact from the contact list and repeat"), _T("Parameter mismatch"), MB_OK);
+ if (serviceFailure) {
+ char szError[512];
+
+ mir_snprintf(szError, 512, "The service %s specified by the %s button definition was not found. You may need to install additional plugins", item->szService, item->szName);
+ MessageBoxA(0, szError, "Service failure", MB_OK);
+ }
+ goto buttons_done;
+ }
+ item = item->nextItem;
+ }
+ }
+ while (pItem) {
+ if (LOWORD(wParam) == pItem->uId) {
+ if (pItem->pfnAction != NULL)
+ pItem->pfnAction(pItem, pContainer->hwndActive, dat, GetDlgItem(hwndDlg, pItem->uId));
+ }
+ pItem = pItem->nextItem;
+ }
+buttons_done:
+ */
+ switch (LOWORD(wParam)) {
+ case IDC_TOGGLESIDEBAR: {
+ RECT rc;
+ LONG dwNewLeft;
+ BOOL skinnedMode = bSkinned;
+
+ if (CMimAPI::m_pfnIsThemeActive)
+ skinnedMode |= (CMimAPI::m_pfnIsThemeActive() ? 1 : 0);
+
+ GetWindowRect(hwndDlg, &rc);
+
+ bool fVisible = pContainer->SideBar->isVisible();
+ if(fVisible) {
+ dwNewLeft = pContainer->SideBar->getWidth();
+ pContainer->SideBar->setVisible(false);
+ }
+ else {
+ pContainer->SideBar->setVisible(true);
+ dwNewLeft = -(pContainer->SideBar->getWidth());
+ }
+
+ pContainer->preSIZE.cx = pContainer->preSIZE.cy = 0;
+ pContainer->oldDCSize.cx = pContainer->oldDCSize.cy = 0;
+
+ PostMessage(hwndDlg, WM_SIZE, 0, 1);
+ break;
+
+ }
+ case IDC_SIDEBARDOWN:
+ case IDC_SIDEBARUP: {
+ HWND hwnd = GetFocus();
+ pContainer->SideBar->processScrollerButtons(LOWORD(wParam));
+ //if(lParam)
+ //SetFocus(GetDlgItem(pContainer->hwndActive, lParam));
+ SetFocus(hwnd);
+ break;
+ }
+ default:
+ Utils::CmdDispatcher(Utils::CMD_CONTAINER, hwndDlg, LOWORD(wParam), wParam, lParam, 0, pContainer);
+ }
+ if (pContainer->dwFlags != dwOldFlags)
+ SendMessage(hwndDlg, DM_CONFIGURECONTAINER, 0, 0);
+ break;
+ }
+ case WM_ENTERSIZEMOVE: {
+ RECT rc;
+ SIZE sz;
+ GetClientRect(GetDlgItem(hwndDlg, IDC_MSGTABS), &rc);
+ sz.cx = rc.right - rc.left;
+ sz.cy = rc.bottom - rc.top;
+ pContainer->oldSize = sz;
+ pContainer->bSizingLoop = TRUE;
+ break;
+ }
+ case WM_EXITSIZEMOVE: {
+ RECT rc;
+
+ GetClientRect(GetDlgItem(hwndDlg, IDC_MSGTABS), &rc);
+ if (!((rc.right - rc.left) == pContainer->oldSize.cx && (rc.bottom - rc.top) == pContainer->oldSize.cy)) {
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+ DM_ScrollToBottom(dat, 0, 0);
+ SendMessage(pContainer->hwndActive, WM_SIZE, 0, 0);
+ }
+ pContainer->bSizingLoop = FALSE;
+ break;
+ }
+ /*
+ * determine minimum and maximum size limits
+ * 1) for maximizing the window when the "vertical maximize" option is set
+ * 2) to limit the minimum height when manually resizing the window
+ * (this avoids overlapping of controls inside the window and ensures
+ * that at least 2 lines of the message log are always visible).
+ */
+ case WM_GETMINMAXINFO: {
+ RECT rc, rcWindow, rcClient = {0};
+ POINT pt;
+ MINMAXINFO *mmi = (MINMAXINFO *) lParam;
+
+ mmi->ptMinTrackSize.x = 275;
+ mmi->ptMinTrackSize.y = 130;
+ GetClientRect(GetDlgItem(hwndDlg, IDC_MSGTABS), &rc);
+ if(pContainer->hwndActive) // at container creation time, there is no hwndActive yet..
+ GetClientRect(pContainer->hwndActive, &rcClient);
+ GetWindowRect(hwndDlg, &rcWindow);
+ pt.y = rc.top;
+ TabCtrl_AdjustRect(GetDlgItem(hwndDlg, IDC_MSGTABS), FALSE, &rc);
+ /*
+ * uChildMinHeight holds the min height for the client window only
+ * so let's add the container's vertical padding (title bar, tab bar,
+ * window border, status bar) to this value
+ */
+ if(pContainer->hwndActive)
+ mmi->ptMinTrackSize.y = pContainer->uChildMinHeight + (pContainer->hwndActive ? ((rcWindow.bottom - rcWindow.top) - rcClient.bottom) : 0);
+
+ if (pContainer->dwFlags & CNT_VERTICALMAX || (GetKeyState(VK_CONTROL) & 0x8000)) {
+ RECT rcDesktop = {0};
+ BOOL fDesktopValid = FALSE;
+ int monitorXOffset = 0;
+ WINDOWPLACEMENT wp = {0};
+
+ if (CMimAPI::m_pfnMonitorFromWindow && CMimAPI::m_pfnGetMonitorInfoA) {
+ HMONITOR hMonitor = CMimAPI::m_pfnMonitorFromWindow(hwndDlg, 2);
+ if (hMonitor) {
+ MONITORINFO mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ CMimAPI::m_pfnGetMonitorInfoA(hMonitor, &mi);
+ rcDesktop = mi.rcWork;
+ OffsetRect(&rcDesktop, -mi.rcMonitor.left, -mi.rcMonitor.top);
+ monitorXOffset = mi.rcMonitor.left;
+ fDesktopValid = TRUE;
+ }
+ }
+ if (!fDesktopValid)
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcDesktop, 0);
+
+ wp.length = sizeof(wp);
+ GetWindowPlacement(hwndDlg, &wp);
+ mmi->ptMaxSize.y = rcDesktop.bottom - rcDesktop.top;
+ mmi->ptMaxSize.x = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
+ mmi->ptMaxPosition.x = wp.rcNormalPosition.left - monitorXOffset;
+ mmi->ptMaxPosition.y = 0;
+ if (IsIconic(hwndDlg)) {
+ mmi->ptMaxPosition.x += rcDesktop.left;
+ mmi->ptMaxPosition.y += rcDesktop.top;
+ }
+
+ /*
+ * protect against invalid values...
+ */
+ if(mmi->ptMinTrackSize.y < 50 || mmi->ptMinTrackSize.y > rcDesktop.bottom)
+ mmi->ptMinTrackSize.y = 130;
+
+ if (PluginConfig.m_MathModAvail) {
+ if (CallService(MTH_GET_PREVIEW_SHOWN, 0, 0)) {
+ RECT rc;
+ HWND hwndMath = FindWindowA("TfrmPreview", "Preview");
+ GetWindowRect(hwndMath, &rc);
+ mmi->ptMaxSize.y -= (rc.bottom - rc.top);
+ }
+ }
+ }
+ return 0;
+ }
+ case WM_MOVE:
+ if (PluginConfig.m_MathModAvail) {
+ TMathWindowInfo mathWndInfo;
+ RECT windRect;
+ GetWindowRect(hwndDlg, &windRect);
+ mathWndInfo.top = windRect.top;
+ mathWndInfo.left = windRect.left;
+ mathWndInfo.right = windRect.right;
+ mathWndInfo.bottom = windRect.bottom;
+ CallService(MTH_RESIZE, 0, (LPARAM) &mathWndInfo);
+ }
+ break;
+ case DM_UPDATETITLE: {
+ HANDLE hContact = 0;
+ const TCHAR *szNewTitle = NULL;
+ TWindowData *dat = NULL;
+
+ if (lParam) { // lParam != 0 means sent by a chat window
+ TCHAR szText[512];
+ dat = (struct TWindowData *)GetWindowLongPtr((HWND)wParam, GWLP_USERDATA);
+ GetWindowText((HWND)wParam, szText, SIZEOF(szText));
+ szText[SIZEOF(szText)-1] = 0;
+ SetWindowText(hwndDlg, szText);
+ if (dat)
+ SendMessage(hwndDlg, DM_SETICON, (WPARAM)dat, (LPARAM)(dat->hTabIcon != dat->hTabStatusIcon ? dat->hTabIcon : dat->hTabStatusIcon));
+ return(0);
+ }
+ if (wParam == 0) { // no hContact given - obtain the hContact for the active tab
+ if (pContainer->hwndActive && IsWindow(pContainer->hwndActive))
+ SendMessage(pContainer->hwndActive, DM_QUERYHCONTACT, 0, (LPARAM)&hContact);
+ else
+ break;
+ dat = (struct TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+ }
+ else {
+ HWND hwnd = M->FindWindow((HANDLE)wParam);
+ if (hwnd == 0) {
+ SESSION_INFO *si = SM_FindSessionByHCONTACT((HANDLE)wParam);
+ if (si) {
+ SendMessage(si->hWnd, GC_UPDATETITLE, 0, 0);
+ return 0;
+ }
+ }
+ hContact = (HANDLE)wParam;
+ if (hwnd && hContact)
+ dat = (struct TWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ }
+ if (dat) {
+ SendMessage(hwndDlg, DM_SETICON, (WPARAM)dat, (LPARAM)(dat->hXStatusIcon ? dat->hXStatusIcon : dat->hTabStatusIcon));
+ szNewTitle = Utils::FormatTitleBar(dat, pContainer->settings->szTitleFormat);
+ if (szNewTitle) {
+ SetWindowText(hwndDlg, szNewTitle);
+ free((void *)szNewTitle);
+ }
+ }
+ return 0;
+ }
+
+
+ case WM_TIMER:
+ if (wParam == TIMERID_HEARTBEAT) {
+ /*
+ int i;
+ TCITEM item = {0};
+ DWORD dwTimeout;
+ */
+ struct TWindowData *dat = 0;
+ /*
+ item.mask = TCIF_PARAM;
+ if ((dwTimeout = PluginConfig.m_TabAutoClose) > 0) {
+ int clients = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_MSGTABS));
+ HWND *hwndClients = (HWND *)mir_alloc(sizeof(HWND) * (clients + 1));
+ for (i = 0; i < clients; i++) {
+ TabCtrl_GetItem(hwndTab, i, &item);
+ hwndClients[i] = (HWND)item.lParam;
+ }
+ for (i = 0; i < clients; i++) {
+ if (IsWindow(hwndClients[i])) {
+ if ((HWND)hwndClients[i] != pContainer->hwndActive)
+ pContainer->bDontSmartClose = TRUE;
+ SendMessage((HWND)hwndClients[i], DM_CHECKAUTOCLOSE, (WPARAM)(dwTimeout * 60), 0);
+ pContainer->bDontSmartClose = FALSE;
+ }
+ }
+ mir_free(hwndClients);
+ }
+ */
+ if(GetForegroundWindow() != hwndDlg && (pContainer->settings->autoCloseSeconds > 0) && !pContainer->fHidden) {
+ BOOL fResult = TRUE;
+ BroadCastContainer(pContainer, DM_CHECKAUTOHIDE, (WPARAM)pContainer->settings->autoCloseSeconds, (LPARAM)&fResult);
+
+ if(fResult && 0 == pContainer->hWndOptions)
+ PostMessage(hwndDlg, WM_CLOSE, 1, 0);
+ }
+ dat = (TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+ if(dat && dat->bType == SESSIONTYPE_IM) {
+ if (dat->idle && pContainer->hwndActive && IsWindow(pContainer->hwndActive))
+ dat->Panel->Invalidate(TRUE);
+ }
+ else if(dat)
+ SendMessage(dat->hwnd, GC_UPDATESTATUSBAR, 0, 0);
+ }
+ else if (wParam == TIMERID_HOVER) {
+ RECT rcWindow;
+ GetWindowRect(hwndDlg, &rcWindow);
+ }
+ break;
+ case WM_SYSCOMMAND:
+ switch (wParam) {
+ case IDM_STAYONTOP:
+ SetWindowPos(hwndDlg, (pContainer->dwFlags & CNT_STICKY) ? HWND_NOTOPMOST : HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ CheckMenuItem(GetSystemMenu(hwndDlg, FALSE), IDM_STAYONTOP, (pContainer->dwFlags & CNT_STICKY) ? MF_BYCOMMAND | MF_UNCHECKED : MF_BYCOMMAND | MF_CHECKED);
+ ApplyContainerSetting(pContainer, CNT_STICKY, pContainer->dwFlags & CNT_STICKY ? 0 : 1, false);
+ break;
+ case IDM_NOTITLE: {
+ pContainer->oldSize.cx = 0;
+ pContainer->oldSize.cy = 0;
+
+ CheckMenuItem(GetSystemMenu(hwndDlg, FALSE), IDM_NOTITLE, (pContainer->dwFlags & CNT_NOTITLE) ? MF_BYCOMMAND | MF_UNCHECKED : MF_BYCOMMAND | MF_CHECKED);
+ ApplyContainerSetting(pContainer, CNT_NOTITLE, pContainer->dwFlags & CNT_NOTITLE ? 0 : 1, false);
+ break;
+ }
+ case IDM_MOREOPTIONS:
+ if (IsIconic(pContainer->hwnd))
+ SendMessage(pContainer->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+ if (pContainer->hWndOptions == 0)
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CONTAINEROPTIONS), hwndDlg, DlgProcContainerOptions, (LPARAM)pContainer);
+ break;
+ case SC_MAXIMIZE:
+ pContainer->oldSize.cx = pContainer->oldSize.cy = 0;
+ break;
+ case SC_RESTORE:
+ pContainer->oldSize.cx = pContainer->oldSize.cy = 0;
+ memset((void *)&pContainer->mOld, -1000, sizeof(MARGINS));
+ break;
+ case SC_MINIMIZE: {
+ TWindowData* dat = reinterpret_cast<TWindowData *>(GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA));
+ if(dat) {
+ //GetWindowRect(GetDlgItem(pContainer->hwndActive, dat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG), &pContainer->rcLogSaved);
+ GetWindowRect(pContainer->hwndActive, &pContainer->rcLogSaved);
+ pContainer->ptLogSaved.x = pContainer->rcLogSaved.left;
+ pContainer->ptLogSaved.y = pContainer->rcLogSaved.top;
+ ScreenToClient(hwndDlg, &pContainer->ptLogSaved);
+ }
+ break;
+ }
+ }
+ break;
+ case DM_SELECTTAB: {
+ switch (wParam) {
+ int iItems, iCurrent, iNewTab;
+ TCITEM item;
+
+ case DM_SELECT_BY_HWND:
+ ActivateTabFromHWND(hwndTab, (HWND) lParam);
+ break;
+ case DM_SELECT_NEXT:
+ case DM_SELECT_PREV:
+ case DM_SELECT_BY_INDEX:
+ iItems = TabCtrl_GetItemCount(hwndTab);
+ iCurrent = TabCtrl_GetCurSel(hwndTab);
+
+ if (iItems == 1)
+ break;
+ if (wParam == DM_SELECT_PREV)
+ iNewTab = iCurrent ? iCurrent - 1 : iItems - 1; // cycle if current is already the leftmost tab..
+ else if (wParam == DM_SELECT_NEXT)
+ iNewTab = (iCurrent == (iItems - 1)) ? 0 : iCurrent + 1;
+ else if (wParam == DM_SELECT_BY_INDEX) {
+ if ((int)lParam > iItems)
+ break;
+ iNewTab = lParam - 1;
+ }
+
+ if (iNewTab != iCurrent) {
+ struct TabControlData *tabdat = (struct TabControlData *)GetWindowLongPtr(hwndTab, GWLP_USERDATA);
+ ZeroMemory((void *)&item, sizeof(item));
+ item.mask = TCIF_PARAM;
+ if (TabCtrl_GetItem(hwndTab, iNewTab, &item)) {
+ TabCtrl_SetCurSel(hwndTab, iNewTab);
+ ShowWindow(pContainer->hwndActive, SW_HIDE);
+ pContainer->hwndActive = (HWND) item.lParam;
+ ShowWindow((HWND)item.lParam, SW_SHOW);
+ SetFocus(pContainer->hwndActive);
+ }
+ }
+ break;
+ }
+ break;
+ }
+ case WM_INITMENUPOPUP:
+ pContainer->MenuBar->setActive(reinterpret_cast<HMENU>(wParam));
+ break;
+
+ case WM_LBUTTONDOWN: {
+ POINT pt;
+
+ if (pContainer->dwFlags & CNT_NOTITLE) {
+ GetCursorPos(&pt);
+ return SendMessage(hwndDlg, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ }
+ break;
+ }
+ /*
+ * pass the WM_ACTIVATE msg to the active message dialog child
+ */
+
+ case WM_NCACTIVATE:
+ if(IsWindowVisible(hwndDlg))
+ pContainer->fHidden = false;
+ break;
+
+ case WM_ACTIVATE:
+ if (pContainer == NULL)
+ break;
+
+ if (LOWORD(wParam == WA_INACTIVE)) {
+ BroadCastContainer(pContainer, DM_CHECKINFOTIP, wParam, lParam);
+ if(PluginConfig.m_MathModAvail)
+ CallService(MTH_HIDE, 0, 0);
+ }
+
+ if (LOWORD(wParam == WA_INACTIVE) && (HWND)lParam != PluginConfig.g_hwndHotkeyHandler && GetParent((HWND)lParam) != hwndDlg) {
+ BOOL fTransAllowed = !bSkinned || PluginConfig.m_bIsVista;
+
+ if (pContainer->dwFlags & CNT_TRANSPARENCY && CMimAPI::m_pSetLayeredWindowAttributes != NULL && fTransAllowed) {
+ CMimAPI::m_pSetLayeredWindowAttributes(hwndDlg, Skin->getColorKey(), (BYTE)HIWORD(pContainer->settings->dwTransparency), (pContainer->dwFlags & CNT_TRANSPARENCY ? LWA_ALPHA : 0));
+ }
+ }
+ pContainer->hwndSaved = 0;
+
+ if (LOWORD(wParam) != WA_ACTIVE) {
+ pContainer->MenuBar->Cancel();
+ break;
+ }
+ case WM_MOUSEACTIVATE: {
+ TCITEM item;
+ int curItem = 0;
+ BOOL fTransAllowed = !bSkinned || PluginConfig.m_WinVerMajor >= 6;
+
+ if (pContainer == NULL)
+ break;
+
+ FlashContainer(pContainer, 0, 0);
+ pContainer->dwFlashingStarted = 0;
+ pLastActiveContainer = pContainer;
+ if (pContainer->dwFlags & CNT_DEFERREDTABSELECT) {
+ NMHDR nmhdr;
+
+ pContainer->dwFlags &= ~CNT_DEFERREDTABSELECT;
+ SendMessage(hwndDlg, WM_SYSCOMMAND, SC_RESTORE, 0);
+ ZeroMemory((void *)&nmhdr, sizeof(nmhdr));
+ nmhdr.code = TCN_SELCHANGE;
+ nmhdr.hwndFrom = hwndTab;
+ nmhdr.idFrom = IDC_MSGTABS;
+ SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM) &nmhdr); // do it via a WM_NOTIFY / TCN_SELCHANGE to simulate user-activation
+ }
+ if (pContainer->dwFlags & CNT_DEFERREDSIZEREQUEST) {
+ pContainer->dwFlags &= ~CNT_DEFERREDSIZEREQUEST;
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ }
+
+ if (pContainer->dwFlags & CNT_TRANSPARENCY && CMimAPI::m_pSetLayeredWindowAttributes != NULL && fTransAllowed) {
+ DWORD trans = LOWORD(pContainer->settings->dwTransparency);
+ CMimAPI::m_pSetLayeredWindowAttributes(hwndDlg, Skin->getColorKey(), (BYTE)trans, (pContainer->dwFlags & CNT_TRANSPARENCY ? LWA_ALPHA : 0));
+ }
+ if (pContainer->dwFlags & CNT_NEED_UPDATETITLE) {
+ HANDLE hContact = 0;
+ pContainer->dwFlags &= ~CNT_NEED_UPDATETITLE;
+ if (pContainer->hwndActive) {
+ SendMessage(pContainer->hwndActive, DM_QUERYHCONTACT, 0, (LPARAM)&hContact);
+ if (hContact)
+ SendMessage(hwndDlg, DM_UPDATETITLE, (WPARAM)hContact, 0);
+ }
+ }
+ ZeroMemory((void *)&item, sizeof(item));
+ item.mask = TCIF_PARAM;
+ if ((curItem = TabCtrl_GetCurSel(hwndTab)) >= 0)
+ TabCtrl_GetItem(hwndTab, curItem, &item);
+ if (pContainer->dwFlags & CNT_DEFERREDCONFIGURE && curItem >= 0) {
+ pContainer->dwFlags &= ~CNT_DEFERREDCONFIGURE;
+ pContainer->hwndActive = (HWND) item.lParam;
+ SendMessage(hwndDlg, WM_SYSCOMMAND, SC_RESTORE, 0);
+ if (pContainer->hwndActive != 0 && IsWindow(pContainer->hwndActive)) {
+ ShowWindow(pContainer->hwndActive, SW_SHOW);
+ SetFocus(pContainer->hwndActive);
+ SendMessage(pContainer->hwndActive, WM_ACTIVATE, WA_ACTIVE, 0);
+ RedrawWindow(pContainer->hwndActive, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
+ }
+ }
+ else if (curItem >= 0)
+ SendMessage((HWND) item.lParam, WM_ACTIVATE, WA_ACTIVE, 0);
+ break;
+ }
+ case DM_CLOSETABATMOUSE: {
+ HWND hwndCurrent;
+ POINT *pt = (POINT *)lParam;
+ int iItem;
+ TCITEM item = {0};
+
+ hwndCurrent = pContainer->hwndActive;
+ if ((iItem = GetTabItemFromMouse(hwndTab, pt)) == -1)
+ break;
+ ZeroMemory((void *)&item, sizeof(item));
+ item.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, iItem, &item);
+ if (item.lParam) {
+ if ((HWND) item.lParam != hwndCurrent) {
+ pContainer->bDontSmartClose = TRUE;
+ SendMessage((HWND) item.lParam, WM_CLOSE, 0, 1);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ pContainer->bDontSmartClose = FALSE;
+ }
+ else
+ SendMessage((HWND) item.lParam, WM_CLOSE, 0, 1);
+ }
+ break;
+ }
+ case WM_PAINT: {
+ bool fAero = M->isAero();
+
+ if (bSkinned || fAero) {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwndDlg, &ps);
+ EndPaint(hwndDlg, &ps);
+ return 0;
+ }
+ break;
+ }
+ case WM_ERASEBKGND: {
+ /*
+ * avoid flickering of the menu bar when aero is active
+ */
+ if(!pContainer)
+ break;
+
+ HDC hdc = (HDC)wParam;
+ RECT rc;
+ GetClientRect(hwndDlg, &rc);
+
+ if (M->isAero()) {
+ HDC hdcMem;
+ HANDLE hbp;
+
+ hbp = CMimAPI::m_pfnBeginBufferedPaint(hdc, &rc, BPBF_TOPDOWNDIB, 0, &hdcMem);
+ FillRect(hdcMem, &rc, CSkin::m_BrushBack);
+ CSkin::FinalizeBufferedPaint(hbp, &rc);
+ }
+ else {
+ if(CSkin::m_skinEnabled)
+ CSkin::DrawItem(hdc, &rc, &SkinItems[ID_EXTBKCONTAINER]);
+ else {
+ CSkin::FillBack(hdc, &rc);
+ if(pContainer->SideBar->isActive() && pContainer->SideBar->isVisible()) {
+
+ HPEN hPen = ::CreatePen(PS_SOLID, 1, PluginConfig.m_cRichBorders ? PluginConfig.m_cRichBorders : ::GetSysColor(COLOR_3DSHADOW));
+ HPEN hOldPen = reinterpret_cast<HPEN>(::SelectObject(hdc, hPen));
+ LONG x = (pContainer->SideBar->getFlags() & CSideBar::SIDEBARORIENTATION_LEFT ? pContainer->SideBar->getWidth() - 2 + pContainer->tBorder_outer_left :
+ rc.right - pContainer->SideBar->getWidth() + 1 - pContainer->tBorder_outer_right);
+ ::MoveToEx(hdc, x, rc.top, 0);
+ ::LineTo(hdc, x, rc.bottom);
+ ::SelectObject(hdc, hOldPen);
+ ::DeleteObject(hPen);
+
+ }
+ }
+ }
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 1);
+ return TRUE;
+ }
+ case DM_OPTIONSAPPLIED: {
+ char szCname[40];
+ TCHAR szTitleFormat[200];
+ TCHAR* szThemeName = NULL;
+ DBVARIANT dbv = {0};
+ char *szSetting = "CNTW_";
+
+ szTitleFormat[0] = 0;
+
+ if (pContainer->isCloned && pContainer->hContactFrom != 0) {
+ //if(pContainer->settings == 0)
+ // pContainer->settings = (TContainerSettings *)malloc(sizeof(TContainerSettings));
+
+ //CopyMemory((void *)pContainer->settings, (void *)&PluginConfig.globalContainerSettings, sizeof(TContainerSettings));
+ //Utils::ReadContainerSettingsFromDB(pContainer->hContactFrom, pContainer->settings);
+
+ pContainer->settings = &PluginConfig.globalContainerSettings;
+
+ pContainer->szRelThemeFile[0] = pContainer->szAbsThemeFile[0] = 0;
+ mir_snprintf(szCname, 40, "%s_theme", szSetting);
+ if (!M->GetTString(pContainer->hContactFrom, SRMSGMOD_T, szCname, &dbv))
+ szThemeName = dbv.ptszVal;
+ }
+ else {
+ Utils::ReadPrivateContainerSettings(pContainer);
+ if (szThemeName == NULL) {
+ mir_snprintf(szCname, 40, "%s%d_theme", szSetting, pContainer->iContainerIndex);
+ if (!M->GetTString(NULL, SRMSGMOD_T, szCname, &dbv))
+ szThemeName = dbv.ptszVal;
+ }
+ }
+ Utils::SettingsToContainer(pContainer);
+
+ if (szThemeName != NULL) {
+ M->pathToAbsolute(szThemeName, pContainer->szAbsThemeFile);
+ mir_sntprintf(pContainer->szRelThemeFile, MAX_PATH, _T("%s"), szThemeName);
+ DBFreeVariant(&dbv);
+ }
+ else
+ pContainer->szAbsThemeFile[0] = pContainer->szRelThemeFile[0] = 0;
+
+ pContainer->ltr_templates = pContainer->rtl_templates = 0;
+ break;
+ }
+ case DM_STATUSBARCHANGED: {
+ RECT rc;
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ GetWindowRect(hwndDlg, &rc);
+ SetWindowPos(hwndDlg, 0, rc.left, rc.top, rc.right - rc.left, (rc.bottom - rc.top) + 1, SWP_NOZORDER | SWP_NOACTIVATE);
+ SetWindowPos(hwndDlg, 0, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_NOACTIVATE);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
+ if (pContainer->hwndStatus != 0 && pContainer->hwndActive != 0)
+ PostMessage(pContainer->hwndActive, DM_STATUSBARCHANGED, 0, 0);
+ return(0);
+ }
+ case DM_CONFIGURECONTAINER: {
+ DWORD ws, wsold, ex = 0, exold = 0;
+ HMENU hSysmenu = GetSystemMenu(hwndDlg, FALSE);
+ HANDLE hContact = 0;
+ int i = 0;
+ UINT sBarHeight;
+ bool fAero = M->isAero();
+
+ ws = wsold = GetWindowLongPtr(hwndDlg, GWL_STYLE);
+ if (!CSkin::m_frameSkins) {
+ ws = (pContainer->dwFlags & CNT_NOTITLE) ?
+ ((IsWindowVisible(hwndDlg) ? WS_VISIBLE : 0) | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN | WS_THICKFRAME | (CSkin::m_frameSkins ? WS_SYSMENU : WS_SYSMENU | WS_SIZEBOX)) :
+ ws | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
+ }
+
+ SetWindowLongPtr(hwndDlg, GWL_STYLE, ws);
+
+ pContainer->tBorder = M->GetByte((bSkinned ? "S_tborder" : "tborder"), 2);
+ pContainer->tBorder_outer_left = g_ButtonSet.left + M->GetByte((bSkinned ? "S_tborder_outer_left" : "tborder_outer_left"), 2);
+ pContainer->tBorder_outer_right = g_ButtonSet.right + M->GetByte((bSkinned ? "S_tborder_outer_right" : "tborder_outer_right"), 2);
+ pContainer->tBorder_outer_top = g_ButtonSet.top + M->GetByte((bSkinned ? "S_tborder_outer_top" : "tborder_outer_top"), 2);
+ pContainer->tBorder_outer_bottom = g_ButtonSet.bottom + M->GetByte((bSkinned ? "S_tborder_outer_bottom" : "tborder_outer_bottom"), 2);
+ sBarHeight = (UINT)M->GetByte((bSkinned ? "S_sbarheight" : "sbarheight"), 0);
+
+ if (LOBYTE(LOWORD(GetVersion())) >= 5 && CMimAPI::m_pSetLayeredWindowAttributes != NULL) {
+ BOOL fTransAllowed = !bSkinned || PluginConfig.m_WinVerMajor >= 6;
+ DWORD exold;
+
+ ex = exold = GetWindowLongPtr(hwndDlg, GWL_EXSTYLE);
+ ex = (pContainer->dwFlags & CNT_TRANSPARENCY && (!CSkin::m_skinEnabled || fTransAllowed)) ? ex | WS_EX_LAYERED : ex & ~(WS_EX_LAYERED);
+ //if(fAero && !pContainer->bSkinned && IsWinVerVistaPlus())
+ // ex = ex | (WS_EX_COMPOSITED);//|WS_EX_LAYERED); // | WS_EX_COMPOSITED); // faster/smoother redrawing on Vista+, especially with skins
+
+ SetWindowLongPtr(hwndDlg, GWL_EXSTYLE, ex);
+ if (pContainer->dwFlags & CNT_TRANSPARENCY && fTransAllowed) {
+ DWORD trans = LOWORD(pContainer->settings->dwTransparency);
+ CMimAPI::m_pSetLayeredWindowAttributes(hwndDlg, Skin->getColorKey(), (BYTE)trans, (/* pContainer->bSkinned ? LWA_COLORKEY : */ 0) | (pContainer->dwFlags & CNT_TRANSPARENCY ? LWA_ALPHA : 0));
+ }
+ }
+
+ if (!CSkin::m_frameSkins)
+ CheckMenuItem(hSysmenu, IDM_NOTITLE, (pContainer->dwFlags & CNT_NOTITLE) ? MF_BYCOMMAND | MF_CHECKED : MF_BYCOMMAND | MF_UNCHECKED);
+
+ CheckMenuItem(hSysmenu, IDM_STAYONTOP, pContainer->dwFlags & CNT_STICKY ? MF_BYCOMMAND | MF_CHECKED : MF_BYCOMMAND | MF_UNCHECKED);
+ SetWindowPos(hwndDlg, (pContainer->dwFlags & CNT_STICKY) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS);
+ if (ws != wsold) {
+ RECT rc;
+ GetWindowRect(hwndDlg, &rc);
+ if ((ws & WS_CAPTION) != (wsold & WS_CAPTION)) {
+ SetWindowPos(hwndDlg, 0, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOCOPYBITS);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW);
+ if (pContainer->hwndActive != 0) {
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+ DM_ScrollToBottom(dat, 0, 0);
+ }
+ }
+ }
+
+ pContainer->dwFlags = ((pContainer->dwFlagsEx & (TCF_SBARLEFT | TCF_SBARRIGHT)) ?
+ pContainer->dwFlags | CNT_SIDEBAR : pContainer->dwFlags & ~CNT_SIDEBAR);
+
+ pContainer->SideBar->Init();
+
+ ws = wsold = GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MSGTABS), GWL_STYLE);
+ if (pContainer->dwFlags & CNT_TABSBOTTOM)
+ ws |= (TCS_BOTTOM);
+ else
+ ws &= ~(TCS_BOTTOM);
+ if ((ws & (TCS_BOTTOM | TCS_MULTILINE)) != (wsold & (TCS_BOTTOM | TCS_MULTILINE))) {
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MSGTABS), GWL_STYLE, ws);
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_MSGTABS), NULL, NULL, RDW_INVALIDATE);
+ }
+
+ if (pContainer->dwFlags & CNT_NOSTATUSBAR) {
+ if (pContainer->hwndStatus) {
+ //SetWindowLongPtr(pContainer->hwndStatus, GWLP_WNDPROC, (LONG_PTR)OldStatusBarproc);
+ DestroyWindow(pContainer->hwndStatus);
+ pContainer->hwndStatus = 0;
+ pContainer->statusBarHeight = 0;
+ SendMessage(hwndDlg, DM_STATUSBARCHANGED, 0, 0);
+ }
+ }
+ else if (pContainer->hwndStatus == 0) {
+ pContainer->hwndStatus = CreateWindowEx(0, _T("TSStatusBarClass"), NULL, SBT_TOOLTIPS | WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwndDlg, NULL, g_hInst, NULL);
+
+ if (sBarHeight && bSkinned)
+ SendMessage(pContainer->hwndStatus, SB_SETMINHEIGHT, sBarHeight, 0);
+ }
+ if (pContainer->hwndActive != 0) {
+ hContact = 0;
+ SendMessage(pContainer->hwndActive, DM_QUERYHCONTACT, 0, (LPARAM)&hContact);
+ if (hContact)
+ SendMessage(hwndDlg, DM_UPDATETITLE, (WPARAM)hContact, 0);
+ }
+ SendMessage(hwndDlg, WM_SIZE, 0, 1);
+ BroadCastContainer(pContainer, DM_CONFIGURETOOLBAR, 0, 1);
+ return(0);
+ }
+ /*
+ * search the first and most recent unread events in all client tabs...
+ * return all information via a RECENTINFO structure (tab indices,
+ * window handles and timestamps).
+ */
+ case DM_QUERYRECENT: {
+ int i;
+ int iItems = TabCtrl_GetItemCount(hwndTab);
+ RECENTINFO *ri = (RECENTINFO *)lParam;
+ TCITEM item = {0};
+
+ DWORD dwTimestamp, dwMostRecent = 0;
+
+ ri->iFirstIndex = ri->iMostRecent = -1;
+ ri->dwFirst = ri->dwMostRecent = 0;
+ ri->hwndFirst = ri->hwndMostRecent = 0;
+
+ for (i = 0; i < iItems; i++) {
+ item.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, i, &item);
+ SendMessage((HWND) item.lParam, DM_QUERYLASTUNREAD, 0, (LPARAM)&dwTimestamp);
+ if (dwTimestamp > ri->dwMostRecent) {
+ ri->dwMostRecent = dwTimestamp;
+ ri->iMostRecent = i;
+ ri->hwndMostRecent = (HWND) item.lParam;
+ if (ri->iFirstIndex == -1) {
+ ri->iFirstIndex = i;
+ ri->dwFirst = dwTimestamp;
+ ri->hwndFirst = (HWND) item.lParam;
+ }
+ }
+ }
+ return(0);
+ }
+ /*
+ * search tab with either next or most recent unread message and select it
+ */
+ case DM_QUERYPENDING: {
+ NMHDR nmhdr;
+ RECENTINFO ri;
+
+ SendMessage(hwndDlg, DM_QUERYRECENT, 0, (LPARAM)&ri);
+ nmhdr.code = TCN_SELCHANGE;
+
+ if (wParam == DM_QUERY_NEXT && ri.iFirstIndex != -1) {
+ TabCtrl_SetCurSel(hwndTab, ri.iFirstIndex);
+ SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM) &nmhdr);
+ }
+ if (wParam == DM_QUERY_MOSTRECENT && ri.iMostRecent != -1) {
+ TabCtrl_SetCurSel(hwndTab, ri.iMostRecent);
+ SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM) &nmhdr);
+ }
+ return(0);
+ }
+
+ case DM_SETICON: {
+ HICON hIconMsg = PluginConfig.g_IconMsgEvent;
+ TWindowData* dat = (TWindowData *)wParam;
+ HICON hIconBig = (dat && dat->cache) ? LoadSkinnedProtoIconBig(dat->cache->getActiveProto(), dat->cache->getActiveStatus()) : 0;
+
+ if(Win7Taskbar->haveLargeIcons()) {
+
+ if ((HICON)lParam == PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING] || (HICON)lParam == hIconMsg) {
+ Win7Taskbar->setOverlayIcon(hwndDlg, lParam);
+ if(GetForegroundWindow() != hwndDlg)
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, lParam);
+ if((HICON)lParam == hIconMsg)
+ pContainer->hIconTaskbarOverlay = hIconMsg;
+ break;
+ }
+
+ if(dat) {
+ if(dat->hTaskbarIcon == 0)
+ dat->hTaskbarIcon = ((dat->pContainer->dwFlags & CNT_AVATARSONTASKBAR) ? Utils::iconFromAvatar(dat) : 0);
+ else {
+ if(!(dat->pContainer->dwFlags & CNT_AVATARSONTASKBAR)) {
+ DestroyIcon(dat->hTaskbarIcon);
+ dat->hTaskbarIcon = 0;
+ }
+ }
+
+ if(dat->hTaskbarIcon) {
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)dat->hTaskbarIcon);
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, lParam);
+ Win7Taskbar->setOverlayIcon(hwndDlg, (LPARAM)(dat->hTabIcon ? (LPARAM)dat->hTabIcon : lParam));
+ }
+ else {
+ if(0 == hIconBig || (HICON)CALLSERVICE_NOTFOUND == hIconBig)
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)lParam);
+ else
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIconBig);
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, lParam);
+ if(dat->pContainer->hIconTaskbarOverlay)
+ Win7Taskbar->setOverlayIcon(hwndDlg, (LPARAM)dat->pContainer->hIconTaskbarOverlay);
+ else if(Win7Taskbar->haveAlwaysGroupingMode() && fForceOverlayIcons)
+ Win7Taskbar->setOverlayIcon(hwndDlg, lParam);
+ else
+ Win7Taskbar->clearOverlayIcon(hwndDlg);
+ }
+ return(0);
+ }
+ }
+ /*
+ * default handling (no win7 taskbar)
+ */
+ if ((HICON)lParam == PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]) { // always set typing icon, but don't save it...
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, lParam);
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, lParam);
+ break;
+ }
+ if(reinterpret_cast<HICON>(lParam) == hIconMsg)
+ hIconBig = LoadSkinnedIconBig(SKINICON_EVENT_MESSAGE);
+
+ if (pContainer->hIcon == STICK_ICON_MSG && (HICON)lParam != hIconMsg && pContainer->dwFlags & CNT_NEED_UPDATETITLE) {
+ lParam = (LPARAM)hIconMsg;
+ hIconBig = LoadSkinnedIconBig(SKINICON_EVENT_MESSAGE);
+ }
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, lParam);
+ if(0 != hIconBig && reinterpret_cast<HICON>(CALLSERVICE_NOTFOUND) != hIconBig)
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hIconBig));
+ pContainer->hIcon = (lParam == (LPARAM)hIconMsg) ? STICK_ICON_MSG : 0;
+ return(0);
+ }
+ case WM_DRAWITEM: {
+ int cx = PluginConfig.m_smcxicon;
+ int cy = PluginConfig.m_smcyicon;
+ DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
+ int id = LOWORD(dis->itemID);
+
+ if (dis->hwndItem == pContainer->hwndStatus && !(pContainer->dwFlags & CNT_NOSTATUSBAR)) {
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+ if (dat)
+ DrawStatusIcons(dat, dis->hDC, dis->rcItem, 2);
+ return TRUE;
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+ }
+ case WM_MEASUREITEM: {
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+ }
+ case DM_QUERYCLIENTAREA: {
+ RECT *rc = (RECT *)lParam;
+ if(rc) {
+ if (!IsIconic(hwndDlg))
+ GetClientRect(hwndDlg, rc);
+ else
+ CopyRect(rc, &pContainer->rcSaved);
+ AdjustTabClientRect(pContainer, rc);
+ }
+ return(0);
+ }
+ case WM_DESTROY: {
+ int i = 0;
+ TCITEM item;
+ SESSION_INFO *node = m_WndList;
+
+ if (PluginConfig.g_FlashAvatarAvail) { // destroy own flash avatar
+ FLASHAVATAR fa = {0};
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+
+ fa.id = 25367;
+ fa.cProto = dat ? dat->szProto : NULL;
+ CallService(MS_FAVATAR_DESTROY, (WPARAM)&fa, 0);
+ }
+ ZeroMemory((void *)&item, sizeof(item));
+ pContainer->hwnd = 0;
+ pContainer->hwndActive = 0;
+ pContainer->hMenuContext = 0;
+ if (pContainer->hwndStatus)
+ DestroyWindow(pContainer->hwndStatus);
+
+ // free private theme...
+ if(pContainer->theme.isPrivate) {
+ free(pContainer->ltr_templates);
+ free(pContainer->rtl_templates);
+ free(pContainer->theme.logFonts);
+ free(pContainer->theme.fontColors);
+ free(pContainer->theme.rtfFonts);
+ }
+
+ if (pContainer->hwndTip)
+ DestroyWindow(pContainer->hwndTip);
+ RemoveContainerFromList(pContainer);
+ if (PluginConfig.m_MathModAvail)
+ CallService(MTH_HIDE, 0, 0);
+ while (node) {
+ if (node->pContainer == pContainer) {
+ node->pContainer = 0;
+ }
+ node = node->next;
+ }
+ if (pContainer->cachedDC) {
+ SelectObject(pContainer->cachedDC, pContainer->oldHBM);
+ DeleteObject(pContainer->cachedHBM);
+ DeleteDC(pContainer->cachedDC);
+ }
+ if(pContainer->cachedToolbarDC) {
+ SelectObject(pContainer->cachedToolbarDC, pContainer->oldhbmToolbarBG);
+ DeleteObject(pContainer->hbmToolbarBG);
+ DeleteDC(pContainer->cachedToolbarDC);
+ }
+ SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)OldContainerWndProc);
+ return 0;
+ }
+
+ case WM_NCDESTROY:
+ if (pContainer) {
+ delete pContainer->MenuBar;
+ delete pContainer->SideBar;
+ if(pContainer->settings != &PluginConfig.globalContainerSettings)
+ free(pContainer->settings);
+ free(pContainer);
+ }
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+ break;
+ case WM_CLOSE: {
+ //mad
+ if (PluginConfig.m_HideOnClose && !lParam) {
+ ShowWindow(hwndDlg, SW_HIDE);
+ pContainer->fHidden = true;
+ }
+ else {
+ WINDOWPLACEMENT wp;
+ char szCName[40];
+ char *szSetting = "CNTW_";
+
+ if(TabCtrl_GetItemCount(hwndTab) > 1) {
+ LRESULT res = CWarning::show(CWarning::WARN_CLOSEWINDOW, MB_YESNOCANCEL|MB_ICONQUESTION);
+ if(IDNO == res || IDCANCEL == res)
+ break;
+ }
+
+ if (lParam == 0 && TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_MSGTABS)) > 0) { // dont ask if container is empty (no tabs)
+ int clients = TabCtrl_GetItemCount(hwndTab), i;
+ TCITEM item = {0};
+ int iOpenJobs = 0;
+
+ item.mask = TCIF_PARAM;
+ for (i = 0; i < clients; i++) {
+ TabCtrl_GetItem(hwndTab, i, &item);
+ if (item.lParam && IsWindow((HWND)item.lParam)) {
+ SendMessage((HWND)item.lParam, DM_CHECKQUEUEFORCLOSE, 0, (LPARAM)&iOpenJobs);
+ }
+ }
+ if (iOpenJobs && pContainer) {
+ LRESULT result;
+
+ if (pContainer->exFlags & CNT_EX_CLOSEWARN)
+ return TRUE;
+
+ pContainer->exFlags |= CNT_EX_CLOSEWARN;
+ result = SendQueue::WarnPendingJobs(iOpenJobs);
+ pContainer->exFlags &= ~CNT_EX_CLOSEWARN;
+ if (result == IDNO)
+ return TRUE;
+ }
+ }
+
+ ZeroMemory((void *)&wp, sizeof(wp));
+ wp.length = sizeof(wp);
+ /*
+ * save geometry information to the database...
+ */
+ if (!(pContainer->dwFlags & CNT_GLOBALSIZE)) {
+ if (GetWindowPlacement(hwndDlg, &wp) != 0) {
+ if (pContainer->isCloned && pContainer->hContactFrom != 0) {
+ HANDLE hContact;
+ int i;
+ TCITEM item = {0};
+
+ item.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, TabCtrl_GetCurSel(hwndTab), &item);
+ SendMessage((HWND)item.lParam, DM_QUERYHCONTACT, 0, (LPARAM)&hContact);
+ M->WriteByte(hContact, SRMSGMOD_T, "splitmax", (BYTE)((wp.showCmd==SW_SHOWMAXIMIZED)?1:0));
+
+ for (i = 0; i < TabCtrl_GetItemCount(hwndTab); i++) {
+ if (TabCtrl_GetItem(hwndTab, i, &item)) {
+ SendMessage((HWND)item.lParam, DM_QUERYHCONTACT, 0, (LPARAM)&hContact);
+ M->WriteDword(hContact, SRMSGMOD_T, "splitx", wp.rcNormalPosition.left);
+ M->WriteDword(hContact, SRMSGMOD_T, "splity", wp.rcNormalPosition.top);
+ M->WriteDword(hContact, SRMSGMOD_T, "splitwidth", wp.rcNormalPosition.right - wp.rcNormalPosition.left);
+ M->WriteDword(hContact, SRMSGMOD_T, "splitheight", wp.rcNormalPosition.bottom - wp.rcNormalPosition.top);
+ }
+ }
+ }
+ else {
+ _snprintf(szCName, 40, "%s%dx", szSetting, pContainer->iContainerIndex);
+ M->WriteDword(SRMSGMOD_T, szCName, wp.rcNormalPosition.left);
+ _snprintf(szCName, 40, "%s%dy", szSetting, pContainer->iContainerIndex);
+ M->WriteDword(SRMSGMOD_T, szCName, wp.rcNormalPosition.top);
+ _snprintf(szCName, 40, "%s%dwidth", szSetting, pContainer->iContainerIndex);
+ M->WriteDword(SRMSGMOD_T, szCName, wp.rcNormalPosition.right - wp.rcNormalPosition.left);
+ _snprintf(szCName, 40, "%s%dheight", szSetting, pContainer->iContainerIndex);
+ M->WriteDword(SRMSGMOD_T, szCName, wp.rcNormalPosition.bottom - wp.rcNormalPosition.top);
+
+ M->WriteByte(SRMSGMOD_T, "splitmax", (BYTE)((wp.showCmd==SW_SHOWMAXIMIZED)?1:0));
+ }
+ }
+ }
+ // clear temp flags which should NEVER be saved...
+
+ if (pContainer->isCloned && pContainer->hContactFrom != 0) {
+ HANDLE hContact;
+ int i;
+ TCITEM item = {0};
+
+ item.mask = TCIF_PARAM;
+ pContainer->dwFlags &= ~(CNT_DEFERREDCONFIGURE | CNT_CREATE_MINIMIZED | CNT_DEFERREDSIZEREQUEST | CNT_CREATE_CLONED);
+ for (i = 0; i < TabCtrl_GetItemCount(hwndTab); i++) {
+ if (TabCtrl_GetItem(hwndTab, i, &item)) {
+ SendMessage((HWND)item.lParam, DM_QUERYHCONTACT, 0, (LPARAM)&hContact);
+ //Utils::WriteContainerSettingsToDB(hContact, pContainer->settings);
+
+ mir_snprintf(szCName, 40, "%s_theme", szSetting);
+ if (lstrlen(pContainer->szRelThemeFile) > 1) {
+ if(pContainer->fPrivateThemeChanged == TRUE) {
+ M->pathToRelative(pContainer->szRelThemeFile, pContainer->szAbsThemeFile);
+ M->WriteTString(hContact, SRMSGMOD_T, szCName, pContainer->szRelThemeFile);
+ pContainer->fPrivateThemeChanged = FALSE;
+ }
+ }
+ else {
+ DBDeleteContactSetting(hContact, SRMSGMOD_T, szCName);
+ pContainer->fPrivateThemeChanged = FALSE;
+ }
+
+ }
+ }
+ }
+ else
+ Utils::SaveContainerSettings(pContainer, szSetting);
+ DestroyWindow(hwndDlg);
+ }
+ break;
+ }
+ default:
+ return FALSE;
+ }
+ return FALSE;
+}
+
+/*
+ * search the list of tabs and return the tab (by index) which "belongs" to the given
+ * hwnd. The hwnd is the handle of a message dialog childwindow. At creation,
+ * the dialog handle is stored in the TCITEM.lParam field, because we need
+ * to know the owner of the tab.
+ *
+ * hwndTab: handle of the tab control itself.
+ * hwnd: handle of a message dialog.
+ *
+ * returns the tab index (zero based), -1 if no tab is found (which SHOULD not
+ * really happen, but who knows... ;) )
+ */
+
+int TSAPI GetTabIndexFromHWND(HWND hwndTab, HWND hwnd)
+{
+ TCITEM item;
+ int i = 0;
+ int iItems;
+
+ iItems = TabCtrl_GetItemCount(hwndTab);
+
+ ZeroMemory((void *)&item, sizeof(item));
+ item.mask = TCIF_PARAM;
+
+ for (i = 0; i < iItems; i++) {
+ TabCtrl_GetItem(hwndTab, i, &item);
+ if ((HWND)item.lParam == hwnd) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/*
+ * activates the tab belonging to the given client HWND (handle of the actual
+ * message window.
+ */
+
+int TSAPI ActivateTabFromHWND(HWND hwndTab, HWND hwnd)
+{
+ NMHDR nmhdr;
+
+ int iItem = GetTabIndexFromHWND(hwndTab, hwnd);
+ if (iItem >= 0) {
+ TabCtrl_SetCurSel(hwndTab, iItem);
+ ZeroMemory((void *)&nmhdr, sizeof(nmhdr));
+ nmhdr.code = TCN_SELCHANGE;
+ SendMessage(GetParent(hwndTab), WM_NOTIFY, 0, (LPARAM) &nmhdr); // do it via a WM_NOTIFY / TCN_SELCHANGE to simulate user-activation
+ return iItem;
+ }
+ return -1;
+}
+
+/*
+ * returns the index of the tab under the mouse pointer. Used for
+ * context menu popup and tooltips
+ * pt: mouse coordinates, obtained from GetCursorPos()
+ */
+
+int TSAPI GetTabItemFromMouse(HWND hwndTab, POINT *pt)
+{
+ TCHITTESTINFO tch;
+
+ ScreenToClient(hwndTab, pt);
+ tch.pt = *pt;
+ tch.flags = 0;
+ return TabCtrl_HitTest(hwndTab, &tch);
+}
+
+/*
+ * cut off contact name to the option value set via Options->Tabbed messaging
+ * some people were requesting this, because really long contact list names
+ * are causing extraordinary wide tabs and these are looking ugly and wasting
+ * screen space.
+ *
+ * size = max length of target string
+ */
+
+int TSAPI CutContactName(const TCHAR *oldname, TCHAR *newname, unsigned int size)
+{
+ int cutMax = PluginConfig.m_CutContactNameTo;
+
+ if ((int)lstrlen(oldname) <= cutMax) {
+ lstrcpyn(newname, oldname, size);
+ newname[size - 1] = 0;
+ }
+ else {
+ TCHAR fmt[20];
+ _sntprintf(fmt, 18, _T("%%%d.%ds..."), cutMax, cutMax);
+ _sntprintf(newname, size, fmt, oldname);
+ newname[size - 1] = 0;
+ }
+ return 0;
+}
+
+/*
+ * functions for handling the linked list of struct ContainerWindowData *foo
+ */
+
+static struct TContainerData* TSAPI AppendToContainerList(struct TContainerData *pContainer) {
+ struct TContainerData *pCurrent = 0;
+
+ if (!pFirstContainer) {
+ pFirstContainer = pContainer;
+ pFirstContainer->pNextContainer = NULL;
+ return pFirstContainer;
+ } else {
+ pCurrent = pFirstContainer;
+ while (pCurrent->pNextContainer != 0)
+ pCurrent = pCurrent->pNextContainer;
+ pCurrent->pNextContainer = pContainer;
+ pContainer->pNextContainer = NULL;
+ return pCurrent;
+ }
+}
+
+struct TContainerData* TSAPI FindContainerByName(const TCHAR *name) {
+ struct TContainerData *pCurrent = pFirstContainer;
+
+ if (name == NULL || lstrlen(name) == 0)
+ return 0;
+
+ if (M->GetByte("singlewinmode", 0)) { // single window mode - always return 0 and force a new container
+ return NULL;
+ }
+
+ while (pCurrent) {
+ if (!_tcsncmp(pCurrent->szName, name, CONTAINER_NAMELEN))
+ return pCurrent;
+ pCurrent = pCurrent->pNextContainer;
+ }
+ // error, didn't find it.
+ return NULL;
+}
+
+static struct TContainerData* TSAPI RemoveContainerFromList(struct TContainerData *pContainer) {
+ struct TContainerData *pCurrent = pFirstContainer;
+
+ if (pContainer == pFirstContainer) {
+ if (pContainer->pNextContainer != NULL)
+ pFirstContainer = pContainer->pNextContainer;
+ else
+ pFirstContainer = NULL;
+
+ if (pLastActiveContainer == pContainer) // make sure, we don't reference this container anymore
+ pLastActiveContainer = pFirstContainer;
+
+ return pFirstContainer;
+ }
+
+ do {
+ if (pCurrent->pNextContainer == pContainer) {
+ pCurrent->pNextContainer = pCurrent->pNextContainer->pNextContainer;
+
+ if (pLastActiveContainer == pContainer) // make sure, we don't reference this container anymore
+ pLastActiveContainer = pFirstContainer;
+
+ return 0;
+ }
+ } while (pCurrent = pCurrent->pNextContainer);
+ return NULL;
+}
+
+/*
+ * calls the TabCtrl_AdjustRect to calculate the "real" client area of the tab.
+ * also checks for the option "hide tabs when only one tab open" and adjusts
+ * geometry if necessary
+ * rc is the RECT obtained by GetClientRect(hwndTab)
+ */
+
+void TSAPI AdjustTabClientRect(struct TContainerData *pContainer, RECT *rc)
+{
+ HWND hwndTab = GetDlgItem(pContainer->hwnd, IDC_MSGTABS);
+ RECT rcTab, rcTabOrig;
+ DWORD dwBottom, dwTop;
+ DWORD tBorder = pContainer->tBorder;
+ DWORD dwStyle = GetWindowLongPtr(hwndTab, GWL_STYLE);
+
+ GetClientRect(hwndTab, &rcTab);
+ dwBottom = rcTab.bottom;
+ dwTop = rcTab.top;
+ if (!(pContainer->dwFlags & CNT_SIDEBAR) && (pContainer->iChilds > 1 || !(pContainer->dwFlags & CNT_HIDETABS))) {
+ DWORD dwTopPad;
+ rcTabOrig = rcTab;
+ TabCtrl_AdjustRect(hwndTab, FALSE, &rcTab);
+ dwTopPad = rcTab.top - rcTabOrig.top;
+
+ rc->left += tBorder;
+ rc->right -= tBorder;
+
+ if (dwStyle & TCS_BUTTONS) {
+ if (pContainer->dwFlags & CNT_TABSBOTTOM) {
+ int nCount = TabCtrl_GetItemCount(hwndTab);
+ RECT rcItem;
+
+ if (nCount > 0) {
+ TabCtrl_GetItemRect(hwndTab, nCount - 1, &rcItem);
+ //rc->top = pContainer->tBorder_outer_top;
+ rc->bottom = rcItem.top;
+ }
+ }
+ else {
+ rc->top += (dwTopPad - 2);;
+ rc->bottom = rcTabOrig.bottom;
+ }
+ }
+ else {
+ if (pContainer->dwFlags & CNT_TABSBOTTOM)
+ rc->bottom = rcTab.bottom + 2;
+ else {
+ rc->top += (dwTopPad - 2);;
+ rc->bottom = rcTabOrig.bottom;
+ }
+ }
+
+ rc->top += tBorder;
+ rc->bottom -= tBorder;
+ }
+ else {
+ rc->bottom = rcTab.bottom;
+ rc->top = rcTab.top;
+ }
+ rc->right -= (pContainer->tBorder_outer_left + pContainer->tBorder_outer_right);
+ if (pContainer->SideBar->isVisible())
+ rc->right -= pContainer->SideBar->getWidth();
+}
+
+/*
+ * retrieve the container name for the given contact handle.
+ * if none is assigned, return the name of the default container
+ */
+
+int TSAPI GetContainerNameForContact(HANDLE hContact, TCHAR *szName, int iNameLen)
+{
+ DBVARIANT dbv;
+
+ if (M->GetByte("singlewinmode", 0)) { // single window mode using cloned (temporary) containers
+ _tcsncpy(szName, _T("Message Session"), iNameLen);
+ return 0;
+ }
+
+ if (M->GetByte("useclistgroups", 0)) { // use clist group names for containers...
+ if (M->GetTString(hContact, "CList", "Group", &dbv)) {
+ _tcsncpy(szName, _T("default"), iNameLen);
+ return 0;
+ }
+ else {
+ if (lstrlen(dbv.ptszVal) > CONTAINER_NAMELEN)
+ dbv.ptszVal[CONTAINER_NAMELEN] = '\0';
+ _tcsncpy(szName, dbv.ptszVal, iNameLen);
+ szName[iNameLen] = '\0';
+ DBFreeVariant(&dbv);
+ return dbv.cchVal;
+ }
+ }
+ if (M->GetTString(hContact, SRMSGMOD_T, "containerW", &dbv)) {
+ _tcsncpy(szName, _T("default"), iNameLen);
+ return 0;
+ }
+ if (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR) {
+ _tcsncpy(szName, dbv.ptszVal, iNameLen);
+ szName[iNameLen] = 0;
+ DBFreeVariant(&dbv);
+ return dbv.cpbVal;
+ }
+ DBFreeVariant(&dbv);
+ return 0;
+}
+
+void TSAPI DeleteContainer(int iIndex) {
+ DBVARIANT dbv;
+ char szIndex[10], szSetting[CONTAINER_NAMELEN + 30];
+ char *szKey = "TAB_ContainersW";
+ char *szSettingP = "CNTW_";
+ char *szSubKey = "containerW";
+ HANDLE hhContact;
+ _snprintf(szIndex, 8, "%d", iIndex);
+
+
+ if (!M->GetTString(NULL, szKey, szIndex, &dbv)) {
+ if (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR) {
+ TCHAR *wszContainerName = dbv.ptszVal;
+ M->WriteTString(NULL, szKey, szIndex, _T("**free**"));
+
+ hhContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hhContact) {
+ DBVARIANT dbv_c;
+ if (!M->GetTString(hhContact, SRMSGMOD_T, szSubKey, &dbv_c)) {
+ TCHAR *wszString = dbv_c.ptszVal;
+ if (_tcscmp(wszString, wszContainerName) && lstrlen(wszString) == lstrlen(wszContainerName))
+ DBDeleteContactSetting(hhContact, SRMSGMOD_T, "containerW");
+ DBFreeVariant(&dbv_c);
+ }
+ hhContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hhContact, 0);
+ }
+ _snprintf(szSetting, CONTAINER_NAMELEN + 15, "%s%d_Flags", szSettingP, iIndex);
+ DBDeleteContactSetting(NULL, SRMSGMOD_T, szSetting);
+ _snprintf(szSetting, CONTAINER_NAMELEN + 15, "%s%d_Trans", szSettingP, iIndex);
+ DBDeleteContactSetting(NULL, SRMSGMOD_T, szSetting);
+ _snprintf(szSetting, CONTAINER_NAMELEN + 15, "%s%dwidth", szSettingP, iIndex);
+ DBDeleteContactSetting(NULL, SRMSGMOD_T, szSetting);
+ _snprintf(szSetting, CONTAINER_NAMELEN + 15, "%s%dheight", szSettingP, iIndex);
+ DBDeleteContactSetting(NULL, SRMSGMOD_T, szSetting);
+ _snprintf(szSetting, CONTAINER_NAMELEN + 15, "%s%dx", szSettingP, iIndex);
+ DBDeleteContactSetting(NULL, SRMSGMOD_T, szSetting);
+ _snprintf(szSetting, CONTAINER_NAMELEN + 15, "%s%dy", szSettingP, iIndex);
+ DBDeleteContactSetting(NULL, SRMSGMOD_T, szSetting);
+ }
+ DBFreeVariant(&dbv);
+ }
+}
+
+void TSAPI RenameContainer(int iIndex, const TCHAR *szNew) {
+ DBVARIANT dbv;
+ char *szKey = "TAB_ContainersW";
+ char *szSettingP = "CNTW_";
+ char *szSubKey = "containerW";
+ char szIndex[10];
+ HANDLE hhContact;
+
+ _snprintf(szIndex, 8, "%d", iIndex);
+ if (!M->GetTString(NULL, szKey, szIndex, &dbv)) {
+ if (szNew != NULL) {
+ if (lstrlen(szNew) != 0)
+ M->WriteTString(NULL, szKey, szIndex, szNew);
+ }
+ hhContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hhContact) {
+ DBVARIANT dbv_c;
+ if (!M->GetTString(hhContact, SRMSGMOD_T, szSubKey, &dbv_c)) {
+ if (!_tcscmp(dbv.ptszVal, dbv_c.ptszVal) && lstrlen(dbv_c.ptszVal) == lstrlen(dbv.ptszVal)) {
+ if (szNew != NULL) {
+ if (lstrlen(szNew) != 0)
+ M->WriteTString(hhContact, SRMSGMOD_T, szSubKey, szNew);
+ }
+ }
+ DBFreeVariant(&dbv_c);
+ }
+ hhContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hhContact, 0);
+ }
+ DBFreeVariant(&dbv);
+ }
+}
+
+HMENU TSAPI BuildContainerMenu()
+{
+ char *szKey = "TAB_ContainersW";
+ char szCounter[10];
+ int i = 0;
+ DBVARIANT dbv = { 0 };
+ HMENU hMenu;
+ MENUITEMINFO mii = {0};
+
+ if (PluginConfig.g_hMenuContainer != 0) {
+ HMENU submenu = GetSubMenu(PluginConfig.g_hMenuContext, 0);
+ RemoveMenu(submenu, 6, MF_BYPOSITION);
+ DestroyMenu(PluginConfig.g_hMenuContainer);
+ PluginConfig.g_hMenuContainer = 0;
+ }
+
+ // no container attach menu, if we are using the "clist group mode"
+ if (M->GetByte("useclistgroups", 0) || M->GetByte("singlewinmode", 0))
+ return NULL;
+
+ hMenu = CreateMenu();
+ do {
+ _snprintf(szCounter, 8, "%d", i);
+ if (M->GetTString(NULL, szKey, szCounter, &dbv))
+ break;
+
+ if (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR) {
+ if (_tcsncmp(dbv.ptszVal, _T("**free**"), CONTAINER_NAMELEN))
+ AppendMenu(hMenu, MF_STRING, IDM_CONTAINERMENU + i, !_tcscmp(dbv.ptszVal, _T("default")) ?
+ CTranslator::get(CTranslator::GEN_DEFAULT_CONTAINER_NAME) : dbv.ptszVal);
+ }
+ DBFreeVariant(&dbv);
+ i++;
+ }
+ while (TRUE);
+
+ InsertMenu(PluginConfig.g_hMenuContext, ID_TABMENU_ATTACHTOCONTAINER, MF_BYCOMMAND | MF_POPUP, (UINT_PTR) hMenu, CTranslator::get(CTranslator::CNT_ATTACH_TO));
+ PluginConfig.g_hMenuContainer = hMenu;
+ return hMenu;
+}
+
+HMENU TSAPI BuildMCProtocolMenu(HWND hwndDlg) {
+ HMENU hMCContextMenu = 0, hMCSubForce = 0, hMCSubDefault = 0, hMenu = 0;
+ DBVARIANT dbv;
+ int iNumProtos = 0, i = 0, iDefaultProtoByNum = 0;
+ char szTemp[50], *szProtoMostOnline = NULL;
+ TCHAR szMenuLine[128], *nick = NULL, *szStatusText = NULL;
+ char *tzProtoName = NULL;
+ HANDLE hContactMostOnline, handle;
+ int iChecked, isForced;
+ WORD wStatus;
+
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ if (dat == NULL)
+ return (HMENU) 0;
+
+ if (!dat->cache->isMeta())
+ return (HMENU) 0;
+
+ hMenu = CreatePopupMenu();
+ hMCContextMenu = GetSubMenu(hMenu, 0);
+ hMCSubForce = CreatePopupMenu();
+ hMCSubDefault = CreatePopupMenu();
+
+ AppendMenu(hMenu, MF_STRING | MF_DISABLED | MF_GRAYED | MF_CHECKED, 1, CTranslator::get(CTranslator::GEN_META_CONTACT));
+ AppendMenu(hMenu, MF_SEPARATOR, 1, _T(""));
+
+ iNumProtos = (int)CallService(MS_MC_GETNUMCONTACTS, (WPARAM)dat->hContact, 0);
+ iDefaultProtoByNum = (int)CallService(MS_MC_GETDEFAULTCONTACTNUM, (WPARAM)dat->hContact, 0);
+ hContactMostOnline = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)dat->hContact, 0);
+ szProtoMostOnline = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContactMostOnline, 0);
+ isForced = M->GetDword(dat->hContact, "tabSRMM_forced", -1);
+
+ for (i = 0; i < iNumProtos; i++) {
+ mir_snprintf(szTemp, sizeof(szTemp), "Protocol%d", i);
+ if (DBGetContactSettingString(dat->hContact, PluginConfig.szMetaName, szTemp, &dbv))
+ continue;
+
+ tzProtoName = dbv.pszVal;
+ PROTOACCOUNT *acc = (PROTOACCOUNT *)CallService(MS_PROTO_GETACCOUNT, (WPARAM)0, (LPARAM)tzProtoName);
+
+ if(acc && acc->tszAccountName) {
+ mir_snprintf(szTemp, sizeof(szTemp), "Handle%d", i);
+ if ((handle = (HANDLE)M->GetDword(dat->hContact, PluginConfig.szMetaName, szTemp, 0)) != 0) {
+ nick = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)handle, GCDNF_TCHAR);
+ mir_snprintf(szTemp, sizeof(szTemp), "Status%d", i);
+ wStatus = (WORD)DBGetContactSettingWord(dat->hContact, PluginConfig.szMetaName, szTemp, 0);
+ szStatusText = (TCHAR *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, wStatus, GSMDF_TCHAR);
+ }
+ mir_sntprintf(szMenuLine, safe_sizeof(szMenuLine), _T("%s: %s [%s] %s"), acc->tszAccountName, nick, szStatusText,
+ i == isForced ? CTranslator::get(CTranslator::GEN_META_FORCED) : _T(""));
+ iChecked = MF_UNCHECKED;
+ if (hContactMostOnline != 0 && hContactMostOnline == handle)
+ iChecked = MF_CHECKED;
+ AppendMenu(hMCSubForce, MF_STRING | iChecked, 100 + i, szMenuLine);
+ AppendMenu(hMCSubDefault, MF_STRING | (i == iDefaultProtoByNum ? MF_CHECKED : MF_UNCHECKED), 1000 + i, szMenuLine);
+ }
+ DBFreeVariant(&dbv);
+ }
+ AppendMenu(hMCSubForce, MF_SEPARATOR, 900, _T(""));
+ AppendMenu(hMCSubForce, MF_STRING | ((isForced == -1) ? MF_CHECKED : MF_UNCHECKED), 999, CTranslator::get(CTranslator::GEN_META_AUTOSELECT));
+ InsertMenu(hMenu, 2, MF_BYPOSITION | MF_POPUP, (UINT_PTR) hMCSubForce, CTranslator::get(CTranslator::GEN_META_USEPROTO));
+ InsertMenu(hMenu, 2, MF_BYPOSITION | MF_POPUP, (UINT_PTR) hMCSubDefault, CTranslator::get(CTranslator::GEN_META_SETDEFAULT));
+
+ return hMenu;
+}
+
+/*
+ * flashes the container
+ * iMode != 0: turn on flashing
+ * iMode == 0: turn off flashing
+ */
+
+void TSAPI FlashContainer(struct TContainerData *pContainer, int iMode, int iCount) {
+ FLASHWINFO fwi;
+
+ if (CMimAPI::m_MyFlashWindowEx == NULL)
+ return;
+
+ if (pContainer->dwFlags & CNT_NOFLASH) // container should never flash
+ return;
+
+ fwi.cbSize = sizeof(fwi);
+ fwi.uCount = 0;
+
+ if (iMode) {
+ fwi.dwFlags = FLASHW_ALL;
+ if (pContainer->dwFlags & CNT_FLASHALWAYS)
+ fwi.dwFlags |= FLASHW_TIMER;
+ else
+ fwi.uCount = (iCount == 0) ? M->GetByte("nrflash", 4) : iCount;
+ fwi.dwTimeout = M->GetDword("flashinterval", 1000);
+
+ }
+ else
+ fwi.dwFlags = FLASHW_STOP;
+
+ fwi.hwnd = pContainer->hwnd;
+ pContainer->dwFlashingStarted = GetTickCount();
+ CMimAPI::m_MyFlashWindowEx(&fwi);
+}
+
+void TSAPI ReflashContainer(struct TContainerData *pContainer) {
+ DWORD dwStartTime = pContainer->dwFlashingStarted;
+
+ if (GetForegroundWindow() == pContainer->hwnd || GetActiveWindow() == pContainer->hwnd) // dont care about active windows
+ return;
+
+ if (pContainer->dwFlags & CNT_NOFLASH || pContainer->dwFlashingStarted == 0)
+ return; // dont care about containers which should never flash
+
+ if (pContainer->dwFlags & CNT_FLASHALWAYS)
+ FlashContainer(pContainer, 1, 0);
+ else {
+ // recalc the remaining flashes
+ DWORD dwInterval = M->GetDword("flashinterval", 1000);
+ int iFlashesElapsed = (GetTickCount() - dwStartTime) / dwInterval;
+ DWORD dwFlashesDesired = M->GetByte("nrflash", 4);
+ if (iFlashesElapsed < (int)dwFlashesDesired)
+ FlashContainer(pContainer, 1, dwFlashesDesired - iFlashesElapsed);
+ else {
+ BOOL isFlashed = FlashWindow(pContainer->hwnd, TRUE);
+ if (!isFlashed)
+ FlashWindow(pContainer->hwnd, TRUE);
+ }
+ }
+ pContainer->dwFlashingStarted = dwStartTime;
+}
+
+/*
+ * broadcasts a message to all child windows (tabs/sessions)
+ */
+
+void TSAPI BroadCastContainer(const TContainerData *pContainer, UINT message, WPARAM wParam, LPARAM lParam, BYTE bType) {
+ int i;
+ TCITEM item;
+
+ HWND hwndTab = GetDlgItem(pContainer->hwnd, IDC_MSGTABS);
+ ZeroMemory((void *)&item, sizeof(item));
+
+ item.mask = TCIF_PARAM;
+
+ int nCount = TabCtrl_GetItemCount(hwndTab);
+ for (i = 0; i < nCount; i++) {
+ TabCtrl_GetItem(hwndTab, i, &item);
+ if (IsWindow((HWND)item.lParam)) {
+ if(bType == SESSIONTYPE_ANY)
+ SendMessage((HWND)item.lParam, message, wParam, lParam);
+ else {
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr((HWND)item.lParam, GWLP_USERDATA);
+ if(dat && dat->bType == bType)
+ SendMessage((HWND)item.lParam, message, wParam, lParam);
+ }
+ }
+ }
+}
diff --git a/plugins/TabSRMM/src/containeroptions.cpp b/plugins/TabSRMM/src/containeroptions.cpp
new file mode 100644
index 0000000000..dd87ef56d2
--- /dev/null
+++ b/plugins/TabSRMM/src/containeroptions.cpp
@@ -0,0 +1,586 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: containeroptions.cpp 13631 2011-04-24 08:44:57Z silvercircle $
+ *
+ * The dialog to customize per container options
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+static void MY_CheckDlgButton(HWND hWnd, UINT id, int iCheck)
+{
+ CheckDlgButton(hWnd, id, iCheck ? BST_CHECKED : BST_UNCHECKED);
+}
+
+static void ReloadGlobalContainerSettings(bool fForceReconfig)
+{
+ struct TContainerData *pC = pFirstContainer;
+
+ while (pC) {
+ if (!pC->settings->fPrivate) {
+ Utils::SettingsToContainer(pC);
+ if(fForceReconfig)
+ SendMessage(pC->hwnd, DM_CONFIGURECONTAINER, 0, 0);
+ else
+ SendMessage(pC->hwnd, WM_SIZE, 0, 1);
+ BroadCastContainer(pC, DM_SETINFOPANEL, 0, 0);
+ }
+ pC = pC->pNextContainer;
+ }
+}
+
+/**
+ * Apply a container setting
+ *
+ * @param pContainer ContainerWindowData *: the container
+ * @param flags DWORD: the flag values to set or clear
+ * @param mode int: bit #0 set/clear, any bit from 16-31 indicates that dwFlagsEx should be affected
+ * @param fForceResize
+ */
+void TSAPI ApplyContainerSetting(TContainerData *pContainer, DWORD flags, UINT mode, bool fForceResize)
+{
+ DWORD dwOld = pContainer->dwFlags;
+ bool isEx = (mode & 0xffff0000) ? true : false;
+ bool set = (mode & 0x01) ? true : false;
+
+ if (!pContainer->settings->fPrivate) {
+ if(!isEx)
+ pContainer->dwFlags = (set ? pContainer->dwFlags | flags : pContainer->dwFlags & ~flags);
+ else
+ pContainer->dwFlagsEx = (set ? pContainer->dwFlagsEx | flags : pContainer->dwFlagsEx & ~flags);
+
+ Utils::ContainerToSettings(pContainer);
+ if (flags & CNT_INFOPANEL)
+ BroadCastContainer(pContainer, DM_SETINFOPANEL, 0, 0);
+ if (flags & CNT_SIDEBAR) {
+ struct TContainerData *pC = pFirstContainer;
+ while (pC) {
+ if (!pC->settings->fPrivate) {
+ SendMessage(pC->hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0);
+ }
+ pC = pC->pNextContainer;
+ }
+ }
+ else
+ ReloadGlobalContainerSettings(fForceResize);
+ }
+ else {
+ if(!isEx)
+ pContainer->dwFlags = (set ? pContainer->dwFlags | flags : pContainer->dwFlags & ~flags);
+ else
+ pContainer->dwFlagsEx = (set ? pContainer->dwFlagsEx | flags : pContainer->dwFlagsEx & ~flags);
+ Utils::ContainerToSettings(pContainer);
+ if (flags & CNT_SIDEBAR)
+ SendMessage(pContainer->hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0);
+ else
+ SendMessage(pContainer->hwnd, DM_CONFIGURECONTAINER, 0, 0);
+ if (flags & CNT_INFOPANEL)
+ BroadCastContainer(pContainer, DM_SETINFOPANEL, 0, 0);
+ }
+
+ if(fForceResize)
+ SendMessage(pContainer->hwnd, WM_SIZE, 0, 1);
+
+ BroadCastContainer(pContainer, DM_BBNEEDUPDATE, 0, 0);
+}
+
+#define NR_O_PAGES 10
+#define NR_O_OPTIONSPERPAGE 10
+
+static struct _tagPages {
+ UINT idTitle;
+ UINT idDesc;
+ UINT uIds[10];
+} o_pages[] = {
+ { CTranslator::CNT_OPT_TITLE_GEN, CTranslator::STR_LAST, IDC_O_NOTABS, IDC_O_STICKY, IDC_VERTICALMAX, IDC_AUTOSPLITTER, IDC_O_AUTOHIDE, IDC_AUTOCLOSETABTIME, IDC_AUTOCLOSETABSPIN, IDC_O_AUTOHIDESECONDS, 0, 0},
+ { CTranslator::CNT_OPT_TITLE_LAYOUT, CTranslator::STR_LAST, IDC_CNTNOSTATUSBAR, IDC_HIDEMENUBAR, IDC_UIDSTATUSBAR, IDC_HIDETOOLBAR, IDC_INFOPANEL, IDC_BOTTOMTOOLBAR, 0, 0, 0, 0},
+ { CTranslator::CNT_OPT_TITLE_TABS, CTranslator::CNT_OPT_DESC_TABS, IDC_TABMODE, IDC_O_TABMODE, IDC_O_SBARLAYOUT, IDC_SBARLAYOUT, IDC_FLASHICON, IDC_FLASHLABEL, IDC_SINGLEROWTAB, IDC_BUTTONTABS, IDC_CLOSEBUTTONONTABS, 0},
+ { CTranslator::CNT_OPT_TITLE_NOTIFY, CTranslator::CNT_OPT_DESC_NOTIFY, IDC_O_DONTREPORT, IDC_DONTREPORTUNFOCUSED2, IDC_DONTREPORTFOCUSED2, IDC_ALWAYSPOPUPSINACTIVE, IDC_O_EXPLAINGLOBALNOTIFY, 0, 0, 0, 0, 0},
+ { CTranslator::CNT_OPT_TITLE_FLASHING, CTranslator::STR_LAST, IDC_O_FLASHDEFAULT, IDC_O_FLASHALWAYS, IDC_O_FLASHNEVER, 0, 0, 0, 0, 0, 0, 0},
+ { CTranslator::CNT_OPT_TITLE_TITLEBAR, CTranslator::STR_LAST, IDC_O_HIDETITLE, IDC_TITLEFORMAT, IDC_O_TITLEBARFORMAT, IDC_O_HELP_TITLEFORMAT, 0, 0, 0, 0, 0, 0},
+ { CTranslator::CNT_OPT_TITLE_THEME, CTranslator::CNT_OPT_DESC_THEME, IDC_THEME, IDC_SELECTTHEME, IDC_USEGLOBALSIZE, IDC_SAVESIZEASGLOBAL, IDC_LABEL_PRIVATETHEME, IDC_TSLABEL_EXPLAINTHEME, 0, 0, 0, 0},
+ { CTranslator::CNT_OPT_TITLE_TRANS, CTranslator::CNT_OPT_DESC_TRANS, IDC_TRANSPARENCY, IDC_TRANSPARENCY_ACTIVE, IDC_TRANSPARENCY_INACTIVE, IDC_TSLABEL_ACTIVE, IDC_TSLABEL_INACTIVE, 0, 0,0, 0, 0},
+ { CTranslator::CNT_OPT_TITLE_AVATARS, CTranslator::STR_LAST, IDC_O_STATIC_AVATAR, IDC_O_STATIC_OWNAVATAR, IDC_AVATARMODE, IDC_OWNAVATARMODE, IDC_AVATARSONTASKBAR, 0, 0, 0, 0, 0},
+ { CTranslator::CNT_OPT_TITLE_SOUNDS, CTranslator::STR_LAST, IDC_O_ENABLESOUNDS, IDC_O_SOUNDSMINIMIZED, IDC_O_SOUNDSUNFOCUSED, IDC_O_SOUNDSINACTIVE, IDC_O_SOUNDSFOCUSED, 0, 0, 0, 0, 0},
+};
+
+static void ShowPage(HWND hwndDlg, int iPage, BOOL fShow)
+{
+ if (iPage >= 0 && iPage < NR_O_PAGES) {
+ for (int i = 0; i < NR_O_OPTIONSPERPAGE && o_pages[iPage].uIds[i] != 0; i++)
+ Utils::showDlgControl(hwndDlg, o_pages[iPage].uIds[i], fShow ? SW_SHOW : SW_HIDE);
+ }
+ if (fShow) {
+ SetDlgItemText(hwndDlg, IDC_TITLEBOX, CTranslator::get(o_pages[iPage].idTitle));
+ if (o_pages[iPage].idDesc != CTranslator::STR_LAST)
+ SetDlgItemText(hwndDlg, IDC_DESC, CTranslator::get(o_pages[iPage].idDesc));
+ else
+ SetDlgItemText(hwndDlg, IDC_DESC, _T(""));
+ }
+ Utils::showDlgControl(hwndDlg, IDC_O_EXPLAINGLOBALNOTIFY, (iPage == 3 && nen_options.bWindowCheck) ? SW_SHOW : SW_HIDE);
+
+#if !defined(__FEAT_EXP_AUTOSPLITTER)
+ if(iPage == 0)
+ Utils::showDlgControl(hwndDlg, IDC_AUTOSPLITTER, SW_HIDE);
+#endif
+ if(iPage == 8 && !IsWinVer7Plus())
+ Utils::showDlgControl(hwndDlg, IDC_AVATARSONTASKBAR, SW_HIDE);
+}
+
+INT_PTR CALLBACK DlgProcContainerOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct TContainerData *pContainer = 0;
+ HWND hwndTree = GetDlgItem(hwndDlg, IDC_SECTIONTREE);
+ pContainer = (struct TContainerData *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg) {
+ case WM_INITDIALOG: {
+ wchar_t szNewTitle[128];
+ TContainerData *pContainer = 0;
+ int i, j;
+ TVINSERTSTRUCT tvis = {0};
+ HTREEITEM hItem;
+ int nr_layouts = 0;
+ const TSideBarLayout* sblayouts = CSideBar::getLayouts(nr_layouts);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) lParam);
+ pContainer = (TContainerData *) lParam;
+ pContainer->hWndOptions = hwndDlg;
+ TranslateDialogDefault(hwndDlg);
+ SetWindowText(hwndDlg, CTranslator::get(CTranslator::CNT_OPT_TITLE));
+ mir_sntprintf(szNewTitle, SIZEOF(szNewTitle), CTranslator::get(CTranslator::CNT_OPT_HEADERBAR), !_tcscmp(pContainer->szName, _T("default")) ?
+ CTranslator::get(CTranslator::GEN_DEFAULT_CONTAINER_NAME) : pContainer->szName);
+ SetDlgItemText(hwndDlg, IDC_HEADERBAR, szNewTitle);
+ Utils::enableDlgControl(hwndDlg, IDC_O_HIDETITLE, CSkin::m_frameSkins ? FALSE : TRUE);
+ CheckDlgButton(hwndDlg, IDC_CNTPRIVATE, pContainer->settings->fPrivate ? BST_CHECKED : BST_UNCHECKED);
+
+ SendDlgItemMessage(hwndDlg, IDC_TABMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::get(CTranslator::CNT_OPT_TABSTOP));
+ SendDlgItemMessage(hwndDlg, IDC_TABMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::get(CTranslator::CNT_OPT_TABSBOTTOM));
+ SendDlgItemMessage(hwndDlg, IDC_TABMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::get(CTranslator::CNT_OPT_TABSLEFT));
+ SendDlgItemMessage(hwndDlg, IDC_TABMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::get(CTranslator::CNT_OPT_TABSRIGHT));
+
+ SendDlgItemMessage(hwndDlg, IDC_AVATARMODE, CB_INSERTSTRING, -1,
+ (LPARAM)CTranslator::getOpt(CTranslator::OPT_GEN_GLOBALLY_ON));
+ SendDlgItemMessage(hwndDlg, IDC_AVATARMODE, CB_INSERTSTRING, -1,
+ (LPARAM)CTranslator::getOpt(CTranslator::OPT_GEN_ON_IF_PRESENT));
+ SendDlgItemMessage(hwndDlg, IDC_AVATARMODE, CB_INSERTSTRING, -1,
+ (LPARAM)CTranslator::getOpt(CTranslator::OPT_GEN_GLOBALLY_OFF));
+ SendDlgItemMessage(hwndDlg, IDC_AVATARMODE, CB_INSERTSTRING, -1,
+ (LPARAM)CTranslator::getOpt(CTranslator::OPT_GEN_ON_ALWAYS_BOTTOM));
+
+ SendDlgItemMessage(hwndDlg, IDC_OWNAVATARMODE, CB_INSERTSTRING, -1,
+ (LPARAM)CTranslator::getOpt(CTranslator::OPT_GEN_ON_IF_PRESENT));
+ SendDlgItemMessage(hwndDlg, IDC_OWNAVATARMODE, CB_INSERTSTRING, -1,
+ (LPARAM)CTranslator::getOpt(CTranslator::OPT_GEN_DONT_SHOW));
+
+ for(i = 0; i < nr_layouts; i++)
+ SendDlgItemMessage(hwndDlg, IDC_SBARLAYOUT, CB_INSERTSTRING, -1, (LPARAM)TranslateTS(sblayouts[i].szName));
+
+ /* bits 24 - 31 of dwFlagsEx hold the side bar layout id */
+ SendDlgItemMessage(hwndDlg, IDC_SBARLAYOUT, CB_SETCURSEL, (WPARAM)((pContainer->settings->dwFlagsEx & 0xff000000) >> 24), 0);
+
+
+ SendMessage(hwndDlg, DM_SC_INITDIALOG, (WPARAM)0, (LPARAM)pContainer->settings);
+ SendDlgItemMessage(hwndDlg, IDC_TITLEFORMAT, EM_LIMITTEXT, TITLE_FORMATLEN - 1, 0);
+ SetDlgItemText(hwndDlg, IDC_TITLEFORMAT, pContainer->settings->szTitleFormat);
+ SetDlgItemText(hwndDlg, IDC_THEME, pContainer->szRelThemeFile);
+ for (i = 0; i < NR_O_PAGES; i++) {
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
+ tvis.item.pszText = const_cast<TCHAR *>(CTranslator::get(o_pages[i].idTitle));
+ tvis.item.lParam = i;
+ hItem = TreeView_InsertItem(hwndTree, &tvis);
+ if (i == 0)
+ SendMessage(hwndTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem);
+ for (j = 0; j < NR_O_OPTIONSPERPAGE && o_pages[i].uIds[j] != 0; j++)
+ Utils::showDlgControl(hwndDlg, o_pages[i].uIds[j], SW_HIDE);
+ ShowPage(hwndDlg, i, FALSE);
+ }
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE));
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(SKINICON_EVENT_MESSAGE));
+ ShowPage(hwndDlg, 0, TRUE);
+ SetFocus(hwndTree);
+ Utils::enableDlgControl(hwndDlg, IDC_APPLY, FALSE);
+
+ HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_DESC, WM_GETFONT, 0, 0);
+ LOGFONT lf = {0};
+
+ GetObject(hFont, sizeof(lf), &lf);
+ lf.lfHeight = (int)(lf.lfHeight * 1.2);
+ hFont = CreateFontIndirect(&lf);
+
+ SendDlgItemMessage(hwndDlg, IDC_TITLEBOX, WM_SETFONT, (WPARAM)hFont, TRUE);
+
+ if(pContainer->isCloned && pContainer->hContactFrom != 0) {
+ Utils::showDlgControl(hwndDlg, IDC_CNTPRIVATE, SW_HIDE);
+ Utils::showDlgControl(hwndDlg, IDC_O_CNTPRIVATE, SW_HIDE);
+ }
+ return FALSE;
+ }
+
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ {
+ HWND hwndChild = (HWND)lParam;
+ UINT id = GetDlgCtrlID(hwndChild);
+
+ if(hwndChild == GetDlgItem(hwndDlg, IDC_TITLEBOX)) {
+ ::SetTextColor((HDC)wParam, RGB(60, 60, 150));
+ } else if(hwndChild == GetDlgItem(hwndDlg, IDC_DESC))
+ ::SetTextColor((HDC)wParam, RGB(160, 50, 50));
+ if(id == IDC_TSLABEL_REOPENWARN)
+ break;
+ SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
+ return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
+ }
+
+ case WM_NOTIFY:
+ if (wParam == IDC_SECTIONTREE && ((LPNMHDR)lParam)->code == TVN_SELCHANGED) {
+ NMTREEVIEW *pmtv = (NMTREEVIEW *)lParam;
+
+ ShowPage(hwndDlg, pmtv->itemOld.lParam, 0);
+ ShowPage(hwndDlg, pmtv->itemNew.lParam, 1);
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_CNTPRIVATE: {
+
+ if(IsDlgButtonChecked(hwndDlg, IDC_CNTPRIVATE)) {
+ Utils::ReadPrivateContainerSettings(pContainer, true);
+ pContainer->settings->fPrivate = true;
+ }
+ else {
+ if(pContainer->settings != &PluginConfig.globalContainerSettings) {
+ char szCname[40];
+ mir_snprintf(szCname, 40, "%s%d_Blob", CNT_BASEKEYNAME, pContainer->iContainerIndex);
+ pContainer->settings->fPrivate = false;
+ DBWriteContactSettingBlob(0, SRMSGMOD_T, szCname, pContainer->settings, sizeof(TContainerSettings));
+ free(pContainer->settings);
+ }
+ pContainer->settings = &PluginConfig.globalContainerSettings;
+ pContainer->settings->fPrivate = false;
+ }
+ SendMessage(hwndDlg, DM_SC_INITDIALOG, 0, (LPARAM)pContainer->settings);
+ goto do_apply;
+ }
+ case IDC_TRANSPARENCY: {
+ int isTrans = IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENCY);
+
+ Utils::enableDlgControl(hwndDlg, IDC_TRANSPARENCY_ACTIVE, isTrans ? TRUE : FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_TRANSPARENCY_INACTIVE, isTrans ? TRUE : FALSE);
+ goto do_apply;
+ }
+ case IDC_SECTIONTREE:
+ case IDC_DESC:
+ return 0;
+ case IDC_SAVESIZEASGLOBAL: {
+ WINDOWPLACEMENT wp = {0};
+
+ wp.length = sizeof(wp);
+ if (GetWindowPlacement(pContainer->hwnd, &wp)) {
+ M->WriteDword(SRMSGMOD_T, "splitx", wp.rcNormalPosition.left);
+ M->WriteDword(SRMSGMOD_T, "splity", wp.rcNormalPosition.top);
+ M->WriteDword(SRMSGMOD_T, "splitwidth", wp.rcNormalPosition.right - wp.rcNormalPosition.left);
+ M->WriteDword(SRMSGMOD_T, "splitheight", wp.rcNormalPosition.bottom - wp.rcNormalPosition.top);
+ }
+ break;
+ }
+ case IDC_O_ENABLESOUNDS:
+ SendMessage(hwndDlg, DM_SC_CONFIG, 0, 0);
+ break;
+ case IDC_TITLEFORMAT:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return TRUE;
+ goto do_apply;
+ case IDC_SELECTTHEME: {
+ const wchar_t *szFileName = GetThemeFileName(0);
+
+ if (PathFileExists(szFileName)) {
+ SetDlgItemText(hwndDlg, IDC_THEME, szFileName);
+ goto do_apply;
+ }
+ break;
+ }
+
+ case IDC_O_HELP_TITLEFORMAT:
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://miranda.or.at/TabSRMM/TitleBarFormatting");
+ break;
+
+ case IDOK:
+ case IDC_APPLY: {
+
+ SendMessage(hwndDlg, DM_SC_BUILDLIST, 0, (LPARAM)pContainer->settings);
+
+ pContainer->settings->dwTransparency = MAKELONG((WORD)SendDlgItemMessage(hwndDlg, IDC_TRANSPARENCY_ACTIVE, TBM_GETPOS, 0, 0),
+ (WORD)SendDlgItemMessage(hwndDlg, IDC_TRANSPARENCY_INACTIVE, TBM_GETPOS, 0, 0));
+
+ pContainer->settings->avatarMode = (WORD)SendDlgItemMessage(hwndDlg, IDC_AVATARMODE, CB_GETCURSEL, 0, 0);
+ pContainer->settings->ownAvatarMode = (WORD)SendDlgItemMessage(hwndDlg, IDC_OWNAVATARMODE, CB_GETCURSEL, 0, 0);
+
+ GetDlgItemText(hwndDlg, IDC_TITLEFORMAT, pContainer->settings->szTitleFormat, TITLE_FORMATLEN);
+ pContainer->settings->szTitleFormat[TITLE_FORMATLEN - 1] = 0;
+
+ pContainer->szRelThemeFile[0] = pContainer->szAbsThemeFile[0] = 0;
+
+ if (GetWindowTextLengthA(GetDlgItem(hwndDlg, IDC_THEME)) > 0) {
+ wchar_t szFinalThemeFile[MAX_PATH], szFilename[MAX_PATH];
+
+ GetDlgItemText(hwndDlg, IDC_THEME, szFilename, MAX_PATH);
+ szFilename[MAX_PATH - 1] = 0;
+ M->pathToAbsolute(szFilename, szFinalThemeFile);
+
+ if(_tcscmp(szFilename, pContainer->szRelThemeFile))
+ pContainer->fPrivateThemeChanged = TRUE;
+
+ if (PathFileExists(szFinalThemeFile))
+ mir_sntprintf(pContainer->szRelThemeFile, MAX_PATH, _T("%s"), szFilename);
+ else
+ pContainer->szRelThemeFile[0] = 0;
+ }
+ else {
+ pContainer->szRelThemeFile[0] = 0;
+ pContainer->fPrivateThemeChanged = TRUE;
+ }
+
+ Utils::SettingsToContainer(pContainer);
+
+ if (!IsDlgButtonChecked(hwndDlg, IDC_CNTPRIVATE)) {
+ ReloadGlobalContainerSettings(true);
+ ::DBWriteContactSettingBlob(0, SRMSGMOD_T, CNT_KEYNAME, &PluginConfig.globalContainerSettings, sizeof(TContainerSettings));
+ }
+ else {
+ char *szSetting = "CNTW_";
+ Utils::SaveContainerSettings(pContainer, szSetting);
+ }
+
+ SendMessage(pContainer->hwnd, DM_CONFIGURECONTAINER, 0, 0);
+ BroadCastContainer(pContainer, DM_SETINFOPANEL, 0, 0);
+
+ ShowWindow(pContainer->hwnd, SW_HIDE);
+ {
+ RECT rc;
+
+ GetWindowRect(pContainer->hwnd, &rc);
+ SetWindowPos(pContainer->hwnd, 0, rc.left, rc.top, (rc.right - rc.left) - 1, (rc.bottom - rc.top) - 1, SWP_NOZORDER | SWP_DRAWFRAME | SWP_FRAMECHANGED);
+ SetWindowPos(pContainer->hwnd, 0, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), SWP_NOZORDER | SWP_DRAWFRAME | SWP_SHOWWINDOW);
+ }
+
+ if (LOWORD(wParam) == IDOK)
+ DestroyWindow(hwndDlg);
+ else
+ Utils::enableDlgControl(hwndDlg, IDC_APPLY, FALSE);
+
+ break;
+ }
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ default:
+do_apply:
+ Utils::enableDlgControl(hwndDlg, IDC_APPLY, TRUE);
+ break;
+ }
+ break;
+ case DM_SC_INITDIALOG: {
+ TContainerSettings* cs = (TContainerSettings *)lParam;
+
+ DWORD dwFlags = cs->dwFlags;
+ DWORD dwTransparency = cs->dwTransparency;
+ DWORD dwFlagsEx = cs->dwFlagsEx;
+ int isTrans;
+ BOOL fAllowTrans = FALSE;
+
+ if(PluginConfig.m_WinVerMajor >= 6)
+ fAllowTrans = TRUE;
+ else
+ fAllowTrans = (!CSkin::m_skinEnabled);
+
+ MY_CheckDlgButton(hwndDlg, IDC_O_HIDETITLE, dwFlags & CNT_NOTITLE);
+ MY_CheckDlgButton(hwndDlg, IDC_O_DONTREPORT, dwFlags & CNT_DONTREPORT);
+ MY_CheckDlgButton(hwndDlg, IDC_O_NOTABS, dwFlags & CNT_HIDETABS);
+ MY_CheckDlgButton(hwndDlg, IDC_O_STICKY, dwFlags & CNT_STICKY);
+ MY_CheckDlgButton(hwndDlg, IDC_O_FLASHNEVER, dwFlags & CNT_NOFLASH);
+ MY_CheckDlgButton(hwndDlg, IDC_O_FLASHALWAYS, dwFlags & CNT_FLASHALWAYS);
+ MY_CheckDlgButton(hwndDlg, IDC_O_FLASHDEFAULT, !((dwFlags & CNT_NOFLASH) || (dwFlags & CNT_FLASHALWAYS)));
+ MY_CheckDlgButton(hwndDlg, IDC_TRANSPARENCY, dwFlags & CNT_TRANSPARENCY);
+ MY_CheckDlgButton(hwndDlg, IDC_DONTREPORTUNFOCUSED2, dwFlags & CNT_DONTREPORTUNFOCUSED);
+ MY_CheckDlgButton(hwndDlg, IDC_DONTREPORTFOCUSED2, dwFlags & CNT_DONTREPORTFOCUSED);
+ MY_CheckDlgButton(hwndDlg, IDC_ALWAYSPOPUPSINACTIVE, dwFlags & CNT_ALWAYSREPORTINACTIVE);
+ MY_CheckDlgButton(hwndDlg, IDC_CNTNOSTATUSBAR, dwFlags & CNT_NOSTATUSBAR);
+ MY_CheckDlgButton(hwndDlg, IDC_HIDEMENUBAR, dwFlags & CNT_NOMENUBAR);
+ MY_CheckDlgButton(hwndDlg, IDC_HIDETOOLBAR, dwFlags & CNT_HIDETOOLBAR);
+ MY_CheckDlgButton(hwndDlg, IDC_BOTTOMTOOLBAR, dwFlags & CNT_BOTTOMTOOLBAR);
+ MY_CheckDlgButton(hwndDlg, IDC_UIDSTATUSBAR, dwFlags & CNT_UINSTATUSBAR);
+ MY_CheckDlgButton(hwndDlg, IDC_VERTICALMAX, dwFlags & CNT_VERTICALMAX);
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ MY_CheckDlgButton(hwndDlg, IDC_AUTOSPLITTER, dwFlags & CNT_AUTOSPLITTER);
+#endif
+ MY_CheckDlgButton(hwndDlg, IDC_AVATARSONTASKBAR, dwFlags & CNT_AVATARSONTASKBAR);
+ MY_CheckDlgButton(hwndDlg, IDC_INFOPANEL, dwFlags & CNT_INFOPANEL);
+ MY_CheckDlgButton(hwndDlg, IDC_USEGLOBALSIZE, dwFlags & CNT_GLOBALSIZE);
+
+ MY_CheckDlgButton(hwndDlg, IDC_FLASHICON, dwFlagsEx & TCF_FLASHICON);
+ MY_CheckDlgButton(hwndDlg, IDC_FLASHLABEL, dwFlagsEx & TCF_FLASHLABEL);
+ MY_CheckDlgButton(hwndDlg, IDC_CLOSEBUTTONONTABS, dwFlagsEx & TCF_CLOSEBUTTON);
+
+ MY_CheckDlgButton(hwndDlg, IDC_SINGLEROWTAB, dwFlagsEx & TCF_SINGLEROWTABCONTROL);
+ MY_CheckDlgButton(hwndDlg, IDC_BUTTONTABS, dwFlagsEx & TCF_FLAT);
+
+ MY_CheckDlgButton(hwndDlg, IDC_O_ENABLESOUNDS, !(dwFlags & CNT_NOSOUND));
+ MY_CheckDlgButton(hwndDlg, IDC_O_SOUNDSMINIMIZED, dwFlagsEx & CNT_EX_SOUNDS_MINIMIZED);
+ MY_CheckDlgButton(hwndDlg, IDC_O_SOUNDSUNFOCUSED, dwFlagsEx & CNT_EX_SOUNDS_UNFOCUSED);
+ MY_CheckDlgButton(hwndDlg, IDC_O_SOUNDSINACTIVE, dwFlagsEx & CNT_EX_SOUNDS_INACTIVETABS);
+ MY_CheckDlgButton(hwndDlg, IDC_O_SOUNDSFOCUSED, dwFlagsEx & CNT_EX_SOUNDS_FOCUSED);
+
+ SendMessage(hwndDlg, DM_SC_CONFIG, 0, 0);
+
+ if(!(dwFlagsEx & (TCF_SBARLEFT | TCF_SBARRIGHT)))
+ SendDlgItemMessage(hwndDlg, IDC_TABMODE, CB_SETCURSEL, dwFlags & CNT_TABSBOTTOM ? 1 : 0, 0);
+ else
+ SendDlgItemMessage(hwndDlg, IDC_TABMODE, CB_SETCURSEL, dwFlagsEx & TCF_SBARLEFT ? 2 : 3, 0);
+
+ if (LOBYTE(LOWORD(GetVersion())) >= 5 && fAllowTrans)
+ CheckDlgButton(hwndDlg, IDC_TRANSPARENCY, dwFlags & CNT_TRANSPARENCY);
+ else
+ CheckDlgButton(hwndDlg, IDC_TRANSPARENCY, FALSE);
+
+ Utils::enableDlgControl(hwndDlg, IDC_TRANSPARENCY, PluginConfig.m_WinVerMajor >= 5 && fAllowTrans ? TRUE : FALSE);
+
+ isTrans = IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENCY);
+ Utils::enableDlgControl(hwndDlg, IDC_TRANSPARENCY_ACTIVE, isTrans ? TRUE : FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_TRANSPARENCY_INACTIVE, isTrans ? TRUE : FALSE);
+
+ SendDlgItemMessage(hwndDlg, IDC_TRANSPARENCY_ACTIVE, TBM_SETRANGE, 0, (LPARAM)MAKELONG(50, 255));
+ SendDlgItemMessage(hwndDlg, IDC_TRANSPARENCY_INACTIVE, TBM_SETRANGE, 0, (LPARAM)MAKELONG(50, 255));
+
+ SendDlgItemMessage(hwndDlg, IDC_TRANSPARENCY_ACTIVE, TBM_SETPOS, TRUE, (LPARAM) LOWORD(dwTransparency));
+ SendDlgItemMessage(hwndDlg, IDC_TRANSPARENCY_INACTIVE, TBM_SETPOS, TRUE, (LPARAM) HIWORD(dwTransparency));
+
+ Utils::enableDlgControl(hwndDlg, IDC_O_DONTREPORT, nen_options.bWindowCheck == 0);
+ Utils::enableDlgControl(hwndDlg, IDC_DONTREPORTUNFOCUSED2, nen_options.bWindowCheck == 0);
+ Utils::enableDlgControl(hwndDlg, IDC_DONTREPORTFOCUSED2, nen_options.bWindowCheck == 0);
+ Utils::enableDlgControl(hwndDlg, IDC_ALWAYSPOPUPSINACTIVE, nen_options.bWindowCheck == 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_AVATARMODE, CB_SETCURSEL, (WPARAM)cs->avatarMode, 0);
+ SendDlgItemMessage(hwndDlg, IDC_OWNAVATARMODE, CB_SETCURSEL, (WPARAM)cs->ownAvatarMode, 0);
+
+ Utils::showDlgControl(hwndDlg, IDC_O_EXPLAINGLOBALNOTIFY, nen_options.bWindowCheck ? SW_SHOW : SW_HIDE);
+
+ SendDlgItemMessage(hwndDlg, IDC_AUTOCLOSETABSPIN, UDM_SETRANGE, 0, MAKELONG(1000, 0));
+ SendDlgItemMessage(hwndDlg, IDC_AUTOCLOSETABSPIN, UDM_SETPOS, 0, (LPARAM)cs->autoCloseSeconds);
+ break;
+ }
+
+ case DM_SC_CONFIG: {
+ LRESULT enable = (IsDlgButtonChecked(hwndDlg, IDC_O_ENABLESOUNDS) ? BST_CHECKED : BST_UNCHECKED);
+ Utils::enableDlgControl(hwndDlg, IDC_O_SOUNDSINACTIVE, enable);
+ Utils::enableDlgControl(hwndDlg, IDC_O_SOUNDSUNFOCUSED, enable);
+ Utils::enableDlgControl(hwndDlg, IDC_O_SOUNDSMINIMIZED, enable);
+ Utils::enableDlgControl(hwndDlg, IDC_O_SOUNDSFOCUSED, enable);
+ return(0);
+ }
+
+ case DM_SC_BUILDLIST: {
+ DWORD dwNewFlags = 0, dwNewFlagsEx = 0;
+ TContainerSettings* cs = (TContainerSettings *)lParam;
+
+ dwNewFlags = (IsDlgButtonChecked(hwndDlg, IDC_O_HIDETITLE) ? CNT_NOTITLE : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_O_DONTREPORT) ? CNT_DONTREPORT : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_O_NOTABS) ? CNT_HIDETABS : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_O_STICKY) ? CNT_STICKY : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_O_FLASHALWAYS) ? CNT_FLASHALWAYS : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_O_FLASHNEVER) ? CNT_NOFLASH : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENCY) ? CNT_TRANSPARENCY : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_DONTREPORTUNFOCUSED2) ? CNT_DONTREPORTUNFOCUSED : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_DONTREPORTFOCUSED2) ? CNT_DONTREPORTFOCUSED : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_ALWAYSPOPUPSINACTIVE) ? CNT_ALWAYSREPORTINACTIVE : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_CNTNOSTATUSBAR) ? CNT_NOSTATUSBAR : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_HIDEMENUBAR) ? CNT_NOMENUBAR : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_HIDETOOLBAR) ? CNT_HIDETOOLBAR : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_BOTTOMTOOLBAR) ? CNT_BOTTOMTOOLBAR : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_UIDSTATUSBAR) ? CNT_UINSTATUSBAR : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_USEGLOBALSIZE) ? CNT_GLOBALSIZE : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_INFOPANEL) ? CNT_INFOPANEL : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_O_ENABLESOUNDS) ? 0 : CNT_NOSOUND) |
+ (IsDlgButtonChecked(hwndDlg, IDC_AVATARSONTASKBAR) ? CNT_AVATARSONTASKBAR : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_VERTICALMAX) ? CNT_VERTICALMAX : 0) |
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ (IsDlgButtonChecked(hwndDlg, IDC_AUTOSPLITTER) ? CNT_AUTOSPLITTER : 0) |
+#endif
+ (CNT_NEWCONTAINERFLAGS);
+
+ LRESULT iTabMode = SendDlgItemMessage(hwndDlg, IDC_TABMODE, CB_GETCURSEL, 0, 0);
+ LRESULT iTabLayout = SendDlgItemMessage(hwndDlg, IDC_SBARLAYOUT, CB_GETCURSEL, 0, 0);
+
+ dwNewFlagsEx = 0;
+
+ if(iTabMode < 2)
+ dwNewFlags = ((iTabMode == 1) ? (dwNewFlags | CNT_TABSBOTTOM) : (dwNewFlags & ~CNT_TABSBOTTOM));
+ else {
+ dwNewFlags &= ~CNT_TABSBOTTOM;
+ dwNewFlagsEx = iTabMode == 2 ? TCF_SBARLEFT : TCF_SBARRIGHT;
+ }
+
+ dwNewFlagsEx |= ((IsDlgButtonChecked(hwndDlg, IDC_FLASHICON) ? TCF_FLASHICON : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_FLASHLABEL) ? TCF_FLASHLABEL : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_BUTTONTABS) ? TCF_FLAT : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_CLOSEBUTTONONTABS) ? TCF_CLOSEBUTTON : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_SINGLEROWTAB) ? TCF_SINGLEROWTABCONTROL : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_O_SOUNDSMINIMIZED) ? CNT_EX_SOUNDS_MINIMIZED : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_O_SOUNDSUNFOCUSED) ? CNT_EX_SOUNDS_UNFOCUSED : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_O_SOUNDSFOCUSED) ? CNT_EX_SOUNDS_FOCUSED : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_O_SOUNDSINACTIVE) ? CNT_EX_SOUNDS_INACTIVETABS : 0)
+ );
+
+ /* bits 24 - 31 of dwFlagsEx hold the sidebar layout id */
+ dwNewFlagsEx |= ((int)((iTabLayout << 24) & 0xff000000));
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_O_FLASHDEFAULT))
+ dwNewFlags &= ~(CNT_FLASHALWAYS | CNT_NOFLASH);
+
+ cs->dwFlags = dwNewFlags;
+ cs->dwFlagsEx = dwNewFlagsEx;
+ cs->autoCloseSeconds = (WORD)SendDlgItemMessage(hwndDlg, IDC_AUTOCLOSETABSPIN, UDM_GETPOS, 0, 0);
+ break;
+ }
+ case WM_DESTROY: {
+ pContainer->hWndOptions = 0;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+
+ HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_TITLEBOX, WM_GETFONT, 0, 0);
+ DeleteObject(hFont);
+ break;
+ }
+ }
+ return FALSE;
+}
diff --git a/plugins/TabSRMM/src/controls.cpp b/plugins/TabSRMM/src/controls.cpp
new file mode 100644
index 0000000000..f524de5f1a
--- /dev/null
+++ b/plugins/TabSRMM/src/controls.cpp
@@ -0,0 +1,1157 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: controls.cpp 13587 2011-04-12 13:54:26Z george.hazan $
+ *
+ * Menu and status bar control(s) for the container window.
+ *
+ */
+
+#include "commonheaders.h"
+static WNDPROC OldStatusBarproc = 0;
+
+extern int status_icon_list_size;
+extern TStatusBarIconNode *status_icon_list;
+
+bool CMenuBar::m_buttonsInit = false;
+HHOOK CMenuBar::m_hHook = 0;
+TBBUTTON CMenuBar::m_TbButtons[8] = {0};
+CMenuBar* CMenuBar::m_Owner = 0;
+HBITMAP CMenuBar::m_MimIcon = 0;
+int CMenuBar::m_MimIconRefCount = 0;
+
+CMenuBar::CMenuBar(HWND hwndParent, const TContainerData *pContainer)
+{
+ m_pContainer = const_cast<TContainerData *>(pContainer);
+
+ if(m_MimIcon == 0) {
+ HDC hdc = ::GetDC(m_pContainer->hwnd);
+ HANDLE hIcon = LoadSkinnedIconHandle(SKINICON_OTHER_MIRANDA);
+
+ HDC hdcTemp = ::CreateCompatibleDC(hdc);
+
+ RECT rc = {0,0,16,16};
+ m_MimIcon = CSkin::CreateAeroCompatibleBitmap(rc, hdcTemp);
+ HBITMAP hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(hdcTemp, m_MimIcon));
+ ::DrawIconEx(hdcTemp, 0, 0, (HICON)hIcon, 16, 16, 0, 0, DI_NORMAL);
+ ::SelectObject(hdcTemp, hbmOld);
+
+ ::DeleteDC(hdcTemp);
+ ::ReleaseDC(m_pContainer->hwnd, hdc);
+ }
+
+ m_MimIconRefCount++;
+
+ m_hwndToolbar = ::CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL, WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_VISIBLE|TBSTYLE_FLAT|TBSTYLE_TRANSPARENT|TBSTYLE_LIST|/*CCS_NOPARENTALIGN|*/CCS_NODIVIDER|CCS_TOP,
+ 0, 0, 0, 0, hwndParent, NULL, g_hInst, NULL);
+
+ ::SendMessage(m_hwndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
+
+ if(m_buttonsInit == false) {
+ ::ZeroMemory(m_TbButtons, sizeof(m_TbButtons));
+
+ m_TbButtons[0].iBitmap = 0;//I_IMAGENONE;
+ m_TbButtons[0].iString = 0;//(INT_PTR)TranslateT("&Main");
+ m_TbButtons[0].fsState = TBSTATE_ENABLED;
+ m_TbButtons[0].fsStyle = BTNS_DROPDOWN|BTNS_AUTOSIZE;
+ m_TbButtons[0].idCommand = 100;
+ m_TbButtons[0].dwData = 0;
+
+ m_TbButtons[1].iBitmap = I_IMAGENONE;
+ m_TbButtons[1].iString = (INT_PTR)CTranslator::get(CTranslator::GEN_MENUBAR_FILE);
+ m_TbButtons[1].fsState = TBSTATE_ENABLED;
+ m_TbButtons[1].fsStyle = BTNS_DROPDOWN|BTNS_AUTOSIZE;
+ m_TbButtons[1].idCommand = 101;
+ m_TbButtons[1].dwData = reinterpret_cast<DWORD_PTR>(::GetSubMenu(PluginConfig.getMenuBar(), 0));
+
+ m_TbButtons[2].iBitmap = I_IMAGENONE;
+ m_TbButtons[2].iString = (INT_PTR)CTranslator::get(CTranslator::GEN_MENUBAR_VIEW);
+ m_TbButtons[2].fsState = TBSTATE_ENABLED;
+ m_TbButtons[2].fsStyle = BTNS_DROPDOWN|BTNS_AUTOSIZE;
+ m_TbButtons[2].idCommand = 102;
+ m_TbButtons[2].dwData = reinterpret_cast<DWORD_PTR>(::GetSubMenu(PluginConfig.getMenuBar(), 1));
+
+ m_TbButtons[3].iBitmap = I_IMAGENONE;
+ m_TbButtons[3].iString = (INT_PTR)CTranslator::get(CTranslator::GEN_MENUBAR_USER);
+ m_TbButtons[3].fsState = TBSTATE_ENABLED;
+ m_TbButtons[3].fsStyle = BTNS_DROPDOWN|BTNS_AUTOSIZE;
+ m_TbButtons[3].idCommand = 103;
+ m_TbButtons[3].dwData = 0; // dynamically built by Clist service
+
+ m_TbButtons[4].iBitmap = I_IMAGENONE;
+ m_TbButtons[4].iString = (INT_PTR)CTranslator::get(CTranslator::GEN_MENUBAR_ROOM);
+ m_TbButtons[4].fsState = TBSTATE_ENABLED;
+ m_TbButtons[4].fsStyle = BTNS_DROPDOWN|BTNS_AUTOSIZE;
+ m_TbButtons[4].idCommand = 104;
+ m_TbButtons[4].dwData = 0;
+
+ m_TbButtons[5].iBitmap = I_IMAGENONE;
+ m_TbButtons[5].iString = (INT_PTR)CTranslator::get(CTranslator::GEN_MENUBAR_LOG);
+ m_TbButtons[5].fsState = TBSTATE_ENABLED;
+ m_TbButtons[5].fsStyle = BTNS_DROPDOWN|BTNS_AUTOSIZE;
+ m_TbButtons[5].idCommand = 105;
+ m_TbButtons[5].dwData = reinterpret_cast<DWORD_PTR>(::GetSubMenu(PluginConfig.getMenuBar(), 2));
+
+ m_TbButtons[6].iBitmap = I_IMAGENONE;
+ m_TbButtons[6].iString = (INT_PTR)CTranslator::get(CTranslator::GEN_MENUBAR_CONTAINER);
+ m_TbButtons[6].fsState = TBSTATE_ENABLED;
+ m_TbButtons[6].fsStyle = BTNS_DROPDOWN|BTNS_AUTOSIZE;
+ m_TbButtons[6].idCommand = 106;
+ m_TbButtons[6].dwData = reinterpret_cast<DWORD_PTR>(::GetSubMenu(PluginConfig.getMenuBar(), 3));
+
+ m_TbButtons[7].iBitmap = I_IMAGENONE;
+ m_TbButtons[7].iString = (INT_PTR)CTranslator::get(CTranslator::GEN_MENUBAR_HELP);
+ m_TbButtons[7].fsState = TBSTATE_ENABLED;
+ m_TbButtons[7].fsStyle = BTNS_DROPDOWN|BTNS_AUTOSIZE;
+ m_TbButtons[7].idCommand = 107;
+ m_TbButtons[7].dwData = reinterpret_cast<DWORD_PTR>(::GetSubMenu(PluginConfig.getMenuBar(), 4));
+
+ m_buttonsInit = true;
+ }
+
+ ::SendMessage(m_hwndToolbar, TB_ADDBUTTONS, sizeof(m_TbButtons)/sizeof(TBBUTTON), (LPARAM)m_TbButtons);
+
+ m_size_y = HIWORD(::SendMessage(m_hwndToolbar, TB_GETBUTTONSIZE, 0, 0));
+
+ TBADDBITMAP tb;
+ tb.nID = (UINT_PTR)m_MimIcon;
+ tb.hInst = 0;
+
+ ::SendMessage(m_hwndToolbar, TB_ADDBITMAP, 1, (LPARAM)&tb);
+
+ m_activeMenu = 0;
+ m_activeID = 0;
+ m_isAero = M->isAero();
+ m_mustAutoHide = false;
+ m_activeSubMenu = 0;
+ m_fTracking = false;
+ m_isContactMenu = m_isMainMenu = false;
+
+ m_oldWndProc = (WNDPROC)::GetWindowLongPtr(m_hwndToolbar, GWLP_WNDPROC);
+ ::SetWindowLongPtr(m_hwndToolbar, GWLP_USERDATA, (UINT_PTR)this);
+ ::SetWindowLongPtr(m_hwndToolbar, GWLP_WNDPROC, (UINT_PTR)wndProc);
+}
+
+CMenuBar::~CMenuBar()
+{
+ ::SetWindowLongPtr(m_hwndToolbar, GWLP_WNDPROC, (UINT_PTR)m_oldWndProc);
+ ::SetWindowLongPtr(m_hwndToolbar, GWLP_USERDATA, 0);
+ ::DestroyWindow(m_hwndToolbar);
+ releaseHook();
+ m_MimIconRefCount--;
+ if(m_MimIconRefCount == 0) {
+ ::DeleteObject(m_MimIcon);
+ m_MimIcon = 0;
+ }
+}
+
+/**
+ * retrieves the client rectangle for the rebar control. This must be
+ * called once per WM_SIZE event by the parent window. getHeight() depends on it.
+ *
+ * @return RECT&: client rectangle of the rebar control
+ */
+const RECT& CMenuBar::getClientRect()
+{
+ ::GetClientRect(m_hwndToolbar, &m_rcClient);
+ return(m_rcClient);
+}
+
+void CMenuBar::obtainHook()
+{
+ releaseHook();
+ if(m_hHook == 0)
+ m_hHook = ::SetWindowsHookEx(WH_MSGFILTER, CMenuBar::MessageHook, g_hInst, 0);
+ m_Owner = this;
+}
+
+void CMenuBar::releaseHook()
+{
+ if(m_hHook) {
+ ::UnhookWindowsHookEx(m_hHook);
+ m_hHook = 0;
+ }
+}
+/**
+ * Retrieve the height of the rebar control
+ *
+ * @return LONG: height of the rebar, in pixels
+ */
+LONG CMenuBar::getHeight() const
+{
+ return((m_pContainer->dwFlags & CNT_NOMENUBAR) ? 0 : m_size_y);
+}
+
+/**
+ * process all relevant messages. Must be called by the parent window's
+ * window procedure.
+ *
+ * @param msg
+ * @param wParam
+ * @param lParam
+ *
+ * @return LRESULT: message processing result. Win32 conform.
+ * -1 means: nothing processed, caller should continue as usual.
+ */
+LONG_PTR CMenuBar::processMsg(const UINT msg, const WPARAM wParam, const LPARAM lParam)
+{
+ if(msg == WM_NOTIFY) {
+ NMHDR* pNMHDR = (NMHDR*)lParam;
+ switch(pNMHDR->code) {
+ case NM_CUSTOMDRAW: {
+ NMCUSTOMDRAW *nm = (NMCUSTOMDRAW*)lParam;
+ return(customDrawWorker(nm));
+ }
+
+ case TBN_DROPDOWN: {
+ NMTOOLBAR *mtb = (NMTOOLBAR *)lParam;
+
+ LRESULT result = Handle(mtb);
+ return(result);
+ }
+ case TBN_HOTITEMCHANGE: {
+ NMTBHOTITEM *nmtb = (NMTBHOTITEM *)lParam;
+
+ if(nmtb->idNew != 0 && m_fTracking && nmtb->idNew != m_activeID && m_activeID != 0) {
+ cancel(0);
+ return(0);
+ }
+ else if(m_fTracking == true && m_activeID == 0 && nmtb->idNew != 0) {
+ invoke(nmtb->idNew);
+ return(0);
+ }
+ break;
+ }
+ default:
+ return(-1);
+ }
+ }
+ else if(msg == WM_LBUTTONDOWN) {
+ if (m_pContainer->dwFlags & CNT_NOTITLE) {
+ POINT pt;
+
+ ::GetCursorPos(&pt);
+ return ::SendMessage(m_pContainer->hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ }
+ }
+ return(-1);
+}
+
+/**
+ * subclass the toolbar control to handle some keyboard events and improve
+ * keyboard navigation
+ */
+
+LRESULT CALLBACK CMenuBar::wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CMenuBar *menuBar = reinterpret_cast<CMenuBar *>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
+
+ switch(msg) {
+ case WM_SYSKEYUP: {
+ if(wParam == VK_MENU) {
+ menuBar->Cancel();
+ return(0);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return(::CallWindowProc(menuBar->m_oldWndProc, hWnd, msg, wParam, lParam));
+}
+
+/**
+ * Implements NM_CUSTOMDRAW for the toolbar
+ *
+ * @param nm NMCUSTOMDRAW *: sent via NM_CUSTOMDRAW message
+ *
+ * @return LONG_PTR: see Win32 NM_CUSTOMDRAW message. The function must return a valid
+ * message return value to indicate how Windows should continue with the drawing process.
+ *
+ * It may return zero in which case, the caller should allow default processing for
+ * the NM_CUSTOMDRAW message.
+ */
+LONG_PTR CMenuBar::customDrawWorker(NMCUSTOMDRAW *nm)
+{
+ bool fMustDraw = true;
+
+ if(nm->hdr.hwndFrom == m_hwndToolbar) {
+ NMTBCUSTOMDRAW *nmtb = (NMTBCUSTOMDRAW *)(nm);
+
+ switch(nmtb->nmcd.dwDrawStage) {
+ case CDDS_PREPAINT:
+ if(fMustDraw) {
+ if(nmtb->nmcd.dwItemSpec == 0) {
+ m_hdcDraw = ::CreateCompatibleDC(nmtb->nmcd.hdc);
+ //m_rcItem = nmtb->nmcd.rc;
+ ::GetClientRect(m_hwndToolbar, &m_rcItem);
+ m_rcItem.bottom -= 4;
+ m_hbmDraw = CSkin::CreateAeroCompatibleBitmap(m_rcItem, nmtb->nmcd.hdc);
+ m_hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(m_hdcDraw, m_hbmDraw));
+ m_hTheme = M->isAero() || M->isVSThemed() ? CMimAPI::m_pfnOpenThemeData(m_hwndToolbar, L"REBAR") : 0;
+ m_hOldFont = reinterpret_cast<HFONT>(::SelectObject(m_hdcDraw, reinterpret_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT))));
+ if(m_isAero) {
+ nm->rc.bottom--;
+ CSkin::ApplyAeroEffect(m_hdcDraw, &m_rcItem, CSkin::AERO_EFFECT_AREA_MENUBAR);
+ nm->rc.bottom++;
+ }
+ else if((PluginConfig.m_fillColor || M->isVSThemed()) && !CSkin::m_skinEnabled) {
+ if(PluginConfig.m_fillColor && PluginConfig.m_tbBackgroundHigh && PluginConfig.m_tbBackgroundLow) {
+ ::DrawAlpha(m_hdcDraw, &m_rcItem, PluginConfig.m_tbBackgroundHigh, 100, PluginConfig.m_tbBackgroundLow, 0,
+ GRADIENT_TB, 0, 0, 0);
+ }
+ else {
+ m_rcItem.bottom--;
+ if(PluginConfig.m_fillColor)
+ CSkin::FillBack(m_hdcDraw, &m_rcItem);
+ else if(M->isVSThemed())
+ M->m_pfnDrawThemeBackground(m_hTheme, m_hdcDraw, 6, 1, &m_rcItem, &m_rcItem);
+ else
+ FillRect(m_hdcDraw, &m_rcItem, GetSysColorBrush(COLOR_3DFACE));
+ }
+ }
+ else if(CSkin::m_MenuBGBrush)
+ ::FillRect(m_hdcDraw, &nm->rc, CSkin::m_MenuBGBrush);
+ else
+ ::FillRect(m_hdcDraw, &nm->rc, GetSysColorBrush(COLOR_3DFACE));
+ }
+ return(CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT | CDRF_NOTIFYPOSTERASE);
+ }
+ else {
+ m_hdcDraw = 0;
+ return(CDRF_DODEFAULT);
+ }
+
+ case CDDS_ITEMPREPAINT:
+ if(fMustDraw) {
+ TCHAR *szText = 0;
+ bool fDraw = true;
+
+ int iIndex = idToIndex(nmtb->nmcd.dwItemSpec);
+
+ if(iIndex >= 0 && iIndex < NR_BUTTONS)
+ szText = reinterpret_cast<TCHAR *>(m_TbButtons[iIndex].iString);
+
+ UINT uState = nmtb->nmcd.uItemState;
+
+ nmtb->nmcd.rc.bottom--;
+ if(CSkin::m_skinEnabled) {
+ CSkinItem *item = 0;
+
+ ::FillRect(m_hdcDraw, &nmtb->nmcd.rc, CSkin::m_MenuBGBrush);
+
+ if(uState & CDIS_MARKED || uState & CDIS_CHECKED || uState & CDIS_SELECTED)
+ item = &SkinItems[ID_EXTBKBUTTONSPRESSED];
+ else if(uState & CDIS_HOT)
+ item = &SkinItems[ID_EXTBKBUTTONSMOUSEOVER];
+
+ if(item)
+ fDraw = !CSkin::DrawItem(m_hdcDraw, &nmtb->nmcd.rc, item);
+ else
+ fDraw = false;
+ }
+ if(fDraw) {
+ COLORREF clr = ::GetSysColor(COLOR_HOTLIGHT);
+ COLORREF clrRev = clr;
+ if(uState & CDIS_MARKED || uState & CDIS_CHECKED) {
+ ::DrawAlpha(m_hdcDraw, &nmtb->nmcd.rc, clrRev, 80, clrRev, 0, 9,
+ 31, 4, 0);
+ }
+ if(uState & CDIS_SELECTED) {
+ ::DrawAlpha(m_hdcDraw, &nmtb->nmcd.rc, clrRev, 80, clrRev, 0, 9,
+ 31, 4, 0);
+ }
+ if(uState & CDIS_HOT) {
+ ::DrawAlpha(m_hdcDraw, &nmtb->nmcd.rc, clrRev, 80, clrRev, 0, 9,
+ 31, 4, 0);
+ }
+ }
+
+ if(szText) {
+ COLORREF clr = CSkin::m_skinEnabled ? CSkin::m_DefaultFontColor :
+ (PluginConfig.m_fillColor ? PluginConfig.m_genericTxtColor :
+ (uState & (CDIS_SELECTED | CDIS_HOT | CDIS_MARKED)) ? ::GetSysColor(COLOR_HIGHLIGHTTEXT) : ::GetSysColor(COLOR_BTNTEXT));
+
+ ::SetBkMode(m_hdcDraw, TRANSPARENT);
+ CSkin::RenderText(m_hdcDraw, m_hTheme, szText, &nmtb->nmcd.rc, DT_SINGLELINE | DT_VCENTER | DT_CENTER,
+ CSkin::m_glowSize, clr);
+ }
+ if(iIndex == 0) {
+ ::DrawIconEx(m_hdcDraw, (nmtb->nmcd.rc.left + nmtb->nmcd.rc.right) / 2 - 8,
+ (nmtb->nmcd.rc.top + nmtb->nmcd.rc.bottom) / 2 - 8, LoadSkinnedIcon(SKINICON_OTHER_MIRANDA),
+ 16, 16, 0, 0, DI_NORMAL);
+ }
+ return(CDRF_SKIPDEFAULT);
+ }
+ else
+ return(CDRF_DODEFAULT);
+
+ case CDDS_PREERASE:
+ case CDDS_ITEMPOSTERASE:
+ case CDDS_ITEMPOSTPAINT:
+ case CDDS_ITEMPREERASE:
+ return(fMustDraw ? CDRF_SKIPDEFAULT : CDRF_DODEFAULT);
+
+ case CDDS_POSTERASE:
+ return(fMustDraw ? CDRF_SKIPDEFAULT : CDRF_DODEFAULT);
+
+ case CDDS_POSTPAINT:
+ if(nmtb->nmcd.dwItemSpec == 0 && m_hdcDraw) {
+ ::BitBlt(nmtb->nmcd.hdc, 0, 0, m_rcItem.right - m_rcItem.left, m_rcItem.bottom - m_rcItem.top,
+ m_hdcDraw, 0, 0, SRCCOPY);
+ ::SelectObject(m_hdcDraw, m_hbmOld);
+ ::DeleteObject(m_hbmDraw);
+ ::SelectObject(m_hdcDraw, m_hOldFont);
+ ::DeleteDC(m_hdcDraw);
+ m_hdcDraw = 0;
+ if(m_hTheme)
+ CMimAPI::m_pfnCloseThemeData(m_hTheme);
+ return(CDRF_SKIPDEFAULT);
+ }
+ else
+ return(CDRF_DODEFAULT);
+
+ default:
+ return(CDRF_DODEFAULT);
+ }
+
+ return(0);
+ }
+ return(0);
+}
+
+/**
+ * Handle the TBN_DROPDOWN notification message sent by the
+ * toolbar control.
+ *
+ * @param nmtb NMTOOLBAR *: notification message structure
+ *
+ * @return LONG_PTR: must be a valid return value. See Win32 API, TBN_DROPDOWN
+ */
+LONG_PTR CMenuBar::Handle(const NMTOOLBAR *nmtb)
+{
+ if(nmtb->hdr.hwndFrom != m_hwndToolbar)
+ return(TBDDRET_NODEFAULT);
+
+ const int index = idToIndex(nmtb->iItem);
+ invoke(nmtb->iItem);
+
+ return(TBDDRET_DEFAULT);
+}
+
+/**
+ * Invoke the dropdown menu for the button with the given control id.
+ *
+ * @param id int: the control id of the toolbar button which has been activated
+ */
+void CMenuBar::invoke(const int id)
+{
+ const int index = idToIndex(id);
+
+ HMENU hMenu;
+
+ m_isContactMenu = m_isMainMenu = false;
+
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(m_pContainer->hwndActive, GWLP_USERDATA);
+
+ HANDLE hContact = dat ? dat->hContact : 0;
+
+ if(index == 3 && hContact != 0) {
+ hMenu = reinterpret_cast<HMENU>(::CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0));
+ m_isContactMenu = true;
+ } else if(index == 0) {
+ hMenu = reinterpret_cast<HMENU>(::CallService(MS_CLIST_MENUBUILDMAIN, 0, 0));
+ m_isMainMenu = true;
+ } else
+ hMenu = reinterpret_cast<HMENU>(m_TbButtons[index].dwData);
+
+ RECT rcButton;
+ POINT pt;
+ ::SendMessage(m_hwndToolbar, TB_GETITEMRECT, (WPARAM)index, (LPARAM)&rcButton);
+ pt.x = rcButton.left;
+ pt.y = rcButton.bottom;
+ ::ClientToScreen(m_hwndToolbar, &pt);
+
+ if(m_activeID)
+ cancel(0);
+
+ m_activeMenu = hMenu;
+ m_activeSubMenu = 0;
+ m_activeID = id;
+ updateState(hMenu);
+ obtainHook();
+ m_fTracking = true;
+ ::SendMessage(m_hwndToolbar, TB_SETSTATE, (WPARAM)id, TBSTATE_CHECKED | TBSTATE_ENABLED);
+ ::TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, m_pContainer->hwnd, 0);
+}
+
+void CMenuBar::cancel(const int id)
+{
+ releaseHook();
+ if(m_activeID)
+ ::SendMessage(m_hwndToolbar, TB_SETSTATE, (WPARAM)m_activeID, TBSTATE_ENABLED);
+ m_activeID = 0;
+ m_activeMenu = 0;
+ m_isContactMenu = m_isMainMenu = false;
+ ::EndMenu();
+}
+
+/**
+ * Cancel menu tracking completely
+ */
+void CMenuBar::Cancel(void)
+{
+ cancel(0);
+ m_fTracking = false;
+ autoShow(0);
+}
+
+void CMenuBar::updateState(const HMENU hMenu) const
+{
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(m_pContainer->hwndActive, GWLP_USERDATA);
+
+ if(dat) {
+ ::CheckMenuItem(hMenu, ID_VIEW_SHOWMENUBAR, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_NOMENUBAR ? MF_UNCHECKED : MF_CHECKED);
+ ::CheckMenuItem(hMenu, ID_VIEW_SHOWSTATUSBAR, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_NOSTATUSBAR ? MF_UNCHECKED : MF_CHECKED);
+ ::CheckMenuItem(hMenu, ID_VIEW_SHOWAVATAR, MF_BYCOMMAND | dat->showPic ? MF_CHECKED : MF_UNCHECKED);
+ ::CheckMenuItem(hMenu, ID_VIEW_SHOWTITLEBAR, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_NOTITLE ? MF_UNCHECKED : MF_CHECKED);
+
+ ::EnableMenuItem(hMenu, ID_VIEW_SHOWTITLEBAR, CSkin::m_skinEnabled && CSkin::m_frameSkins ? MF_GRAYED : MF_ENABLED);
+
+ ::CheckMenuItem(hMenu, ID_VIEW_TABSATBOTTOM, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_TABSBOTTOM ? MF_CHECKED : MF_UNCHECKED);
+ ::CheckMenuItem(hMenu, ID_VIEW_VERTICALMAXIMIZE, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_VERTICALMAX ? MF_CHECKED : MF_UNCHECKED);
+ ::CheckMenuItem(hMenu, ID_VIEW_SHOWTOOLBAR, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_HIDETOOLBAR ? MF_UNCHECKED : MF_CHECKED);
+ ::CheckMenuItem(hMenu, ID_VIEW_BOTTOMTOOLBAR, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_BOTTOMTOOLBAR ? MF_CHECKED : MF_UNCHECKED);
+
+ ::CheckMenuItem(hMenu, ID_VIEW_SHOWMULTISENDCONTACTLIST, MF_BYCOMMAND | (dat->sendMode & SMODE_MULTIPLE) ? MF_CHECKED : MF_UNCHECKED);
+ ::CheckMenuItem(hMenu, ID_VIEW_STAYONTOP, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_STICKY ? MF_CHECKED : MF_UNCHECKED);
+
+ ::EnableMenuItem(hMenu, 2, MF_BYPOSITION | (nen_options.bWindowCheck ? MF_GRAYED : MF_ENABLED));
+ ::CheckMenuItem(hMenu, ID_EVENTPOPUPS_DISABLEALLEVENTPOPUPS, MF_BYCOMMAND | m_pContainer->dwFlags & (CNT_DONTREPORT | CNT_DONTREPORTUNFOCUSED | CNT_DONTREPORTFOCUSED | CNT_ALWAYSREPORTINACTIVE) ? MF_UNCHECKED : MF_CHECKED);
+ ::CheckMenuItem(hMenu, ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISMINIMIZED, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_DONTREPORT ? MF_CHECKED : MF_UNCHECKED);
+ ::CheckMenuItem(hMenu, ID_EVENTPOPUPS_SHOWPOPUPSFORALLINACTIVESESSIONS, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_ALWAYSREPORTINACTIVE ? MF_CHECKED : MF_UNCHECKED);
+ ::CheckMenuItem(hMenu, ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISUNFOCUSED, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_DONTREPORTUNFOCUSED ? MF_CHECKED : MF_UNCHECKED);
+ ::CheckMenuItem(hMenu, ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISFOCUSED, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_DONTREPORTFOCUSED ? MF_CHECKED : MF_UNCHECKED);
+
+ ::CheckMenuItem(hMenu, ID_WINDOWFLASHING_USEDEFAULTVALUES, MF_BYCOMMAND | (m_pContainer->dwFlags & (CNT_NOFLASH | CNT_FLASHALWAYS)) ? MF_UNCHECKED : MF_CHECKED);
+ ::CheckMenuItem(hMenu, ID_WINDOWFLASHING_DISABLEFLASHING, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_NOFLASH ? MF_CHECKED : MF_UNCHECKED);
+ ::CheckMenuItem(hMenu, ID_WINDOWFLASHING_FLASHUNTILFOCUSED, MF_BYCOMMAND | m_pContainer->dwFlags & CNT_FLASHALWAYS ? MF_CHECKED : MF_UNCHECKED);
+ }
+}
+
+/*
+ * this updates the container menu bar and other window elements depending on the current child
+ * session (IM, chat etc.). It fully supports IEView and will disable/enable the message log menus
+ * depending on the configuration of IEView (e.g. when template mode is on, the message log settin
+ * menus have no functionality, thus can be disabled to improve ui feedback quality).
+ */
+
+void CMenuBar::configureMenu() const
+{
+ TWindowData *dat = (TWindowData *)::GetWindowLongPtr(m_pContainer->hwndActive, GWLP_USERDATA);
+
+ BOOL fDisable = FALSE;
+
+ if(dat) {
+ bool fChat = (dat->bType == SESSIONTYPE_CHAT);
+
+ ::SendMessage(m_hwndToolbar, TB_SETSTATE, 103, fChat ? TBSTATE_HIDDEN : TBSTATE_ENABLED);
+ ::SendMessage(m_hwndToolbar, TB_SETSTATE, 104, fChat ? TBSTATE_ENABLED : TBSTATE_HIDDEN);
+ ::SendMessage(m_hwndToolbar, TB_SETSTATE, 105, fChat ? TBSTATE_HIDDEN : TBSTATE_ENABLED);
+
+ if (dat->bType == SESSIONTYPE_IM)
+ ::EnableWindow(GetDlgItem(dat->hwnd, IDC_TIME), fDisable ? FALSE : TRUE);
+ }
+}
+
+/**
+ * Automatically shows or hides the menu bar. Depends on the current state,
+ * used when the ALT key is hit in the message window.
+ */
+void CMenuBar::autoShow(const int showcmd)
+{
+ if(m_mustAutoHide && !(m_pContainer->dwFlags & CNT_NOMENUBAR)) {
+ m_pContainer->dwFlags |= CNT_NOMENUBAR;
+ m_mustAutoHide = false;
+ ::SendMessage(m_pContainer->hwnd, WM_SIZE, 0, 1);
+ releaseHook();
+ }
+
+ if(showcmd == 0) {
+ ::SetFocus(m_pContainer->hwndActive);
+ return;
+ }
+
+ if(m_pContainer->dwFlags & CNT_NOMENUBAR) {
+ m_mustAutoHide = true;
+ m_pContainer->dwFlags &= ~CNT_NOMENUBAR;
+ ::SendMessage(m_pContainer->hwnd, WM_SIZE, 0, 1);
+ }
+ else // do nothing, already visible
+ m_mustAutoHide = false;
+ //obtainHook();
+ ::SetFocus(m_hwndToolbar);
+ //::SendMessage(m_hwndToolbar, TB_SETHOTITEM, 0, HICF_ACCELERATOR);
+}
+
+/**
+ * Message hook function, installed by the menu handler to support
+ * hot-tracking and keyboard navigation for the menu bar while a modal
+ * popup menu is active.
+ *
+ * Hook is only active while a (modal) popup menu is processed.
+ *
+ * @params See Win32, message hooks
+ *
+ * @return
+ */
+LRESULT CALLBACK CMenuBar::MessageHook(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ if (nCode < 0)
+ return(::CallNextHookEx(m_hHook, nCode, wParam, lParam));
+
+ MSG *pMsg = reinterpret_cast<MSG *>(lParam);
+ bool fCancel = false;
+
+ if(nCode == MSGF_MENU) {
+ switch(pMsg->message) {
+ case WM_KEYDOWN:
+ switch(pMsg->wParam) {
+ case VK_ESCAPE: {
+ fCancel = true;
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+
+ case WM_SYSKEYUP:
+ if(pMsg->wParam == VK_MENU)
+ fCancel = true;
+ break;
+
+ case WM_LBUTTONDOWN: {
+ POINT pt;
+
+ ::GetCursorPos(&pt);
+ if(::MenuItemFromPoint(0, m_Owner->m_activeMenu, pt) >= 0) // inside menu
+ break;
+ if(m_Owner->m_activeSubMenu && ::MenuItemFromPoint(0, m_Owner->m_activeSubMenu, pt) >= 0)
+ break;
+ else { // anywhere else, cancel the menu
+ ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
+ m_Owner->Cancel();
+ return(0);
+ }
+ }
+ /*
+ * allow hottracking by the toolbar control
+ */
+ case WM_MOUSEMOVE: {
+ POINT pt;
+
+ ::GetCursorPos(&pt);
+ ::ScreenToClient(m_Owner->m_hwndToolbar, &pt);
+ LPARAM newPos = MAKELONG(pt.x, pt.y);
+ ::SendMessage(m_Owner->m_hwndToolbar, pMsg->message, pMsg->wParam, newPos);
+ break;
+ }
+ default:
+ break;
+ }
+ /*
+ * some key event requested to cancel the menu
+ */
+ if(fCancel) {
+ int iIndex = m_Owner->idToIndex(m_Owner->m_activeID);
+ if(iIndex != -1)
+ ::SendMessage(m_Owner->m_hwndToolbar, TB_SETHOTITEM, (WPARAM)iIndex, 0);
+ ::SetFocus(m_Owner->m_hwndToolbar);
+ ::SendMessage(m_Owner->m_hwndToolbar, TB_SETSTATE, (WPARAM)m_Owner->m_activeID, TBSTATE_ENABLED | TBSTATE_PRESSED);
+ m_Owner->cancel(0);
+ m_Owner->m_fTracking = false;
+ }
+ }
+ return(::CallNextHookEx(m_hHook, nCode, wParam, lParam));
+}
+
+/*
+ * window procedure for the status bar class.
+ */
+
+static int tooltip_active = FALSE;
+static POINT ptMouse = {0};
+RECT rcLastStatusBarClick; // remembers click (down event) point for status bar clicks
+
+LONG_PTR CALLBACK StatusBarSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ TContainerData *pContainer = (TContainerData *)GetWindowLongPtr(GetParent(hWnd), GWLP_USERDATA);
+
+ if (OldStatusBarproc == 0) {
+ WNDCLASSEX wc = {0};
+ wc.cbSize = sizeof(wc);
+ GetClassInfoEx(g_hInst, STATUSCLASSNAME, &wc);
+ OldStatusBarproc = wc.lpfnWndProc;
+ }
+ switch (msg) {
+ case WM_CREATE: {
+ CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
+ LRESULT ret;
+ HWND hwndParent = GetParent(hWnd);
+ /*
+ * dirty trick to get rid of that annoying sizing gripper
+ */
+ SetWindowLongPtr(hwndParent, GWL_STYLE, GetWindowLongPtr(hwndParent, GWL_STYLE) & ~WS_THICKFRAME);
+ SetWindowLongPtr(hwndParent, GWL_EXSTYLE, GetWindowLongPtr(hwndParent, GWL_EXSTYLE) & ~WS_EX_APPWINDOW);
+ cs->style &= ~SBARS_SIZEGRIP;
+ ret = CallWindowProc(OldStatusBarproc, hWnd, msg, wParam, lParam);
+ SetWindowLongPtr(hwndParent, GWL_STYLE, GetWindowLongPtr(hwndParent, GWL_STYLE) | WS_THICKFRAME);
+ SetWindowLongPtr(hwndParent, GWL_EXSTYLE, GetWindowLongPtr(hwndParent, GWL_EXSTYLE) | WS_EX_APPWINDOW);
+ return ret;
+ }
+
+ case WM_NCHITTEST: {
+ RECT r;
+ POINT pt;
+ LRESULT lr = SendMessage(GetParent(hWnd), WM_NCHITTEST, wParam, lParam);
+ int clip = CSkin::m_bClipBorder;
+
+ GetWindowRect(hWnd, &r);
+ GetCursorPos(&pt);
+ if (pt.y <= r.bottom && pt.y >= r.bottom - clip - 3) {
+ if (pt.x > r.right - clip - 4)
+ return HTBOTTOMRIGHT;
+ }
+ if (lr == HTLEFT || lr == HTRIGHT || lr == HTBOTTOM || lr == HTTOP || lr == HTTOPLEFT || lr == HTTOPRIGHT
+ || lr == HTBOTTOMLEFT || lr == HTBOTTOMRIGHT)
+ return HTTRANSPARENT;
+ break;
+ }
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_PAINT: {
+ PAINTSTRUCT ps;
+ TCHAR szText[1024];
+ int i;
+ RECT itemRect;
+ HICON hIcon;
+ LONG height, width;
+ HDC hdc = BeginPaint(hWnd, &ps);
+ HFONT hFontOld = 0;
+ UINT nParts = SendMessage(hWnd, SB_GETPARTS, 0, 0);
+ LRESULT result;
+ RECT rcClient;
+ HDC hdcMem;
+ HBITMAP hbm, hbmOld;
+ HANDLE hbp = 0;
+ CSkinItem * item = &SkinItems[ID_EXTBKSTATUSBARPANEL];
+ COLORREF clr = 0;
+
+ BOOL fAero = M->isAero();
+ HANDLE hTheme = fAero ? CMimAPI::m_pfnOpenThemeData(hWnd, L"ButtonStyle") : 0;
+ TWindowData* dat = 0;
+
+ if(pContainer)
+ dat = (TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+
+ GetClientRect(hWnd, &rcClient);
+
+ if(CMimAPI::m_haveBufferedPaint)
+ hbp = CMimAPI::m_pfnBeginBufferedPaint(hdc, &rcClient, BPBF_TOPDOWNDIB, NULL, &hdcMem);
+ else {
+ hdcMem = CreateCompatibleDC(hdc);
+ hbm = CSkin::CreateAeroCompatibleBitmap(rcClient, hdc);
+ hbmOld = (HBITMAP)SelectObject(hdcMem, hbm);
+ }
+
+ SetBkMode(hdcMem, TRANSPARENT);
+
+ clr = CSkin::m_skinEnabled ? CSkin::m_DefaultFontColor : (PluginConfig.m_fillColor ? PluginConfig.m_genericTxtColor : GetSysColor(COLOR_BTNTEXT));
+
+ hFontOld = (HFONT)SelectObject(hdcMem, GetStockObject(DEFAULT_GUI_FONT));
+
+ if (pContainer && CSkin::m_skinEnabled)
+ CSkin::SkinDrawBG(hWnd, GetParent(hWnd), pContainer, &rcClient, hdcMem);
+ else if(fAero) {
+ FillRect(hdcMem, &rcClient, CSkin::m_BrushBack);
+ CSkin::ApplyAeroEffect(hdcMem, &rcClient, CSkin::AERO_EFFECT_AREA_STATUSBAR);
+ } else {
+ CSkin::FillBack(hdcMem, &rcClient);
+ RECT rcFrame = rcClient;
+ if(PluginConfig.m_fillColor == 0) {
+ InflateRect(&rcFrame, -2, -1);
+ DrawEdge(hdcMem, &rcClient, BDR_RAISEDINNER | BDR_SUNKENOUTER, BF_RECT);
+ }
+ else {
+ CSkin::m_switchBarItem->setAlphaFormat(AC_SRC_ALPHA, 180);
+ CSkin::m_switchBarItem->Render(hdcMem, &rcFrame, true);
+ }
+ }
+ for (i = 0; i < (int)nParts; i++) {
+ SendMessage(hWnd, SB_GETRECT, (WPARAM)i, (LPARAM)&itemRect);
+ if (!item->IGNORED && !fAero && pContainer && CSkin::m_skinEnabled)
+ CSkin::DrawItem(hdcMem, &itemRect, item);
+
+ if (i == 0)
+ itemRect.left += 2;
+
+ /*
+ * draw visual message length indicator in the leftmost status bar field
+ */
+
+ if (PluginConfig.m_visualMessageSizeIndicator && i == 0) {
+
+ if(dat && dat->bType == SESSIONTYPE_IM) {
+ HBRUSH br = CreateSolidBrush(RGB(0, 255, 0));
+ HBRUSH brOld = (HBRUSH)SelectObject(hdcMem, br);
+ RECT rc = itemRect;
+
+ rc.top = rc.bottom - 3;
+ rc.left = 0;
+
+ if (!PluginConfig.m_autoSplit) {
+ float fMax = (float)dat->nMax;
+ float uPercent = (float)dat->textLen / ((fMax / (float)100.0) ? (fMax / (float)100.0) : (float)75.0);
+ float fx = ((float)rc.right / (float)100.0) * uPercent;
+
+ rc.right = (LONG)fx;
+ FillRect(hdcMem, &rc, br);
+ } else {
+ float baselen = (dat->textLen <= dat->nMax) ? (float)dat->textLen : (float)dat->nMax;
+ float fMax = (float)dat->nMax;
+ float uPercent = baselen / ((fMax / (float)100.0) ? (fMax / (float)100.0) : (float)75.0);
+ float fx;
+ LONG width = rc.right - rc.left;
+ if (dat->textLen >= dat->nMax)
+ rc.right = rc.right / 3;
+ fx = ((float)rc.right / (float)100.0) * uPercent;
+ rc.right = (LONG)fx;
+ FillRect(hdcMem, &rc, br);
+ if (dat->textLen >= dat->nMax) {
+ SelectObject(hdcMem, brOld);
+ DeleteObject(br);
+ br = CreateSolidBrush(RGB(255, 0, 0));
+ brOld = (HBRUSH)SelectObject(hdcMem, br);
+ rc.left = width / 3;
+ rc.right = width;
+ uPercent = (float)dat->textLen / (float)200.0;
+ fx = ((float)(rc.right - rc.left) / (float)100.0) * uPercent;
+ rc.right = rc.left + (LONG)fx;
+ FillRect(hdcMem, &rc, br);
+ }
+ }
+ DeleteObject(br);
+ }
+ }
+
+ height = itemRect.bottom - itemRect.top;
+ width = itemRect.right - itemRect.left;
+ hIcon = (HICON)SendMessage(hWnd, SB_GETICON, i, 0);
+ szText[0] = 0;
+ result = SendMessage(hWnd, SB_GETTEXT, i, (LPARAM)szText);
+ if (i == 2 && pContainer) {
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+
+ if (dat)
+ DrawStatusIcons(dat, hdcMem, itemRect, 2);
+ }
+ else {
+ if (hIcon) {
+ if (LOWORD(result) > 1) { // we have a text
+ DrawIconEx(hdcMem, itemRect.left + 3, (height / 2 - 8) + itemRect.top, hIcon, 16, 16, 0, 0, DI_NORMAL);
+ if(dat) {
+ if(dat->showTyping == 2)
+ DrawIconEx(hdcMem, itemRect.left + 3, (height / 2 - 8) + itemRect.top, PluginConfig.g_iconOverlayEnabled, 16, 16, 0, 0, DI_NORMAL);
+ }
+ itemRect.left += 20;
+ CSkin::RenderText(hdcMem, hTheme, szText, &itemRect, DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX,
+ CSkin::m_glowSize, clr);
+ }
+ else
+ DrawIconEx(hdcMem, itemRect.left + 3, (height / 2 - 8) + itemRect.top, hIcon, 16, 16, 0, 0, DI_NORMAL);
+ }
+ else {
+ itemRect.left += 2;
+ itemRect.right -= 2;
+ CSkin::RenderText(hdcMem, hTheme, szText, &itemRect, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX,
+ CSkin::m_glowSize, clr);
+ }
+ }
+ }
+ if(hbp)
+ CSkin::FinalizeBufferedPaint(hbp, &rcClient);
+ else {
+ BitBlt(hdc, 0, 0, rcClient.right, rcClient.bottom, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hbmOld);
+ DeleteObject(hbm);
+ SelectObject(hdcMem, hFontOld);
+ DeleteDC(hdcMem);
+ }
+
+ if(hTheme)
+ CMimAPI::m_pfnCloseThemeData(hTheme);
+
+ EndPaint(hWnd, &ps);
+ return 0;
+ }
+
+ /*
+ * tell status bar to update the part layout (re-calculate part widths)
+ * needed when an icon is added to or removed from the icon area
+ */
+ case WM_USER + 101: {
+ struct TWindowData *dat = (struct TWindowData *)lParam;
+ RECT rcs;
+ int statwidths[5];
+ struct TStatusBarIconNode *current = status_icon_list;
+ int list_icons = 0;
+ char buff[100];
+ DWORD flags;
+
+ while (current && dat) {
+ flags=current->sid.flags;
+ if(current->sid.flags&MBF_OWNERSTATE){
+ struct TStatusBarIconNode *currentSIN = dat->pSINod;
+
+ while (currentSIN) {
+ if (strcmp(currentSIN->sid.szModule, current->sid.szModule) == 0 && currentSIN->sid.dwId == current->sid.dwId) {
+ flags=currentSIN->sid.flags;
+ break;
+ }
+ currentSIN = currentSIN->next;
+ }
+ }
+ else {
+ sprintf(buff, "SRMMStatusIconFlags%d", (int)current->sid.dwId);
+ flags = M->GetByte(dat->hContact, current->sid.szModule, buff, current->sid.flags);
+ }
+ if (!(flags & MBF_HIDDEN))
+ list_icons++;
+ current = current->next;
+ }
+
+ SendMessage(hWnd, WM_SIZE, 0, 0);
+ GetWindowRect(hWnd, &rcs);
+
+ statwidths[0] = (rcs.right - rcs.left) - (2 * SB_CHAR_WIDTH + 20) - (52 + ((list_icons) * (PluginConfig.m_smcxicon + 2)));
+ statwidths[1] = (rcs.right - rcs.left) - (62 + ((list_icons) * (PluginConfig.m_smcxicon + 2)));
+ statwidths[2] = -1;
+ SendMessage(hWnd, SB_SETPARTS, 3, (LPARAM) statwidths);
+ return 0;
+ }
+
+ case WM_SETCURSOR: {
+ POINT pt;
+
+ GetCursorPos(&pt);
+ SendMessage(GetParent(hWnd), msg, wParam, lParam);
+ if (pt.x == ptMouse.x && pt.y == ptMouse.y) {
+ return 1;
+ }
+ ptMouse = pt;
+ if (tooltip_active) {
+ KillTimer(hWnd, TIMERID_HOVER);
+ CallService("mToolTip/HideTip", 0, 0);
+ tooltip_active = FALSE;
+ }
+ KillTimer(hWnd, TIMERID_HOVER);
+ SetTimer(hWnd, TIMERID_HOVER, 450, 0);
+ break;
+ }
+
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN: {
+ POINT pt;
+
+ KillTimer(hWnd, TIMERID_HOVER);
+ CallService("mToolTip/HideTip", 0, 0);
+ tooltip_active = FALSE;
+ GetCursorPos(&pt);
+ rcLastStatusBarClick.left = pt.x - 2;
+ rcLastStatusBarClick.right = pt.x + 2;
+ rcLastStatusBarClick.top = pt.y - 2;
+ rcLastStatusBarClick.bottom = pt.y + 2;
+
+ if (pContainer->dwFlags & CNT_NOTITLE) {
+ POINT pt1 = pt;
+ RECT rcIconpart;
+
+ ScreenToClient(hWnd, &pt1);
+ SendMessage(hWnd, SB_GETRECT, 2, (LPARAM)&rcIconpart);
+ if(!PtInRect(&rcIconpart, pt1))
+ return SendMessage(pContainer->hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ }
+ break;
+ }
+
+ case WM_TIMER:
+ if (wParam == TIMERID_HOVER) {
+ POINT pt;
+ char *szTTService = "mToolTip/ShowTipW";
+ CLCINFOTIP ti = {0};
+ ti.cbSize = sizeof(ti);
+
+ KillTimer(hWnd, TIMERID_HOVER);
+ GetCursorPos(&pt);
+ if (pt.x == ptMouse.x && pt.y == ptMouse.y) {
+ RECT rc;
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+//mad
+ SIZE size;
+ TCHAR szStatusBarText[512];
+//mad_
+ ti.ptCursor = pt;
+ ScreenToClient(hWnd, &pt);
+ SendMessage(hWnd, SB_GETRECT, 2, (LPARAM)&rc);
+ if (dat && PtInRect(&rc, pt)) {
+ int gap = 2;
+ TStatusBarIconNode *current = status_icon_list;
+ TStatusBarIconNode *clicked = NULL;
+ TStatusBarIconNode *currentSIN = NULL;
+
+ unsigned int iconNum = (pt.x - rc.left) / (PluginConfig.m_smcxicon + gap);
+ unsigned int list_icons = 0;
+ char buff[100];
+ DWORD flags;
+
+ while (current) {
+ if(current->sid.flags&MBF_OWNERSTATE&&dat->pSINod){
+ TStatusBarIconNode *currentSIN = dat->pSINod;
+ flags=current->sid.flags;
+ while (currentSIN) {
+ if (strcmp(currentSIN->sid.szModule, current->sid.szModule) == 0 && currentSIN->sid.dwId == current->sid.dwId) {
+ flags=currentSIN->sid.flags;
+ break;
+ }
+ currentSIN = currentSIN->next;
+ }
+ }
+ else {
+ sprintf(buff, "SRMMStatusIconFlags%d", (int)current->sid.dwId);
+ flags = M->GetByte(dat->hContact, current->sid.szModule, buff, current->sid.flags);
+ }
+ if (!(flags & MBF_HIDDEN)) {
+ if (list_icons++ == iconNum)
+ clicked = current;
+ }
+ current = current->next;
+ }
+
+ if(clicked&&clicked->sid.flags&MBF_OWNERSTATE) {
+ currentSIN=dat->pSINod;
+ while (currentSIN) {
+ if (strcmp(currentSIN->sid.szModule, clicked->sid.szModule) == 0 && currentSIN->sid.dwId == clicked->sid.dwId) {
+ clicked=currentSIN;
+ break;
+ }
+ currentSIN = currentSIN->next;
+ }
+ }
+
+ if ((int)iconNum == list_icons && pContainer) {
+ TCHAR wBuf[512];
+
+ mir_sntprintf(wBuf, safe_sizeof(wBuf), CTranslator::get(CTranslator::CNT_SBAR_SOUNDS),
+ pContainer->dwFlags & CNT_NOSOUND ? CTranslator::get(CTranslator::GEN_DISABLED) : CTranslator::get(CTranslator::GEN_ENABLED));
+ CallService(szTTService, (WPARAM)wBuf, (LPARAM)&ti);
+ tooltip_active = TRUE;
+ }
+ else if ((int)iconNum == list_icons + 1 && dat && dat->bType == SESSIONTYPE_IM) {
+ int mtnStatus = (int)M->GetByte(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M->GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW));
+ TCHAR wBuf[512];
+
+ mir_sntprintf(wBuf, safe_sizeof(wBuf), CTranslator::get(CTranslator::CNT_SBAR_MTN),
+ mtnStatus ? CTranslator::get(CTranslator::GEN_ENABLED) : CTranslator::get(CTranslator::GEN_DISABLED));
+ CallService(szTTService, (WPARAM)wBuf, (LPARAM)&ti);
+ tooltip_active = TRUE;
+ }
+ else if((int)iconNum == list_icons + 2) {
+ TCHAR wBuf[512];
+
+ mir_sntprintf(wBuf, safe_sizeof(wBuf), _T("%s"), CTranslator::get(CTranslator::CNT_SBAR_SLIST));
+
+ CallService(szTTService, (WPARAM)wBuf, (LPARAM)&ti);
+ tooltip_active = TRUE;
+ }
+ else {
+ if (clicked) {
+ CallService("mToolTip/ShowTip", (WPARAM)clicked->sid.szTooltip, (LPARAM)&ti);
+ tooltip_active = TRUE;
+ }
+ }
+ }
+ SendMessage(hWnd, SB_GETRECT, 1, (LPARAM)&rc);
+ if (dat && PtInRect(&rc, pt)) {
+ int iLength = 0;
+ GETTEXTLENGTHEX gtxl = {0};
+ int iQueued = M->GetDword(dat->hContact, "SendLater", "count", 0);
+ gtxl.codepage = CP_UTF8;
+ gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMBYTES;
+ iLength = SendDlgItemMessage(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE, EM_GETTEXTLENGTHEX, (WPARAM) & gtxl, 0);
+ tooltip_active = TRUE;
+
+ TCHAR wBuf[512];
+ const TCHAR *szFormat = CTranslator::get(CTranslator::GEN_SBAR_TIP_MSGLENGTH);
+
+ mir_sntprintf(wBuf, safe_sizeof(wBuf), szFormat, dat->iOpenJobs, iLength, dat->nMax ? dat->nMax : 20000, iQueued);
+ CallService(szTTService, (WPARAM)wBuf, (LPARAM)&ti);
+ }
+ //MAD
+ if(SendMessage(dat->pContainer->hwndStatus, SB_GETTEXT, 0, (LPARAM)szStatusBarText)) {
+ HDC hdc;
+ int iLen=SendMessage(dat->pContainer->hwndStatus,SB_GETTEXTLENGTH,0,0);
+ SendMessage(hWnd, SB_GETRECT, 0, (LPARAM)&rc);
+ GetTextExtentPoint32( hdc=GetDC( dat->pContainer->hwndStatus), szStatusBarText, iLen, &size );
+ ReleaseDC (dat->pContainer->hwndStatus,hdc);
+
+ if(dat && PtInRect(&rc,pt)&&((rc.right-rc.left)<size.cx)) {
+ DBVARIANT dbv={0};
+
+ if(dat->bType == SESSIONTYPE_CHAT)
+ M->GetTString(dat->hContact,dat->szProto,"Topic",&dbv);
+
+ tooltip_active = TRUE;
+ CallService(szTTService, (WPARAM)dbv.ptszVal, (LPARAM)&ti);
+ if(dbv.pszVal)
+ DBFreeVariant(&dbv);
+ }
+ }
+ // MAD_
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ KillTimer(hWnd, TIMERID_HOVER);
+ }
+ return CallWindowProc(OldStatusBarproc, hWnd, msg, wParam, lParam);
+}
+
diff --git a/plugins/TabSRMM/src/eventpopups.cpp b/plugins/TabSRMM/src/eventpopups.cpp
new file mode 100644
index 0000000000..ea1df5a209
--- /dev/null
+++ b/plugins/TabSRMM/src/eventpopups.cpp
@@ -0,0 +1,997 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: eventpopups.cpp 13750 2011-08-03 20:10:43Z george.hazan $
+ *
+ * This implements the event notification module for tabSRMM. The code
+ * is largely based on the NewEventNotify plugin for Miranda IM. See
+ * notices below.
+ *
+ * Name: NewEventNotify - Plugin for Miranda ICQ
+ * Description: Notifies you when you receive a message
+ * Author: icebreaker, <icebreaker@newmail.net>
+ * Date: 18.07.02 13:59 / Update: 16.09.02 17:45
+ * Copyright: (C) 2002 Starzinger Michael
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+extern INT_PTR CALLBACK DlgProcSetupStatusModes(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+extern HIMAGELIST CreateStateImageList();
+extern HANDLE g_hEvent;
+
+typedef std::vector<PLUGIN_DATAT *>::iterator PopupListIterator;
+static std::vector<PLUGIN_DATAT *> PopupList;
+
+BOOL bWmNotify = TRUE;
+
+static const PLUGIN_DATAT* PU_GetByContact(const HANDLE hContact)
+{
+ if(PopupList.size()) {
+ PopupListIterator it = PopupList.begin();
+ while(it != PopupList.end()) {
+ if((*it)->hContact == hContact)
+ return(*it);
+ it++;
+ }
+ }
+ return(0);
+}
+
+/**
+ * remove stale popup data which has been marked for removal by the popup
+ * window procedure.
+ *
+ */
+static void PU_CleanUp()
+{
+ if(PopupList.size()) {
+ PopupListIterator it = PopupList.begin();
+ while(it != PopupList.end()) {
+ if(PopupList.size() == 0)
+ break;
+ if((*it)->hContact == 0) {
+ //_DebugTraceW(_T("found stale popup %s"), (*it)->eventData->szText);
+ if((*it)->eventData)
+ free((*it)->eventData);
+ free(*it);
+ it = PopupList.erase(it);
+ continue;
+ }
+ it++;
+ }
+ }
+}
+
+static void CheckForRemoveMask()
+{
+ if (!M->GetByte(MODULE, "firsttime", 0) && (nen_options.maskActL & MASK_REMOVE || nen_options.maskActR & MASK_REMOVE || nen_options.maskActTE & MASK_REMOVE)) {
+ MessageBoxA(0, Translate("One of your popup actions is set to DISMISS EVENT.\nNote that this options may have unwanted side effects as it REMOVES the event from the unread queue.\nThis may lead to events not showing up as \"new\". If you don't want this behaviour, please review the Event Notifications settings page."), "tabSRMM Warning Message", MB_OK | MB_ICONSTOP);
+ M->WriteByte(MODULE, "firsttime", 1);
+ }
+}
+
+
+int TSAPI NEN_ReadOptions(NEN_OPTIONS *options)
+{
+ options->bPreview = (BOOL)M->GetByte(MODULE, OPT_PREVIEW, TRUE);
+ options->bDefaultColorMsg = (BOOL)M->GetByte(MODULE, OPT_COLDEFAULT_MESSAGE, TRUE);
+ options->bDefaultColorOthers = (BOOL)M->GetByte(MODULE, OPT_COLDEFAULT_OTHERS, TRUE);
+ options->bDefaultColorErr = (BOOL)M->GetByte(MODULE, OPT_COLDEFAULT_ERR, TRUE);
+ options->colBackMsg = (COLORREF)M->GetDword(MODULE, OPT_COLBACK_MESSAGE, DEFAULT_COLBACK);
+ options->colTextMsg = (COLORREF)M->GetDword(MODULE, OPT_COLTEXT_MESSAGE, DEFAULT_COLTEXT);
+ options->colBackOthers = (COLORREF)M->GetDword(MODULE, OPT_COLBACK_OTHERS, DEFAULT_COLBACK);
+ options->colTextOthers = (COLORREF)M->GetDword(MODULE, OPT_COLTEXT_OTHERS, DEFAULT_COLTEXT);
+ options->colBackErr = (COLORREF)M->GetDword(MODULE, OPT_COLBACK_ERR, DEFAULT_COLBACK);
+ options->colTextErr = (COLORREF)M->GetDword(MODULE, OPT_COLTEXT_ERR, DEFAULT_COLTEXT);
+ options->maskActL = (UINT)M->GetByte(MODULE, OPT_MASKACTL, DEFAULT_MASKACTL);
+ options->maskActR = (UINT)M->GetByte(MODULE, OPT_MASKACTR, DEFAULT_MASKACTR);
+ options->maskActTE = (UINT)M->GetByte(MODULE, OPT_MASKACTTE, DEFAULT_MASKACTR) & (MASK_OPEN | MASK_DISMISS);
+ options->bMergePopup = (BOOL)M->GetByte(MODULE, OPT_MERGEPOPUP, 0);
+ options->iDelayMsg = (int)M->GetDword(MODULE, OPT_DELAY_MESSAGE, (DWORD)DEFAULT_DELAY);
+ options->iDelayOthers = (int)M->GetDword(MODULE, OPT_DELAY_OTHERS, (DWORD)DEFAULT_DELAY);
+ options->iDelayErr = (int)M->GetDword(MODULE, OPT_DELAY_ERR, (DWORD)DEFAULT_DELAY);
+ options->iDelayDefault = (int)DBGetContactSettingRangedWord(NULL, "PopUp", "Seconds", SETTING_LIFETIME_DEFAULT, SETTING_LIFETIME_MIN, SETTING_LIFETIME_MAX);
+ options->bShowHeaders = (BYTE)M->GetByte(MODULE, OPT_SHOW_HEADERS, FALSE);
+ options->bNoRSS = (BOOL)M->GetByte(MODULE, OPT_NORSS, FALSE);
+ options->iDisable = (BYTE)M->GetByte(MODULE, OPT_DISABLE, 0);
+ options->iMUCDisable = (BYTE)M->GetByte(MODULE, OPT_MUCDISABLE, 0);
+ options->dwStatusMask = (DWORD)M->GetDword(MODULE, "statusmask", (DWORD) - 1);
+ options->bTraySupport = (BOOL)M->GetByte(MODULE, "traysupport", 0);
+ options->bWindowCheck = (BOOL)M->GetByte(MODULE, OPT_WINDOWCHECK, 0);
+ options->bNoRSS = (BOOL)M->GetByte(MODULE, OPT_NORSS, 0);
+ options->iLimitPreview = (int)M->GetDword(MODULE, OPT_LIMITPREVIEW, 0);
+ options->wMaxFavorites = 15;
+ options->wMaxRecent = 15;
+ options->dwRemoveMask = M->GetDword(MODULE, OPT_REMOVEMASK, 0);
+ options->bDisableNonMessage = M->GetByte(MODULE, "disablenonmessage", 0);
+ CheckForRemoveMask();
+ return 0;
+}
+
+int TSAPI NEN_WriteOptions(NEN_OPTIONS *options)
+{
+ M->WriteByte(MODULE, OPT_PREVIEW, (BYTE)options->bPreview);
+ M->WriteByte(MODULE, OPT_COLDEFAULT_MESSAGE, (BYTE)options->bDefaultColorMsg);
+ M->WriteByte(MODULE, OPT_COLDEFAULT_OTHERS, (BYTE)options->bDefaultColorOthers);
+ M->WriteByte(MODULE, OPT_COLDEFAULT_ERR, (BYTE)options->bDefaultColorErr);
+ M->WriteDword(MODULE, OPT_COLBACK_MESSAGE, (DWORD)options->colBackMsg);
+ M->WriteDword(MODULE, OPT_COLTEXT_MESSAGE, (DWORD)options->colTextMsg);
+ M->WriteDword(MODULE, OPT_COLBACK_OTHERS, (DWORD)options->colBackOthers);
+ M->WriteDword(MODULE, OPT_COLTEXT_OTHERS, (DWORD)options->colTextOthers);
+ M->WriteDword(MODULE, OPT_COLBACK_ERR, (DWORD)options->colBackErr);
+ M->WriteDword(MODULE, OPT_COLTEXT_ERR, (DWORD)options->colTextErr);
+ M->WriteByte(MODULE, OPT_MASKACTL, (BYTE)options->maskActL);
+ M->WriteByte(MODULE, OPT_MASKACTR, (BYTE)options->maskActR);
+ M->WriteByte(MODULE, OPT_MASKACTTE, (BYTE)options->maskActTE);
+ M->WriteByte(MODULE, OPT_MERGEPOPUP, (BYTE)options->bMergePopup);
+ M->WriteDword(MODULE, OPT_DELAY_MESSAGE, (DWORD)options->iDelayMsg);
+ M->WriteDword(MODULE, OPT_DELAY_OTHERS, (DWORD)options->iDelayOthers);
+ M->WriteDword(MODULE, OPT_DELAY_ERR, (DWORD)options->iDelayErr);
+ M->WriteByte(MODULE, OPT_SHOW_HEADERS, (BYTE)options->bShowHeaders);
+ M->WriteByte(MODULE, OPT_DISABLE, (BYTE)options->iDisable);
+ M->WriteByte(MODULE, OPT_MUCDISABLE, (BYTE)options->iMUCDisable);
+ M->WriteByte(MODULE, "traysupport", (BYTE)options->bTraySupport);
+ M->WriteByte(MODULE, OPT_WINDOWCHECK, (BYTE)options->bWindowCheck);
+ M->WriteByte(MODULE, OPT_NORSS, (BYTE)options->bNoRSS);
+ M->WriteDword(MODULE, OPT_LIMITPREVIEW, options->iLimitPreview);
+ M->WriteDword(MODULE, OPT_REMOVEMASK, options->dwRemoveMask);
+ M->WriteByte(MODULE, "disablenonmessage", options->bDisableNonMessage);
+ return 0;
+}
+
+INT_PTR CALLBACK DlgProcPopupOpts(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ NEN_OPTIONS *options = &nen_options;
+
+ switch (msg) {
+ case WM_INITDIALOG: {
+ TVINSERTSTRUCT tvi = {0};
+ int i = 0;
+ SetWindowLongPtr(GetDlgItem(hWnd, IDC_EVENTOPTIONS), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hWnd, IDC_EVENTOPTIONS), GWL_STYLE) | (TVS_NOHSCROLL | TVS_CHECKBOXES));
+ TranslateDialogDefault(hWnd);
+ HIMAGELIST himl = (HIMAGELIST)SendDlgItemMessage(hWnd, IDC_EVENTOPTIONS, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)CreateStateImageList());
+ ImageList_Destroy(himl);
+
+ if(!PluginConfig.g_PopupAvail) {
+ HWND hwndChild = FindWindowEx(hWnd, 0, 0, 0);
+ while(hwndChild) {
+ ShowWindow(hwndChild, SW_HIDE);
+ hwndChild = FindWindowEx(hWnd, hwndChild, 0, 0);
+ }
+ Utils::showDlgControl(hWnd, IDC_NOPOPUPAVAIL, SW_SHOW);
+ }
+ else
+ Utils::showDlgControl(hWnd, IDC_NOPOPUPAVAIL, SW_HIDE);
+ /*
+ * fill the tree view
+ */
+
+ TOptionListGroup *lGroups = CTranslator::getGroupTree(CTranslator::TREE_NEN);
+
+ while (lGroups[i].szName != NULL) {
+ tvi.hParent = 0;
+ tvi.hInsertAfter = TVI_LAST;
+ tvi.item.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.item.pszText = lGroups[i].szName;
+ tvi.item.stateMask = TVIS_STATEIMAGEMASK | TVIS_EXPANDED | TVIS_BOLD;
+ tvi.item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_EXPANDED | TVIS_BOLD;
+ lGroups[i++].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hWnd, IDC_EVENTOPTIONS), &tvi);
+ }
+ i = 0;
+
+ TOptionListItem *defaultItems = CTranslator::getTree(CTranslator::TREE_NEN);
+
+ while (defaultItems[i].szName != 0) {
+ tvi.hParent = (HTREEITEM)lGroups[defaultItems[i].uGroup].handle;
+ tvi.hInsertAfter = TVI_LAST;
+ tvi.item.pszText = defaultItems[i].szName;
+ tvi.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvi.item.lParam = i;
+ tvi.item.stateMask = TVIS_STATEIMAGEMASK;
+ if (defaultItems[i].uType == LOI_TYPE_SETTING)
+ tvi.item.state = INDEXTOSTATEIMAGEMASK(*((BOOL *)defaultItems[i].lParam) ? 3 : 2);//2 : 1);
+ else if (defaultItems[i].uType == LOI_TYPE_FLAG) {
+ UINT uVal = *((UINT *)defaultItems[i].lParam);
+ tvi.item.state = INDEXTOSTATEIMAGEMASK(uVal & defaultItems[i].id ? 3 : 2);//2 : 1);
+ }
+ defaultItems[i].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hWnd, IDC_EVENTOPTIONS), &tvi);
+ i++;
+ }
+ SendDlgItemMessage(hWnd, IDC_COLBACK_MESSAGE, CPM_SETCOLOUR, 0, options->colBackMsg);
+ SendDlgItemMessage(hWnd, IDC_COLTEXT_MESSAGE, CPM_SETCOLOUR, 0, options->colTextMsg);
+ SendDlgItemMessage(hWnd, IDC_COLBACK_OTHERS, CPM_SETCOLOUR, 0, options->colBackOthers);
+ SendDlgItemMessage(hWnd, IDC_COLTEXT_OTHERS, CPM_SETCOLOUR, 0, options->colTextOthers);
+ SendDlgItemMessage(hWnd, IDC_COLBACK_ERR, CPM_SETCOLOUR, 0, options->colBackErr);
+ SendDlgItemMessage(hWnd, IDC_COLTEXT_ERR, CPM_SETCOLOUR, 0, options->colTextErr);
+ CheckDlgButton(hWnd, IDC_CHKDEFAULTCOL_MESSAGE, options->bDefaultColorMsg ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hWnd, IDC_CHKDEFAULTCOL_OTHERS, options->bDefaultColorOthers ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hWnd, IDC_CHKDEFAULTCOL_ERR, options->bDefaultColorErr ? BST_CHECKED : BST_UNCHECKED);
+
+ SendDlgItemMessage(hWnd, IDC_COLTEXT_MUC, CPM_SETCOLOUR, 0, g_Settings.crPUTextColour);
+ SendDlgItemMessage(hWnd, IDC_COLBACK_MUC, CPM_SETCOLOUR, 0, g_Settings.crPUBkgColour);
+ CheckDlgButton(hWnd, IDC_CHKDEFAULTCOL_MUC, g_Settings.iPopupStyle == 2 ? BST_CHECKED : BST_UNCHECKED);
+
+ SendDlgItemMessage(hWnd, IDC_DELAY_MESSAGE_SPIN, UDM_SETRANGE, 0, MAKELONG(3600, -1));
+ SendDlgItemMessage(hWnd, IDC_DELAY_OTHERS_SPIN, UDM_SETRANGE, 0, MAKELONG(3600, -1));
+ SendDlgItemMessage(hWnd, IDC_DELAY_MESSAGE_MUC_SPIN, UDM_SETRANGE, 0, MAKELONG(3600, -1));
+ SendDlgItemMessage(hWnd, IDC_DELAY_ERR_SPIN, UDM_SETRANGE, 0, MAKELONG(3600, -1));
+
+ SendDlgItemMessage(hWnd, IDC_DELAY_MESSAGE_SPIN, UDM_SETPOS, 0, (LPARAM)options->iDelayMsg);
+ SendDlgItemMessage(hWnd, IDC_DELAY_OTHERS_SPIN, UDM_SETPOS, 0, (LPARAM)options->iDelayOthers);
+ SendDlgItemMessage(hWnd, IDC_DELAY_ERR_SPIN, UDM_SETPOS, 0, (LPARAM)options->iDelayErr);
+ SendDlgItemMessage(hWnd, IDC_DELAY_MESSAGE_MUC_SPIN, UDM_SETPOS, 0, (LPARAM)g_Settings.iPopupTimeout);
+
+ Utils::enableDlgControl(hWnd, IDC_COLBACK_MESSAGE, !options->bDefaultColorMsg);
+ Utils::enableDlgControl(hWnd, IDC_COLTEXT_MESSAGE, !options->bDefaultColorMsg);
+ Utils::enableDlgControl(hWnd, IDC_COLBACK_OTHERS, !options->bDefaultColorOthers);
+ Utils::enableDlgControl(hWnd, IDC_COLTEXT_OTHERS, !options->bDefaultColorOthers);
+ Utils::enableDlgControl(hWnd, IDC_COLBACK_ERR, !options->bDefaultColorErr);
+ Utils::enableDlgControl(hWnd, IDC_COLTEXT_ERR, !options->bDefaultColorErr);
+ Utils::enableDlgControl(hWnd, IDC_COLTEXT_MUC, (g_Settings.iPopupStyle == 3) ? TRUE : FALSE);
+ Utils::enableDlgControl(hWnd, IDC_COLBACK_MUC, (g_Settings.iPopupStyle == 3) ? TRUE : FALSE);
+
+ CheckDlgButton(hWnd, IDC_MUC_LOGCOLORS, g_Settings.iPopupStyle < 2 ? TRUE : FALSE);
+ Utils::enableDlgControl(hWnd, IDC_MUC_LOGCOLORS, g_Settings.iPopupStyle != 2 ? TRUE : FALSE);
+
+ SetDlgItemInt(hWnd, IDC_MESSAGEPREVIEWLIMIT, options->iLimitPreview, FALSE);
+ CheckDlgButton(hWnd, IDC_LIMITPREVIEW, (options->iLimitPreview > 0) ? 1 : 0);
+ SendDlgItemMessage(hWnd, IDC_MESSAGEPREVIEWLIMITSPIN, UDM_SETRANGE, 0, MAKELONG(2048, options->iLimitPreview > 0 ? 50 : 0));
+ SendDlgItemMessage(hWnd, IDC_MESSAGEPREVIEWLIMITSPIN, UDM_SETPOS, 0, (LPARAM)options->iLimitPreview);
+ Utils::enableDlgControl(hWnd, IDC_MESSAGEPREVIEWLIMIT, IsDlgButtonChecked(hWnd, IDC_LIMITPREVIEW));
+ Utils::enableDlgControl(hWnd, IDC_MESSAGEPREVIEWLIMITSPIN, IsDlgButtonChecked(hWnd, IDC_LIMITPREVIEW));
+
+ bWmNotify = FALSE;
+ return TRUE;
+ }
+ case DM_STATUSMASKSET:
+ M->WriteDword(MODULE, "statusmask", (DWORD)lParam);
+ options->dwStatusMask = (int)lParam;
+ break;
+ case WM_COMMAND:
+ if (!bWmNotify) {
+ switch (LOWORD(wParam)) {
+ case IDC_PREVIEW:
+ PopupPreview(options);
+ break;
+ case IDC_POPUPSTATUSMODES: {
+ HWND hwndNew = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CHOOSESTATUSMODES), hWnd, DlgProcSetupStatusModes, M->GetDword(MODULE, "statusmask", (DWORD) - 1));
+ SendMessage(hwndNew, DM_SETPARENTDIALOG, 0, (LPARAM)hWnd);
+ break;
+ }
+ default: {
+
+ if(IsDlgButtonChecked(hWnd, IDC_CHKDEFAULTCOL_MUC))
+ g_Settings.iPopupStyle = 2;
+ else if(IsDlgButtonChecked(hWnd, IDC_MUC_LOGCOLORS))
+ g_Settings.iPopupStyle = 1;
+ else
+ g_Settings.iPopupStyle = 3;
+
+ Utils::enableDlgControl(hWnd, IDC_MUC_LOGCOLORS, g_Settings.iPopupStyle != 2 ? TRUE : FALSE);
+
+ options->bDefaultColorMsg = IsDlgButtonChecked(hWnd, IDC_CHKDEFAULTCOL_MESSAGE);
+ options->bDefaultColorOthers = IsDlgButtonChecked(hWnd, IDC_CHKDEFAULTCOL_OTHERS);
+ options->bDefaultColorErr = IsDlgButtonChecked(hWnd, IDC_CHKDEFAULTCOL_ERR);
+
+ options->iDelayMsg = SendDlgItemMessage(hWnd, IDC_DELAY_MESSAGE_SPIN, UDM_GETPOS, 0, 0);
+ options->iDelayOthers = SendDlgItemMessage(hWnd, IDC_DELAY_OTHERS_SPIN, UDM_GETPOS, 0, 0);
+ options->iDelayErr = SendDlgItemMessage(hWnd, IDC_DELAY_ERR_SPIN, UDM_GETPOS, 0, 0);
+
+ g_Settings.iPopupTimeout = SendDlgItemMessage(hWnd, IDC_DELAY_MESSAGE_MUC_SPIN, UDM_GETPOS, 0, 0);
+
+ if (IsDlgButtonChecked(hWnd, IDC_LIMITPREVIEW))
+ options->iLimitPreview = GetDlgItemInt(hWnd, IDC_MESSAGEPREVIEWLIMIT, NULL, FALSE);
+ else
+ options->iLimitPreview = 0;
+ Utils::enableDlgControl(hWnd, IDC_COLBACK_MESSAGE, !options->bDefaultColorMsg);
+ Utils::enableDlgControl(hWnd, IDC_COLTEXT_MESSAGE, !options->bDefaultColorMsg);
+ Utils::enableDlgControl(hWnd, IDC_COLBACK_OTHERS, !options->bDefaultColorOthers);
+ Utils::enableDlgControl(hWnd, IDC_COLTEXT_OTHERS, !options->bDefaultColorOthers);
+ Utils::enableDlgControl(hWnd, IDC_COLBACK_ERR, !options->bDefaultColorErr);
+ Utils::enableDlgControl(hWnd, IDC_COLTEXT_ERR, !options->bDefaultColorErr);
+ Utils::enableDlgControl(hWnd, IDC_COLTEXT_MUC, (g_Settings.iPopupStyle == 3) ? TRUE : FALSE);
+ Utils::enableDlgControl(hWnd, IDC_COLBACK_MUC, (g_Settings.iPopupStyle == 3) ? TRUE : FALSE);
+
+ Utils::enableDlgControl(hWnd, IDC_MESSAGEPREVIEWLIMIT, IsDlgButtonChecked(hWnd, IDC_LIMITPREVIEW));
+ Utils::enableDlgControl(hWnd, IDC_MESSAGEPREVIEWLIMITSPIN, IsDlgButtonChecked(hWnd, IDC_LIMITPREVIEW));
+ //disable delay textbox when infinite is checked
+
+ Utils::enableDlgControl(hWnd, IDC_DELAY_MESSAGE, options->iDelayMsg != -1);
+ Utils::enableDlgControl(hWnd, IDC_DELAY_OTHERS, options->iDelayOthers != -1);
+ Utils::enableDlgControl(hWnd, IDC_DELAY_ERR, options->iDelayErr != -1);
+ Utils::enableDlgControl(hWnd, IDC_DELAY_MUC, g_Settings.iPopupTimeout != -1);
+
+ if (HIWORD(wParam) == CPN_COLOURCHANGED) {
+ options->colBackMsg = SendDlgItemMessage(hWnd, IDC_COLBACK_MESSAGE, CPM_GETCOLOUR, 0, 0);
+ options->colTextMsg = SendDlgItemMessage(hWnd, IDC_COLTEXT_MESSAGE, CPM_GETCOLOUR, 0, 0);
+ options->colBackOthers = SendDlgItemMessage(hWnd, IDC_COLBACK_OTHERS, CPM_GETCOLOUR, 0, 0);
+ options->colTextOthers = SendDlgItemMessage(hWnd, IDC_COLTEXT_OTHERS, CPM_GETCOLOUR, 0, 0);
+ options->colBackErr = SendDlgItemMessage(hWnd, IDC_COLBACK_ERR, CPM_GETCOLOUR, 0, 0);
+ options->colTextErr = SendDlgItemMessage(hWnd, IDC_COLTEXT_ERR, CPM_GETCOLOUR, 0, 0);
+ g_Settings.crPUBkgColour = SendDlgItemMessage(hWnd, IDC_COLBACK_MUC, CPM_GETCOLOUR, 0, 0);
+ g_Settings.crPUTextColour = SendDlgItemMessage(hWnd, IDC_COLTEXT_MUC, CPM_GETCOLOUR, 0, 0);
+ }
+ SendMessage(GetParent(hWnd), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case IDC_EVENTOPTIONS:
+ if (((LPNMHDR)lParam)->code == NM_CLICK) {
+ TVHITTESTINFO hti;
+ TVITEM item = {0};
+
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ item.stateMask = TVIS_STATEIMAGEMASK | TVIS_BOLD;
+ hti.pt.x = (short)LOWORD(GetMessagePos());
+ hti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt);
+ if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti)) {
+ item.hItem = (HTREEITEM)hti.hItem;
+ SendDlgItemMessageA(hWnd, IDC_EVENTOPTIONS, TVM_GETITEMA, 0, (LPARAM)&item);
+ if (item.state & TVIS_BOLD && hti.flags & TVHT_ONITEMSTATEICON) {
+ item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_BOLD;
+ SendDlgItemMessageA(hWnd, IDC_EVENTOPTIONS, TVM_SETITEMA, 0, (LPARAM)&item);
+ }
+ else if (hti.flags&TVHT_ONITEMSTATEICON) {
+ if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 3) {
+ item.state = INDEXTOSTATEIMAGEMASK(1);
+ SendDlgItemMessageA(hWnd, IDC_EVENTOPTIONS, TVM_SETITEMA, 0, (LPARAM)&item);
+ }
+ SendMessage(GetParent(hWnd), PSM_CHANGED, 0, 0);
+ }
+ }
+ }
+ break;
+ }
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY: {
+ int i = 0;
+ TVITEM item = {0};
+ struct TContainerData *pContainer = pFirstContainer;
+
+ TOptionListItem *defaultItems = CTranslator::getTree(CTranslator::TREE_NEN);
+
+ while (defaultItems[i].szName != NULL) {
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ item.hItem = (HTREEITEM)defaultItems[i].handle;
+ item.stateMask = TVIS_STATEIMAGEMASK;
+
+ SendDlgItemMessageA(hWnd, IDC_EVENTOPTIONS, TVM_GETITEMA, 0, (LPARAM)&item);
+ if (defaultItems[i].uType == LOI_TYPE_SETTING) {
+ BOOL *ptr = (BOOL *)defaultItems[i].lParam;
+ *ptr = (item.state >> 12) == 3/*2*/ ? TRUE : FALSE;
+ }
+ else if (defaultItems[i].uType == LOI_TYPE_FLAG) {
+ UINT *uVal = (UINT *)defaultItems[i].lParam;
+ *uVal = ((item.state >> 12) == 3/*2*/) ? *uVal | defaultItems[i].id : *uVal & ~defaultItems[i].id;
+ }
+ i++;
+ }
+ M->WriteByte("Chat", "PopupStyle", (BYTE)g_Settings.iPopupStyle);
+ DBWriteContactSettingWord(NULL, "Chat", "PopupTimeout", g_Settings.iPopupTimeout);
+
+ g_Settings.crPUBkgColour = SendDlgItemMessage(hWnd, IDC_COLBACK_MUC, CPM_GETCOLOUR, 0, 0);
+ M->WriteDword("Chat", "PopupColorBG", (DWORD)g_Settings.crPUBkgColour);
+ g_Settings.crPUTextColour = SendDlgItemMessage(hWnd, IDC_COLTEXT_MUC, CPM_GETCOLOUR, 0, 0);
+ M->WriteDword("Chat", "PopupColorText", (DWORD)g_Settings.crPUTextColour);
+
+ NEN_WriteOptions(&nen_options);
+ CheckForRemoveMask();
+ CreateSystrayIcon(nen_options.bTraySupport);
+ SetEvent(g_hEvent); // wake up the thread which cares about the floater and tray
+ break;
+ }
+ case PSN_RESET:
+ NEN_ReadOptions(&nen_options);
+ break;
+ }
+ break;
+ case WM_DESTROY: {
+ //ImageList_Destroy((HIMAGELIST)SendDlgItemMessage(hWnd, IDC_EVENTOPTIONS, TVM_GETIMAGELIST, 0, 0));
+ bWmNotify = TRUE;
+ break;
+ }
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+static int PopupAct(HWND hWnd, UINT mask, PLUGIN_DATAT* pdata)
+{
+ pdata->iActionTaken = TRUE;
+ if (mask & MASK_OPEN) {
+ int i;
+
+ for (i = 0; i < pdata->nrMerged; i++) {
+ if (pdata->eventData[i].hEvent != 0) {
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_HANDLECLISTEVENT, (WPARAM)pdata->hContact, (LPARAM)pdata->eventData[i].hEvent);
+ pdata->eventData[i].hEvent = 0;
+ }
+ }
+ }
+ if (mask & MASK_REMOVE) {
+ int i;
+
+ for (i = 0; i < pdata->nrMerged; i++) {
+ if (pdata->eventData[i].hEvent != 0) {
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_REMOVECLISTEVENT, (WPARAM)pdata->hContact, (LPARAM)pdata->eventData[i].hEvent);
+ pdata->eventData[i].hEvent = 0;
+ }
+ }
+ }
+ if (mask & MASK_DISMISS)
+ {
+ PUDeletePopUp(hWnd);
+ if (pdata->hContainer)
+ {
+ FLASHWINFO fwi;
+ fwi.cbSize = sizeof(fwi);
+ fwi.uCount = 0;
+ fwi.dwFlags = FLASHW_STOP;
+ fwi.hwnd = pdata->hContainer;
+ fwi.dwTimeout = 0;
+ FlashWindowEx(&fwi);
+ }
+ }
+ return 0;
+}
+
+static BOOL CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ PLUGIN_DATAT* pdata = NULL;
+
+ pdata = (PLUGIN_DATAT *)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, (LPARAM)pdata);
+ if (!pdata) return FALSE;
+
+ switch (message) {
+ case WM_COMMAND:
+ PopupAct(hWnd, pdata->pluginOptions->maskActL, pdata);
+ break;
+ case WM_CONTEXTMENU:
+ PopupAct(hWnd, pdata->pluginOptions->maskActR, pdata);
+ break;
+ case UM_FREEPLUGINDATA:
+ pdata->hContact = 0; // mark as removeable
+ pdata->hWnd = 0;
+ return TRUE;
+ case UM_INITPOPUP:
+ pdata->hWnd = hWnd;
+ if (pdata->iSeconds > 0)
+ SetTimer(hWnd, TIMER_TO_ACTION, pdata->iSeconds * 1000, NULL);
+ break;
+ case WM_MOUSEWHEEL:
+ break;
+ case WM_SETCURSOR:
+ break;
+ case WM_TIMER: {
+ POINT pt;
+ RECT rc;
+
+ if (wParam != TIMER_TO_ACTION)
+ break;
+
+ GetCursorPos(&pt);
+ GetWindowRect(hWnd, &rc);
+ if(PtInRect(&rc, pt))
+ break;
+
+ if (pdata->iSeconds > 0)
+ KillTimer(hWnd, TIMER_TO_ACTION);
+ PopupAct(hWnd, pdata->pluginOptions->maskActTE, pdata);
+ break;
+ }
+ default:
+ break;
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+/**
+ * Get a preview for the message
+ * caller must always mir_free() the return value
+ *
+ * @param eventType the event type
+ * @param dbe DBEVENTINFO *: database event structure
+ *
+ * @return
+ */
+static TCHAR *GetPreviewT(WORD eventType, DBEVENTINFO* dbe)
+{
+ TCHAR *commentFix = NULL;
+ char *pBlob = (char *)dbe->pBlob;
+ bool fAddEllipsis = false;
+
+ int iPreviewLimit = nen_options.iLimitPreview;
+
+ if(iPreviewLimit > 500 || iPreviewLimit == 0)
+ iPreviewLimit = 500;
+
+ switch (eventType) {
+ case EVENTTYPE_MESSAGE:
+ if (pBlob) {
+ if(nen_options.bPreview) {
+ TCHAR* buf = DbGetEventTextT(dbe, CP_ACP);
+ if(lstrlen(buf) > iPreviewLimit) {
+ fAddEllipsis = true;
+ int iIndex = iPreviewLimit;
+ int iWordThreshold = 20;
+ while(iIndex && buf[iIndex] != ' ' && iWordThreshold--) {
+ buf[iIndex--] = 0;
+ }
+ buf[iIndex] = 0;
+ }
+ buf = (TCHAR *)mir_realloc(buf, (lstrlen(buf) + 5) * sizeof(TCHAR));
+ if(fAddEllipsis)
+ _tcscat(buf, _T("..."));
+ return(buf);
+ }
+ }
+ commentFix = mir_tstrdup(CTranslator::get(CTranslator::GEN_POPUPS_MESSAGE));
+ break;
+ case EVENTTYPE_FILE:
+ if(pBlob) {
+ if(!nen_options.bPreview) {
+ commentFix = mir_tstrdup(CTranslator::get(CTranslator::GEN_STRING_EVENT_FILE));
+ break;
+ }
+ if(dbe->cbBlob > 5) { // min valid size = (sizeof(DWORD) + 1 character file name + terminating 0)
+ char* szFileName = (char *)dbe->pBlob + sizeof(DWORD);
+ char* szDescr = 0;
+ size_t namelength = Utils::safe_strlen(szFileName, dbe->cbBlob - sizeof(DWORD));
+
+ if(dbe->cbBlob > (sizeof(DWORD) + namelength + 1))
+ szDescr = szFileName + namelength + 1;
+
+ TCHAR* tszFileName = DbGetEventStringT(dbe, szFileName );
+ TCHAR* buf = 0;
+
+ if (szDescr && Utils::safe_strlen(szDescr, dbe->cbBlob - sizeof(DWORD) - namelength - 1) > 0) {
+ TCHAR* tszDescr = DbGetEventStringT(dbe, szDescr);
+
+ if(tszFileName && tszDescr) {
+ size_t uRequired = sizeof(TCHAR) * (_tcslen(CTranslator::get(CTranslator::GEN_STRING_EVENT_FILE)) + namelength + _tcslen(tszDescr) + 10);
+ buf = (TCHAR *)mir_alloc(uRequired);
+ mir_sntprintf(buf, uRequired, _T("%s: %s (%s)"), CTranslator::get(CTranslator::GEN_STRING_EVENT_FILE),
+ tszFileName, tszDescr);
+ mir_free(tszDescr);
+ mir_free(tszFileName);
+ return(buf);
+ }
+ }
+
+ if(tszFileName) {
+ size_t uRequired = sizeof(TCHAR) * (_tcslen(CTranslator::get(CTranslator::GEN_STRING_EVENT_FILE)) + namelength +
+ _tcslen(CTranslator::get(CTranslator::GEN_STRING_EVENT_FILE_NODESC)) + 10);
+ buf = (TCHAR *)mir_alloc(uRequired);
+ mir_sntprintf(buf, uRequired, _T("%s: %s (%s)"), CTranslator::get(CTranslator::GEN_STRING_EVENT_FILE),
+ tszFileName, CTranslator::get(CTranslator::GEN_STRING_EVENT_FILE_NODESC));
+ mir_free(tszFileName);
+ }
+ if(buf)
+ return(buf);
+ }
+ }
+ commentFix = mir_tstrdup(CTranslator::get(CTranslator::GEN_STRING_EVENT_FILE_INVALID));
+ break;
+ default:
+ commentFix = mir_tstrdup(CTranslator::get(CTranslator::GEN_POPUPS_UNKNOWN));
+ break;
+ }
+ return commentFix;
+}
+
+static int PopupUpdateT(HANDLE hContact, HANDLE hEvent)
+{
+ PLUGIN_DATAT *pdata = 0;
+ DBEVENTINFO dbe;
+ TCHAR lpzText[MAX_SECONDLINE] = _T("");
+ TCHAR timestamp[MAX_DATASIZE] = _T("\0");
+ TCHAR formatTime[MAX_DATASIZE] = _T("\0");
+ int iEvent = 0;
+ TCHAR *p = lpzText;
+ int available = 0, i;
+ TCHAR *szPreview = NULL;
+
+ pdata = const_cast<PLUGIN_DATAT *>(PU_GetByContact(hContact));
+
+ if(!pdata)
+ return(1);
+
+ ZeroMemory((void *)&dbe, sizeof(dbe));
+
+ if (hEvent) {
+ if (pdata->pluginOptions->bShowHeaders) {
+ mir_sntprintf(pdata->szHeader, safe_sizeof(pdata->szHeader), _T("%s %d\n"),
+ CTranslator::get(CTranslator::GEN_POPUPS_NEW), pdata->nrMerged + 1);
+ pdata->szHeader[255] = 0;
+ }
+ ZeroMemory(&dbe, sizeof(dbe));
+ dbe.cbSize = sizeof(dbe);
+ if (pdata->pluginOptions->bPreview && hContact) {
+ dbe.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hEvent, 0);
+ dbe.pBlob = (PBYTE)malloc(dbe.cbBlob);
+ }
+ CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&dbe);
+
+ formatTime[0] = 0;
+ _tcsncpy(formatTime, _T("%Y.%m.%d %H:%M"), MAX_DATASIZE);
+ _tcsftime(timestamp, MAX_DATASIZE, formatTime, _localtime32((__time32_t *)&dbe.timestamp));
+ mir_sntprintf(pdata->eventData[pdata->nrMerged].szText, MAX_SECONDLINE, _T("\n\n%s\n"), timestamp);
+
+ szPreview = GetPreviewT(dbe.eventType, &dbe);
+ if (szPreview) {
+ _tcsncat(pdata->eventData[pdata->nrMerged].szText, szPreview, MAX_SECONDLINE);
+ mir_free(szPreview);
+ } else
+ _tcsncat(pdata->eventData[pdata->nrMerged].szText, _T(" "), MAX_SECONDLINE);
+
+ pdata->eventData[pdata->nrMerged].szText[MAX_SECONDLINE - 1] = 0;
+
+ /*
+ * now, reassemble the popup text, make sure the *last* event is shown, and then show the most recent events
+ * for which there is enough space in the popup text
+ */
+
+ available = MAX_SECONDLINE - 1;
+ if (pdata->pluginOptions->bShowHeaders) {
+ _tcsncpy(lpzText, pdata->szHeader, MAX_SECONDLINE);
+ available -= lstrlen(pdata->szHeader);
+ }
+ for (i = pdata->nrMerged; i >= 0; i--) {
+ available -= lstrlen(pdata->eventData[i].szText);
+ if (available <= 0)
+ break;
+ }
+ i = (available > 0) ? i + 1 : i + 2;
+ for (; i <= pdata->nrMerged; i++) {
+ _tcsncat(lpzText, pdata->eventData[i].szText, MAX_SECONDLINE);
+ }
+ pdata->eventData[pdata->nrMerged].hEvent = hEvent;
+ pdata->eventData[pdata->nrMerged].timestamp = dbe.timestamp;
+ pdata->nrMerged++;
+ if (pdata->nrMerged >= pdata->nrEventsAlloced) {
+ pdata->nrEventsAlloced += 5;
+ pdata->eventData = (EVENT_DATAT *)realloc(pdata->eventData, pdata->nrEventsAlloced * sizeof(EVENT_DATAT));
+ }
+ if (dbe.pBlob)
+ free(dbe.pBlob);
+
+ CallService(MS_POPUP_CHANGETEXTT, (WPARAM)pdata->hWnd, (LPARAM)lpzText);
+ }
+ return(0);
+}
+
+static int PopupShowT(NEN_OPTIONS *pluginOptions, HANDLE hContact, HANDLE hEvent, UINT eventType, HWND hContainer)
+{
+ POPUPDATAT_V2 pud = {0};
+ PLUGIN_DATAT *pdata;
+ DBEVENTINFO dbe;
+ long iSeconds = 0;
+ TCHAR *szPreview = NULL;
+
+ //there has to be a maximum number of popups shown at the same time
+ if(PopupList.size() >= MAX_POPUPS)
+ return(2);
+
+ if (!PluginConfig.g_PopupAvail)
+ return 0;
+
+ switch (eventType) {
+ case EVENTTYPE_MESSAGE:
+ pud.lchIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ pud.colorBack = pluginOptions->bDefaultColorMsg ? 0 : pluginOptions->colBackMsg;
+ pud.colorText = pluginOptions->bDefaultColorMsg ? 0 : pluginOptions->colTextMsg;
+ iSeconds = pluginOptions->iDelayMsg;
+ break;
+ case EVENTTYPE_FILE:
+ pud.lchIcon = LoadSkinnedIcon(SKINICON_EVENT_FILE);
+ pud.colorBack = pluginOptions->bDefaultColorOthers ? 0 : pluginOptions->colBackOthers;
+ pud.colorText = pluginOptions->bDefaultColorOthers ? 0 : pluginOptions->colTextOthers;
+ iSeconds = pluginOptions->iDelayOthers;
+ break;
+ default:
+ return 1;
+ }
+
+ ZeroMemory(&dbe, sizeof(dbe));
+ dbe.pBlob = NULL;
+ dbe.cbSize = sizeof(dbe);
+
+ // fix for a crash
+ if (hEvent && (pluginOptions->bPreview || hContact == 0)) {
+ dbe.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hEvent, 0);
+ dbe.pBlob = (PBYTE)malloc(dbe.cbBlob);
+ } else
+ dbe.cbBlob = 0;
+ CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&dbe);
+
+ if(hEvent == 0 && hContact == 0)
+ dbe.szModule = Translate("Unknown module or contact");
+
+ pdata = (PLUGIN_DATAT *)malloc(sizeof(PLUGIN_DATAT));
+ ZeroMemory((void *)pdata, sizeof(PLUGIN_DATAT));
+
+ pdata->eventType = eventType;
+ pdata->hContact = hContact;
+ pdata->pluginOptions = pluginOptions;
+ pdata->pud = &pud;
+ pdata->iSeconds = iSeconds; // ? iSeconds : pluginOptions->iDelayDefault;
+ pdata->hContainer = hContainer;
+ pud.iSeconds = pdata->iSeconds ? -1 : 0;
+
+ //finally create the popup
+ pud.lchContact = hContact;
+ pud.PluginWindowProc = (WNDPROC)PopupDlgProc;
+ pud.PluginData = pdata;
+
+ if (hContact)
+ mir_sntprintf(pud.lptzContactName, MAX_CONTACTNAME, _T("%s"), (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR));
+ else {
+ TCHAR *szModule = mir_a2t(dbe.szModule);
+ mir_sntprintf(pud.lptzContactName, MAX_CONTACTNAME, _T("%s"), szModule);
+ mir_free(szModule);
+ }
+
+ szPreview = GetPreviewT((WORD)eventType, &dbe);
+ if (szPreview) {
+ mir_sntprintf(pud.lptzText, MAX_SECONDLINE, _T("%s"), szPreview);
+ mir_free(szPreview);
+ } else
+ mir_sntprintf(pud.lptzText, MAX_SECONDLINE, _T(" "));
+
+ pdata->eventData = (EVENT_DATAT *)malloc(NR_MERGED * sizeof(EVENT_DATAT));
+ pdata->eventData[0].hEvent = hEvent;
+ pdata->eventData[0].timestamp = dbe.timestamp;
+ _tcsncpy(pdata->eventData[0].szText, pud.lptzText, MAX_SECONDLINE);
+ pdata->eventData[0].szText[MAX_SECONDLINE - 1] = 0;
+ pdata->nrEventsAlloced = NR_MERGED;
+ pdata->nrMerged = 1;
+
+ // fix for broken popups -- process failures
+ if (CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&pud, 0) < 0) {
+ // failed to display, perform cleanup
+ if (pdata->eventData)
+ free(pdata->eventData);
+ free(pdata);
+ }
+ else
+ PopupList.push_back(pdata);
+
+ if (dbe.pBlob)
+ free(dbe.pBlob);
+
+ return 0;
+}
+
+static int TSAPI PopupPreview(NEN_OPTIONS *pluginOptions)
+{
+ PopupShowT(pluginOptions, NULL, NULL, EVENTTYPE_MESSAGE, NULL);
+ return 0;
+}
+
+/*
+ * updates the menu entry...
+ * bForced is used to only update the status, nickname etc. and does NOT update the unread count
+ */
+void TSAPI UpdateTrayMenuState(struct TWindowData *dat, BOOL bForced)
+{
+ MENUITEMINFO mii = {0};
+ TCHAR szMenuEntry[80];
+
+ if (PluginConfig.g_hMenuTrayUnread == 0)
+ return;
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA | MIIM_BITMAP;
+
+ if (dat->hContact != 0) {
+ const TCHAR *tszProto = dat->cache->getRealAccount();
+
+ assert(tszProto != 0);
+
+ GetMenuItemInfo(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)dat->hContact, FALSE, &mii);
+ if (!bForced)
+ PluginConfig.m_UnreadInTray -= (mii.dwItemData & 0x0000ffff);
+ if (mii.dwItemData > 0 || bForced) {
+ if (!bForced)
+ mii.dwItemData = 0;
+ mii.fMask |= MIIM_STRING;
+ mir_sntprintf(szMenuEntry, safe_sizeof(szMenuEntry), _T("%s: %s (%s) [%d]"), tszProto, dat->cache->getNick(), dat->szStatus[0] ? dat->szStatus : _T("(undef)"), mii.dwItemData & 0x0000ffff);
+ mii.dwTypeData = (LPTSTR)szMenuEntry;
+ mii.cch = lstrlen(szMenuEntry) + 1;
+ }
+ mii.hbmpItem = HBMMENU_CALLBACK;
+ SetMenuItemInfo(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)dat->hContact, FALSE, &mii);
+ }
+}
+/*
+ * if we want tray support, add the contact to the list of unread sessions in the tray menu
+ */
+
+int TSAPI UpdateTrayMenu(const TWindowData *dat, WORD wStatus, const char *szProto, const TCHAR *szStatus, HANDLE hContact, DWORD fromEvent)
+{
+ if (PluginConfig.g_hMenuTrayUnread != 0 && hContact != 0 && szProto != NULL) {
+ TCHAR szMenuEntry[80], *tszFinalProto = NULL;
+ MENUITEMINFO mii = {0};
+ WORD wMyStatus;
+ const TCHAR *szMyStatus;
+ const TCHAR *szNick = NULL;
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA | MIIM_ID | MIIM_BITMAP;
+
+ if (szProto == NULL)
+ return 0; // should never happen...
+
+ PROTOACCOUNT *acc = (PROTOACCOUNT *)CallService(MS_PROTO_GETACCOUNT, (WPARAM)0, (LPARAM)szProto);
+
+ tszFinalProto = (acc && acc->tszAccountName ? acc->tszAccountName : 0);
+
+ if(tszFinalProto == 0)
+ return(0); // should also NOT happen
+
+ wMyStatus = (wStatus == 0) ? DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE) : wStatus;
+ szMyStatus = (szStatus == NULL) ? (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)wMyStatus, GSMDF_TCHAR) : szStatus;
+ mii.wID = (UINT)hContact;
+ mii.hbmpItem = HBMMENU_CALLBACK;
+
+ if (dat != 0) {
+ szNick = dat->cache->getNick();
+ GetMenuItemInfo(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)hContact, FALSE, &mii);
+ mii.dwItemData++;
+ if (fromEvent == 2) // from chat...
+ mii.dwItemData |= 0x10000000;
+ DeleteMenu(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)hContact, MF_BYCOMMAND);
+ mir_sntprintf(szMenuEntry, safe_sizeof(szMenuEntry), _T("%s: %s (%s) [%d]"), tszFinalProto, szNick, szMyStatus, mii.dwItemData & 0x0000ffff);
+ AppendMenu(PluginConfig.g_hMenuTrayUnread, MF_BYCOMMAND | MF_STRING, (UINT_PTR)hContact, szMenuEntry);
+ PluginConfig.m_UnreadInTray++;
+ if (PluginConfig.m_UnreadInTray)
+ SetEvent(g_hEvent);
+ SetMenuItemInfo(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)hContact, FALSE, &mii);
+ } else {
+ szNick = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR);
+ if (CheckMenuItem(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)hContact, MF_BYCOMMAND | MF_UNCHECKED) == -1) {
+ mir_sntprintf(szMenuEntry, safe_sizeof(szMenuEntry), _T("%s: %s (%s) [%d]"), tszFinalProto, szNick, szMyStatus, fromEvent ? 1 : 0);
+ AppendMenu(PluginConfig.g_hMenuTrayUnread, MF_BYCOMMAND | MF_STRING, (UINT_PTR)hContact, szMenuEntry);
+ mii.dwItemData = fromEvent ? 1 : 0;
+ PluginConfig.m_UnreadInTray += (mii.dwItemData & 0x0000ffff);
+ if (PluginConfig.m_UnreadInTray)
+ SetEvent(g_hEvent);
+ if (fromEvent == 2)
+ mii.dwItemData |= 0x10000000;
+ } else {
+ GetMenuItemInfo(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)hContact, FALSE, &mii);
+ mii.dwItemData += (fromEvent ? 1 : 0);
+ PluginConfig.m_UnreadInTray += (fromEvent ? 1 : 0);
+ if (PluginConfig.m_UnreadInTray)
+ SetEvent(g_hEvent);
+ mii.fMask |= MIIM_STRING;
+ if (fromEvent == 2)
+ mii.dwItemData |= 0x10000000;
+ mir_sntprintf(szMenuEntry, safe_sizeof(szMenuEntry), _T("%s: %s (%s) [%d]"), tszFinalProto, szNick, szMyStatus, mii.dwItemData & 0x0000ffff);
+ mii.cch = lstrlen(szMenuEntry) + 1;
+ mii.dwTypeData = (LPTSTR)szMenuEntry;
+ }
+ SetMenuItemInfo(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)hContact, FALSE, &mii);
+ }
+ }
+ return 0;
+}
+
+
+int tabSRMM_ShowPopup(WPARAM wParam, LPARAM lParam, WORD eventType, int windowOpen, struct TContainerData *pContainer, HWND hwndChild, const char *szProto, struct TWindowData *dat)
+{
+ int heFlags;
+
+ if (nen_options.iDisable) // no popups at all. Period
+ return(0);
+
+ PU_CleanUp();
+
+ heFlags = HistoryEvents_GetFlags(eventType);
+ if (heFlags != -1 && !(heFlags & HISTORYEVENTS_FLAG_DEFAULT)) // Filter history events popups
+ return 0;
+
+ if (nen_options.bDisableNonMessage && eventType != EVENTTYPE_MESSAGE)
+ return(0);
+
+ /*
+ * check the status mode against the status mask
+ */
+
+ if (nen_options.dwStatusMask != -1) {
+ DWORD dwStatus = 0;
+ if (szProto != NULL) {
+ dwStatus = (DWORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ if (!(dwStatus == 0 || dwStatus <= ID_STATUS_OFFLINE || ((1 << (dwStatus - ID_STATUS_ONLINE)) & nen_options.dwStatusMask))) // should never happen, but...
+ return 0;
+ }
+ }
+ if (nen_options.bNoRSS && szProto != NULL && !strncmp(szProto, "RSS", 3))
+ return 0; // filter out RSS popups
+ //
+ if (windowOpen && pContainer != 0) { // message window is open, need to check the container config if we want to see a popup nonetheless
+ if (nen_options.bWindowCheck && windowOpen) // no popups at all for open windows... no exceptions
+ return(0);
+ if (pContainer->dwFlags & CNT_DONTREPORT && (IsIconic(pContainer->hwnd))) // in tray counts as "minimised"
+ goto passed;
+ if (pContainer->dwFlags & CNT_DONTREPORTUNFOCUSED) {
+ if (!IsIconic(pContainer->hwnd) && GetForegroundWindow() != pContainer->hwnd && GetActiveWindow() != pContainer->hwnd)
+ goto passed;
+ }
+ if (pContainer->dwFlags & CNT_ALWAYSREPORTINACTIVE) {
+ if (pContainer->dwFlags & CNT_DONTREPORTFOCUSED)
+ goto passed;
+
+ if (pContainer->hwndActive == hwndChild)
+ return 0;
+ else
+ goto passed;
+ }
+ return 0;
+ }
+passed:
+ if (!(PluginConfig.g_PopupAvail && PluginConfig.g_PopupWAvail))
+ return 0;
+
+ if(PU_GetByContact((HANDLE)wParam) && nen_options.bMergePopup && eventType == EVENTTYPE_MESSAGE) {
+ if(PopupUpdateT((HANDLE)wParam, (HANDLE)lParam) != 0)
+ PopupShowT(&nen_options, (HANDLE)wParam, (HANDLE)lParam, (UINT)eventType, pContainer ? pContainer->hwnd : 0);
+ }
+ else
+ PopupShowT(&nen_options, (HANDLE)wParam, (HANDLE)lParam, (UINT)eventType, pContainer ? pContainer->hwnd : 0);
+
+ return 0;
+}
+
+/**
+ * remove all popups for hContact, but only if the mask matches the current "mode"
+ */
+
+void TSAPI DeletePopupsForContact(HANDLE hContact, DWORD dwMask)
+{
+ int i = 0;
+ PLUGIN_DATAT* _T = 0;
+
+ if (!(dwMask & nen_options.dwRemoveMask) || nen_options.iDisable || !PluginConfig.g_PopupAvail)
+ return;
+
+ while ((_T = const_cast<PLUGIN_DATAT *>(PU_GetByContact(hContact))) != 0) {
+ _T->hContact = 0; // make sure, it never "comes back"
+ if (_T->hWnd != 0 && IsWindow(_T->hWnd))
+ PUDeletePopUp(_T->hWnd);
+ }
+}
diff --git a/plugins/TabSRMM/src/generic_msghandlers.cpp b/plugins/TabSRMM/src/generic_msghandlers.cpp
new file mode 100644
index 0000000000..d507076eae
--- /dev/null
+++ b/plugins/TabSRMM/src/generic_msghandlers.cpp
@@ -0,0 +1,2419 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: generic_msghandlers.cpp 13587 2011-04-12 13:54:26Z george.hazan $
+ *
+ * these are generic message handlers which are used by the message dialog window procedure.
+ * calling them directly instead of using SendMessage() is faster.
+ * also contains various callback functions for custom buttons
+ */
+
+
+#include "commonheaders.h"
+
+extern RECT rcLastStatusBarClick;
+
+
+/**
+ * Save message log for given session as RTF document
+ */
+void TSAPI DM_SaveLogAsRTF(const TWindowData* dat)
+{
+ TCHAR szFilename[MAX_PATH];
+ OPENFILENAME ofn = {0};
+ EDITSTREAM stream = { 0 };
+ TCHAR szFilter[MAX_PATH];
+
+ if (dat && dat->hwndIEView != 0) {
+ IEVIEWEVENT event = {0};
+
+ event.cbSize = sizeof(IEVIEWEVENT);
+ event.hwnd = dat->hwndIEView;
+ event.hContact = dat->hContact;
+ event.iType = IEE_SAVE_DOCUMENT;
+ event.dwFlags = 0;
+ event.count = 0;
+ event.codepage = 0;
+ CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event);
+ } else if(dat) {
+ TCHAR szInitialDir[MAX_PATH + 2];
+
+ mir_sntprintf(szFilter, SIZEOF(szFilter), _T("%s%c*.rtf%c%c"), TranslateT("Rich Edit file"), 0, 0, 0);
+ mir_sntprintf(szFilename, MAX_PATH, _T("%s.rtf"), dat->cache->getNick());
+
+ Utils::sanitizeFilename(szFilename);
+
+ mir_sntprintf(szInitialDir, MAX_PATH, _T("%s%s\\"), M->getDataPath(), _T("\\Saved message logs"));
+ CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)szInitialDir);
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = dat->hwnd;
+ ofn.lpstrFile = szFilename;
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrInitialDir = szInitialDir;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.Flags = OFN_HIDEREADONLY;
+ ofn.lpstrDefExt = _T("rtf");
+ if (GetSaveFileName(&ofn)) {
+ stream.dwCookie = (DWORD_PTR)szFilename;
+ stream.dwError = 0;
+ stream.pfnCallback = Utils::StreamOut;
+ SendDlgItemMessage(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG, EM_STREAMOUT, SF_RTF | SF_USECODEPAGE, (LPARAM) & stream);
+ }
+ }
+}
+
+/**
+ * This is broadcasted by the container to all child windows to check if the
+ * container can be autohidden or -closed.
+ *
+ * wParam is the autohide timeout (in seconds)
+ * lParam points to a BOOL and a session which wants to prevent auto-hiding
+ * the container must set it to FALSE.
+ *
+ * If no session in the container disagrees, the container will be hidden.
+ */
+void TSAPI DM_CheckAutoHide(const TWindowData* dat, WPARAM wParam, LPARAM lParam)
+{
+ if(dat && lParam) {
+ BOOL *fResult = (BOOL *)lParam;
+
+ if(GetWindowTextLengthA(GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE)) > 0) {
+ *fResult = FALSE;
+ return; // text entered in the input area -> prevent autohide/cose
+ }
+ if(dat->dwUnread) {
+ *fResult = FALSE;
+ return; // unread events, do not hide or close the container
+ }
+ if(((GetTickCount() - dat->dwLastActivity) / 1000) <= wParam)
+ *fResult = FALSE; // time since last activity did not yet reach the threshold.
+ }
+}
+/**
+ * checks if the balloon tooltip can be dismissed (usually called by
+ * WM_MOUSEMOVE events
+ */
+
+void TSAPI DM_DismissTip(TWindowData *dat, const POINT& pt)
+{
+ RECT rc;
+
+ if(!IsWindowVisible(dat->hwndTip))
+ return;
+
+ GetWindowRect(dat->hwndTip, &rc);
+ if(PtInRect(&rc, pt))
+ return;
+
+ if(abs(pt.x - dat->ptTipActivation.x) > 5 || abs(pt.y - dat->ptTipActivation.y) > 5) {
+ SendMessage(dat->hwndTip, TTM_TRACKACTIVATE, FALSE, 0);
+ dat->ptTipActivation.x = dat->ptTipActivation.y = 0;
+ }
+}
+
+/**
+ * initialize the balloon tooltip for message window notifications
+ */
+void TSAPI DM_InitTip(TWindowData *dat)
+{
+ dat->hwndTip = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_BALLOON, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT, dat->hwnd, NULL, g_hInst, (LPVOID) NULL);
+
+ ZeroMemory((void *)&dat->ti, sizeof(dat->ti));
+ dat->ti.cbSize = sizeof(dat->ti);
+ dat->ti.lpszText = PluginConfig.m_szNoStatus;
+ dat->ti.hinst = g_hInst;
+ dat->ti.hwnd = dat->hwnd;
+ dat->ti.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_TRANSPARENT;
+ dat->ti.uId = (UINT_PTR)dat->hwnd;
+ SendMessageA(dat->hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&dat->ti);
+ SetWindowPos(dat->hwndTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
+}
+
+/**
+ * checks generic hotkeys valid for both IM and MUC sessions
+ *
+ * returns 1 for handled hotkeys, 0 otherwise.
+ */
+LRESULT TSAPI DM_GenericHotkeysCheck(MSG *message, TWindowData *dat)
+{
+ LRESULT mim_hotkey_check = CallService(MS_HOTKEY_CHECK, (WPARAM)message, (LPARAM)(TABSRMM_HK_SECTION_GENERIC));
+ HWND hwndDlg = dat->hwnd;
+
+ switch(mim_hotkey_check) {
+ case TABSRMM_HK_PASTEANDSEND:
+ HandlePasteAndSend(dat);
+ return(1);
+ case TABSRMM_HK_HISTORY:
+ SendMessage(hwndDlg, WM_COMMAND, IDC_HISTORY, 0);
+ return(1);
+ case TABSRMM_HK_CONTAINEROPTIONS:
+ if (dat->pContainer->hWndOptions == 0)
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CONTAINEROPTIONS), dat->pContainer->hwnd,
+ DlgProcContainerOptions, (LPARAM)dat->pContainer);
+ return(1);
+ case TABSRMM_HK_SEND:
+ if (!(GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_STYLE) & ES_READONLY)) {
+ PostMessage(hwndDlg, WM_COMMAND, IDOK, 0);
+ return(1);
+ }
+ break;
+ case TABSRMM_HK_TOGGLEINFOPANEL:
+ dat->Panel->setActive(dat->Panel->isActive() ? FALSE : TRUE);
+ dat->Panel->showHide();
+ return(1);
+ case TABSRMM_HK_EMOTICONS:
+ SendMessage(hwndDlg, WM_COMMAND, IDC_SMILEYBTN, 0);
+ return(1);
+ case TABSRMM_HK_TOGGLETOOLBAR:
+ SendMessage(hwndDlg, WM_COMMAND, IDC_TOGGLETOOLBAR, 0);
+ return(1);
+ case TABSRMM_HK_CLEARLOG:
+ ClearLog(dat);
+ return(1);
+ case TABSRMM_HK_TOGGLESIDEBAR:
+ if(dat->pContainer->SideBar->isActive())
+ SendMessage(hwndDlg, WM_COMMAND, IDC_TOGGLESIDEBAR, 0);
+ return(1);
+ default:
+ break;
+ }
+ return(0);
+}
+
+LRESULT TSAPI DM_MsgWindowCmdHandler(HWND hwndDlg, TContainerData *m_pContainer, TWindowData *dat, UINT cmd, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndContainer = m_pContainer->hwnd;
+
+ switch(cmd) {
+ case IDC_FONTBOLD:
+ case IDC_FONTITALIC:
+ case IDC_FONTUNDERLINE:
+ case IDC_FONTSTRIKEOUT: {
+ CHARFORMAT2 cf, cfOld;
+ int cmd = LOWORD(wParam);
+ BOOL isBold, isItalic, isUnderline, isStrikeout;
+
+ if (dat->SendFormat == 0) // dont use formatting if disabled
+ break;
+
+ ZeroMemory(&cf, sizeof(CHARFORMAT2));
+ ZeroMemory(&cfOld, sizeof(CHARFORMAT2));
+ cfOld.cbSize = cf.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT;
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD);
+ isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC);
+ isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE);
+ isStrikeout = (cfOld.dwEffects & CFM_STRIKEOUT) && (cfOld.dwMask & CFM_STRIKEOUT);
+
+ if (cmd == IDC_FONTBOLD && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTBOLD)))
+ break;
+ if (cmd == IDC_FONTITALIC && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTITALIC)))
+ break;
+ if (cmd == IDC_FONTUNDERLINE && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTUNDERLINE)))
+ break;
+ if (cmd == IDC_FONTSTRIKEOUT && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTSTRIKEOUT)))
+ break;
+ if (cmd == IDC_FONTBOLD) {
+ cf.dwEffects = isBold ? 0 : CFE_BOLD;
+ cf.dwMask = CFM_BOLD;
+ CheckDlgButton(hwndDlg, IDC_FONTBOLD, !isBold);
+ } else if (cmd == IDC_FONTITALIC) {
+ cf.dwEffects = isItalic ? 0 : CFE_ITALIC;
+ cf.dwMask = CFM_ITALIC;
+ CheckDlgButton(hwndDlg, IDC_FONTITALIC, !isItalic);
+ } else if (cmd == IDC_FONTUNDERLINE) {
+ cf.dwEffects = isUnderline ? 0 : CFE_UNDERLINE;
+ cf.dwMask = CFM_UNDERLINE;
+ CheckDlgButton(hwndDlg, IDC_FONTUNDERLINE, !isUnderline);
+ } else if (cmd == IDC_FONTSTRIKEOUT) {
+ cf.dwEffects = isStrikeout ? 0 : CFM_STRIKEOUT;
+ cf.dwMask = CFM_STRIKEOUT;
+ CheckDlgButton(hwndDlg, IDC_FONTSTRIKEOUT, !isStrikeout);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ break;
+ }
+ case IDC_FONTFACE: {
+ HMENU submenu = GetSubMenu(m_pContainer->hMenuContext, 7);
+ RECT rc;
+ int iSelection, i;
+ CHARFORMAT2 cf;
+
+ ZeroMemory(&cf, sizeof(CHARFORMAT2));
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwMask = CFM_COLOR;
+ cf.dwEffects = 0;
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_FONTFACE), &rc);
+ iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL);
+ if (iSelection == ID_FONT_CLEARALLFORMATTING) {
+ cf.dwMask = CFM_BOLD | CFM_COLOR | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT;
+ cf.crTextColor = M->GetDword(FONTMODULE, "Font16Col", 0);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ break;
+ }
+ if (iSelection == ID_FONT_DEFAULTCOLOR) {
+ int i = 0;
+ cf.crTextColor = M->GetDword(FONTMODULE, "Font16Col", 0);
+ for (i = 0; i < Utils::rtf_ctable_size; i++) {
+ if (Utils::rtf_ctable[i].clr == cf.crTextColor)
+ cf.crTextColor = RGB(GetRValue(cf.crTextColor), GetGValue(cf.crTextColor), GetBValue(cf.crTextColor) == 0 ? GetBValue(cf.crTextColor) + 1 : GetBValue(cf.crTextColor) - 1);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ break;
+ }
+ for (i = 0; i < RTF_CTABLE_DEFSIZE; i++) {
+ if (Utils::rtf_ctable[i].menuid == iSelection) {
+ cf.crTextColor = Utils::rtf_ctable[i].clr;
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+ }
+ break;
+ }
+
+ case IDCANCEL: {
+ ShowWindow(hwndContainer, SW_MINIMIZE);
+ return FALSE;
+ }
+
+ case IDC_SAVE:
+ SendMessage(hwndDlg, WM_CLOSE, 1, 0);
+ break;
+
+ case IDC_NAME: {
+ if (GetKeyState(VK_SHIFT) & 0x8000) // copy UIN
+ SendMessage(hwndDlg, DM_UINTOCLIPBOARD, 0, 0);
+ else {
+ CallService(MS_USERINFO_SHOWDIALOG, (WPARAM) (dat->cache->getActiveContact()), 0);
+ }
+ break;
+ }
+
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM) dat->hContact, 0);
+ break;
+
+ case IDC_SMILEYBTN:
+ if (dat->doSmileys && PluginConfig.g_SmileyAddAvail) {
+ RECT rc;
+ HANDLE hContact = dat->cache->getActiveContact();
+
+ if (CheckValidSmileyPack(dat->cache->getActiveProto(), hContact) != 0) {
+ SMADD_SHOWSEL3 smaddInfo = {0};
+
+ if (lParam == 0)
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_SMILEYBTN), &rc);
+ else
+ GetWindowRect((HWND)lParam, &rc);
+ smaddInfo.cbSize = sizeof(SMADD_SHOWSEL3);
+ smaddInfo.hwndTarget = GetDlgItem(hwndDlg, IDC_MESSAGE);
+ smaddInfo.targetMessage = EM_REPLACESEL;
+ smaddInfo.targetWParam = TRUE;
+ smaddInfo.Protocolname = const_cast<char *>(dat->cache->getActiveProto());
+ smaddInfo.Direction = 0;
+ smaddInfo.xPosition = rc.left;
+ smaddInfo.yPosition = rc.top + 24;
+ smaddInfo.hwndParent = hwndContainer;
+ smaddInfo.hContact = hContact;
+ CallService(MS_SMILEYADD_SHOWSELECTION, (WPARAM)hwndContainer, (LPARAM) &smaddInfo);
+ }
+ }
+ break;
+ case IDC_TIME: {
+ RECT rc;
+ HMENU submenu = GetSubMenu(m_pContainer->hMenuContext, 2);
+ int iSelection, isHandled;
+ DWORD dwOldFlags = dat->dwFlags;
+ DWORD dwOldEventIsShown = dat->dwFlagsEx;
+
+ MsgWindowUpdateMenu(dat, submenu, MENU_LOGMENU);
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_TIME), &rc);
+
+ iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL);
+ isHandled = MsgWindowMenuHandler(dat, iSelection, MENU_LOGMENU);
+ return(isHandled);
+ }
+ case IDC_PROTOMENU: {
+ RECT rc;
+ HMENU submenu = GetSubMenu(m_pContainer->hMenuContext, 4);
+ int iSelection;
+ int iOldGlobalSendFormat = PluginConfig.m_SendFormat;
+
+ if (dat->hContact) {
+ int iLocalFormat = M->GetDword(dat->hContact, "sendformat", 0);
+ int iNewLocalFormat = iLocalFormat;
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_PROTOCOL), &rc);
+
+ CheckMenuItem(submenu, ID_MODE_GLOBAL, MF_BYCOMMAND | (!(dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(submenu, ID_MODE_PRIVATE, MF_BYCOMMAND | (dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE ? MF_CHECKED : MF_UNCHECKED));
+
+ /*
+ * formatting menu..
+ */
+
+ CheckMenuItem(submenu, ID_GLOBAL_BBCODE, MF_BYCOMMAND | ((PluginConfig.m_SendFormat) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(submenu, ID_GLOBAL_OFF, MF_BYCOMMAND | ((PluginConfig.m_SendFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED));
+
+ CheckMenuItem(submenu, ID_THISCONTACT_GLOBALSETTING, MF_BYCOMMAND | ((iLocalFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(submenu, ID_THISCONTACT_BBCODE, MF_BYCOMMAND | ((iLocalFormat > 0) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(submenu, ID_THISCONTACT_OFF, MF_BYCOMMAND | ((iLocalFormat == -1) ? MF_CHECKED : MF_UNCHECKED));
+
+ iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL);
+ switch (iSelection) {
+ case ID_MODE_GLOBAL:
+ dat->dwFlagsEx &= ~(MWF_SHOW_SPLITTEROVERRIDE);
+ M->WriteByte(dat->hContact, SRMSGMOD_T, "splitoverride", 0);
+ LoadSplitter(dat);
+ AdjustBottomAvatarDisplay(dat);
+ DM_RecalcPictureSize(dat);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ break;
+ case ID_MODE_PRIVATE:
+ dat->dwFlagsEx |= MWF_SHOW_SPLITTEROVERRIDE;
+ M->WriteByte(dat->hContact, SRMSGMOD_T, "splitoverride", 1);
+ LoadSplitter(dat);
+ AdjustBottomAvatarDisplay(dat);
+ DM_RecalcPictureSize(dat);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ break;
+ case ID_GLOBAL_BBCODE:
+ PluginConfig.m_SendFormat = SENDFORMAT_BBCODE;
+ break;
+ case ID_GLOBAL_OFF:
+ PluginConfig.m_SendFormat = SENDFORMAT_NONE;
+ break;
+ case ID_THISCONTACT_GLOBALSETTING:
+ iNewLocalFormat = 0;
+ break;
+ case ID_THISCONTACT_BBCODE:
+ iNewLocalFormat = SENDFORMAT_BBCODE;
+ break;
+ case ID_THISCONTACT_OFF:
+ iNewLocalFormat = -1;
+ break;
+ }
+ if (iNewLocalFormat == 0)
+ DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "sendformat");
+ else if (iNewLocalFormat != iLocalFormat)
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "sendformat", iNewLocalFormat);
+
+ if (PluginConfig.m_SendFormat != iOldGlobalSendFormat)
+ M->WriteByte(SRMSGMOD_T, "sendformat", (BYTE)PluginConfig.m_SendFormat);
+ if (iNewLocalFormat != iLocalFormat || PluginConfig.m_SendFormat != iOldGlobalSendFormat) {
+ dat->SendFormat = M->GetDword(dat->hContact, "sendformat", PluginConfig.m_SendFormat);
+ if (dat->SendFormat == -1) // per contact override to disable it..
+ dat->SendFormat = 0;
+ M->BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1);
+ }
+ }
+ break;
+ }
+ case IDC_TOGGLETOOLBAR:
+ if (lParam == 1)
+ ApplyContainerSetting(m_pContainer, CNT_NOMENUBAR, m_pContainer->dwFlags & CNT_NOMENUBAR ? 0 : 1, true);
+ else
+ ApplyContainerSetting(m_pContainer, CNT_HIDETOOLBAR, m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1, true);
+ break;
+ case IDC_INFOPANELMENU: {
+ RECT rc;
+ int iSelection;
+
+ HMENU submenu = GetSubMenu(m_pContainer->hMenuContext, 9);
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_NAME), &rc);
+
+ EnableMenuItem(submenu, ID_FAVORITES_ADDCONTACTTOFAVORITES, !dat->cache->isFavorite() ? MF_ENABLED : MF_GRAYED);
+ EnableMenuItem(submenu, ID_FAVORITES_REMOVECONTACTFROMFAVORITES, !dat->cache->isFavorite() ? MF_GRAYED : MF_ENABLED);
+
+ iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL);
+
+ switch(iSelection) {
+ case ID_FAVORITES_ADDCONTACTTOFAVORITES:
+ DBWriteContactSettingByte(dat->hContact, SRMSGMOD_T, "isFavorite", 1);
+ AddContactToFavorites(dat->hContact, dat->cache->getNick(), dat->cache->getActiveProto(), dat->szStatus, dat->wStatus, LoadSkinnedProtoIcon(dat->cache->getActiveProto(), dat->cache->getActiveStatus()), 1, PluginConfig.g_hMenuFavorites);
+ break;
+ case ID_FAVORITES_REMOVECONTACTFROMFAVORITES:
+ DBWriteContactSettingByte(dat->hContact, SRMSGMOD_T, "isFavorite", 0);
+ DeleteMenu(PluginConfig.g_hMenuFavorites, (UINT_PTR)dat->hContact, MF_BYCOMMAND);
+ break;
+ default:
+ break;
+ }
+ dat->cache->updateFavorite();
+ break;
+ }
+ case IDC_SENDMENU: {
+ RECT rc;
+ HMENU submenu = GetSubMenu(m_pContainer->hMenuContext, 3);
+ int iSelection;
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rc);
+ CheckMenuItem(submenu, ID_SENDMENU_SENDTOMULTIPLEUSERS, MF_BYCOMMAND | (dat->sendMode & SMODE_MULTIPLE ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(submenu, ID_SENDMENU_SENDDEFAULT, MF_BYCOMMAND | (dat->sendMode == 0 ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(submenu, ID_SENDMENU_SENDTOCONTAINER, MF_BYCOMMAND | (dat->sendMode & SMODE_CONTAINER ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(submenu, ID_SENDMENU_FORCEANSISEND, MF_BYCOMMAND | (dat->sendMode & SMODE_FORCEANSI ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(submenu, ID_SENDMENU_SENDLATER, MF_BYCOMMAND | (dat->sendMode & SMODE_SENDLATER ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(submenu, ID_SENDMENU_SENDWITHOUTTIMEOUTS, MF_BYCOMMAND | (dat->sendMode & SMODE_NOACK ? MF_CHECKED : MF_UNCHECKED));
+ {
+ const char *szFinalProto = dat->cache->getActiveProto();
+ char szServiceName[128];
+
+ mir_snprintf(szServiceName, 128, "%s/SendNudge", szFinalProto);
+ EnableMenuItem(submenu, ID_SENDMENU_SENDNUDGE, MF_BYCOMMAND | ((ServiceExists(szServiceName) && ServiceExists(MS_NUDGE_SEND)) ? MF_ENABLED : MF_GRAYED));
+ }
+ if (lParam)
+ iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL);
+ else
+ iSelection = HIWORD(wParam);
+
+ switch (iSelection) {
+ case ID_SENDMENU_SENDTOMULTIPLEUSERS:
+ dat->sendMode ^= SMODE_MULTIPLE;
+ if (dat->sendMode & SMODE_MULTIPLE)
+ HWND hwndClist = DM_CreateClist(dat);
+ else {
+ if (IsWindow(GetDlgItem(hwndDlg, IDC_CLIST)))
+ DestroyWindow(GetDlgItem(hwndDlg, IDC_CLIST));
+ }
+ break;
+ case ID_SENDMENU_SENDNUDGE:
+ SendNudge(dat);
+ break;
+ case ID_SENDMENU_SENDDEFAULT:
+ dat->sendMode = 0;
+ break;
+ case ID_SENDMENU_SENDTOCONTAINER:
+ dat->sendMode ^= SMODE_CONTAINER;
+ RedrawWindow(hwndDlg, 0, 0, RDW_ERASENOW|RDW_UPDATENOW);
+ break;
+ case ID_SENDMENU_FORCEANSISEND:
+ dat->sendMode ^= SMODE_FORCEANSI;
+ break;
+ case ID_SENDMENU_SENDLATER:
+ if(sendLater->isAvail())
+ dat->sendMode ^= SMODE_SENDLATER;
+ else
+ CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK|MB_ICONINFORMATION, CTranslator::get(CTranslator::QMGR_ERROR_NOMULTISEND));
+ break;
+ case ID_SENDMENU_SENDWITHOUTTIMEOUTS:
+ dat->sendMode ^= SMODE_NOACK;
+ if (dat->sendMode & SMODE_NOACK)
+ M->WriteByte(dat->hContact, SRMSGMOD_T, "no_ack", 1);
+ else
+ DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "no_ack");
+ break;
+ }
+ M->WriteByte(dat->hContact, SRMSGMOD_T, "no_ack", (BYTE)(dat->sendMode & SMODE_NOACK ? 1 : 0));
+ M->WriteByte(dat->hContact, SRMSGMOD_T, "forceansi", (BYTE)(dat->sendMode & SMODE_FORCEANSI ? 1 : 0));
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE);
+ if (dat->sendMode & SMODE_MULTIPLE || dat->sendMode & SMODE_CONTAINER) {
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER|
+ SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS);
+ RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_ALLCHILDREN);
+ }
+ else {
+ if (IsWindow(GetDlgItem(hwndDlg, IDC_CLIST)))
+ DestroyWindow(GetDlgItem(hwndDlg, IDC_CLIST));
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER|
+ SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS);
+ RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_ALLCHILDREN);
+ }
+ SendMessage(hwndContainer, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ DM_ScrollToBottom(dat, 1, 1);
+ Utils::showDlgControl(hwndDlg, IDC_MULTISPLITTER, (dat->sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE);
+ Utils::showDlgControl(hwndDlg, IDC_CLIST, (dat->sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE);
+ break;
+ }
+ case IDC_TOGGLESIDEBAR: {
+ SendMessage(m_pContainer->hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0);
+ break;
+ }
+ case IDC_PIC: {
+ RECT rc;
+ GetClientRect(hwndDlg, &rc);
+
+ dat->fEditNotesActive = !dat->fEditNotesActive;
+ if(dat->fEditNotesActive) {
+ int iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ if(iLen != 0) {
+ SendMessage(hwndDlg, DM_ACTIVATETOOLTIP, IDC_MESSAGE, (LPARAM)CTranslator::get(CTranslator::GEN_MSG_NO_EDIT_NOTES));
+ dat->fEditNotesActive = false;
+ break;
+ }
+
+ if(!dat->fIsAutosizingInput) {
+ dat->iSplitterSaved = dat->splitterY;
+ dat->splitterY = rc.bottom / 2;
+ SendMessage(hwndDlg, WM_SIZE, 1, 1);
+ }
+
+ DBVARIANT dbv = {0};
+
+ if(0 == M->GetTString(dat->hContact, "UserInfo", "MyNotes", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_MESSAGE, dbv.ptszVal);
+ mir_free(dbv.ptszVal);
+ }
+ }
+ else {
+ int iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE));
+
+ TCHAR *buf = (TCHAR *)mir_alloc((iLen + 2) * sizeof(TCHAR));
+ GetDlgItemText(hwndDlg, IDC_MESSAGE, buf, iLen + 1);
+ M->WriteTString(dat->hContact, "UserInfo", "MyNotes", buf);
+ SetDlgItemText(hwndDlg, IDC_MESSAGE, _T(""));
+
+ if(!dat->fIsAutosizingInput) {
+ dat->splitterY = dat->iSplitterSaved;
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ DM_ScrollToBottom(dat, 0, 1);
+ }
+ }
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER|
+ SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS);
+ RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME|RDW_UPDATENOW|RDW_ALLCHILDREN);
+
+ if(dat->fEditNotesActive)
+ CWarning::show(CWarning::WARN_EDITUSERNOTES, MB_OK|MB_ICONINFORMATION);
+ break;
+ }
+ case IDM_CLEAR:
+ ClearLog(dat);
+ break;
+ case IDC_PROTOCOL: {
+ RECT rc;
+ int iSel = 0;
+
+ HMENU hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) dat->hContact, 0);
+ if(lParam == 0)
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_PROTOCOL/*IDC_NAME*/), &rc);
+ else
+ GetWindowRect((HWND)lParam, &rc);
+ iSel = TrackPopupMenu(hMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL);
+
+ if(iSel)
+ CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(iSel), MPCF_CONTACTMENU), (LPARAM) dat->hContact);
+
+ DestroyMenu(hMenu);
+ break;
+ }
+ // error control
+ case IDC_CANCELSEND:
+ SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_CANCEL, 0);
+ break;
+ case IDC_RETRY:
+ SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_RETRY, 0);
+ break;
+ case IDC_MSGSENDLATER:
+ SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_SENDLATER, 0);
+ break;
+ case IDC_SELFTYPING:
+ if (dat->hContact) {
+ int iCurrentTypingMode = M->GetByte(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M->GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW));
+
+ if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON && iCurrentTypingMode) {
+ DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+ dat->nTypeMode = PROTOTYPE_SELFTYPING_OFF;
+ }
+ M->WriteByte(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, (BYTE)!iCurrentTypingMode);
+ }
+ break;
+ default:
+ return(0);
+ }
+ return(1);
+}
+
+LRESULT TSAPI DM_ContainerCmdHandler(TContainerData *pContainer, UINT cmd, WPARAM wParam, LPARAM lParam)
+{
+ if(!pContainer)
+ return(0);
+
+ HWND hwndDlg = pContainer->hwnd;
+
+ switch(cmd) {
+ case IDC_CLOSE:
+ SendMessage(hwndDlg, WM_SYSCOMMAND, SC_CLOSE, 0);
+ break;
+ case IDC_MINIMIZE:
+ PostMessage(hwndDlg, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+ break;
+ case IDC_MAXIMIZE:
+ SendMessage(hwndDlg, WM_SYSCOMMAND, IsZoomed(hwndDlg) ? SC_RESTORE : SC_MAXIMIZE, 0);
+ break;
+ case IDOK:
+ SendMessage(pContainer->hwndActive, WM_COMMAND, wParam, lParam); // pass the IDOK command to the active child - fixes the "enter not working
+ break;
+ case ID_FILE_SAVEMESSAGELOGAS:
+ SendMessage(pContainer->hwndActive, DM_SAVEMESSAGELOG, 0, 0);
+ break;
+ case ID_FILE_CLOSEMESSAGESESSION:
+ PostMessage(pContainer->hwndActive, WM_CLOSE, 0, 1);
+ break;
+ case ID_FILE_CLOSE:
+ PostMessage(hwndDlg, WM_CLOSE, 0, 1);
+ break;
+ case ID_VIEW_SHOWSTATUSBAR:
+ ApplyContainerSetting(pContainer, CNT_NOSTATUSBAR, pContainer->dwFlags & CNT_NOSTATUSBAR ? 0 : 1, true);
+ break;
+ case ID_VIEW_VERTICALMAXIMIZE:
+ ApplyContainerSetting(pContainer, CNT_VERTICALMAX, pContainer->dwFlags & CNT_VERTICALMAX ? 0 : 1, false);
+ break;
+ case ID_VIEW_BOTTOMTOOLBAR:
+ ApplyContainerSetting(pContainer, CNT_BOTTOMTOOLBAR, pContainer->dwFlags & CNT_BOTTOMTOOLBAR ? 0 : 1, false);
+ M->BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1);
+ return 0;
+ case ID_VIEW_SHOWTOOLBAR:
+ ApplyContainerSetting(pContainer, CNT_HIDETOOLBAR, pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1, false);
+ M->BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1);
+ return 0;
+ case ID_VIEW_SHOWMENUBAR:
+ ApplyContainerSetting(pContainer, CNT_NOMENUBAR, pContainer->dwFlags & CNT_NOMENUBAR ? 0 : 1, true);
+ break;
+ case ID_VIEW_SHOWTITLEBAR:
+ ApplyContainerSetting(pContainer, CNT_NOTITLE, pContainer->dwFlags & CNT_NOTITLE ? 0 : 1, true);
+ break;
+ case ID_VIEW_TABSATBOTTOM:
+ ApplyContainerSetting(pContainer, CNT_TABSBOTTOM, pContainer->dwFlags & CNT_TABSBOTTOM ? 0 : 1, false);
+ break;
+ case ID_VIEW_SHOWMULTISENDCONTACTLIST:
+ SendMessage(pContainer->hwndActive, WM_COMMAND, MAKEWPARAM(IDC_SENDMENU, ID_SENDMENU_SENDTOMULTIPLEUSERS), 0);
+ break;
+ case ID_VIEW_STAYONTOP:
+ SendMessage(hwndDlg, WM_SYSCOMMAND, IDM_STAYONTOP, 0);
+ break;
+ case ID_CONTAINER_CONTAINEROPTIONS:
+ SendMessage(hwndDlg, WM_SYSCOMMAND, IDM_MOREOPTIONS, 0);
+ break;
+ case ID_EVENTPOPUPS_DISABLEALLEVENTPOPUPS:
+ ApplyContainerSetting(pContainer, (CNT_DONTREPORT | CNT_DONTREPORTUNFOCUSED | CNT_DONTREPORTFOCUSED | CNT_ALWAYSREPORTINACTIVE), 0, false);
+ return 0;
+ case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISMINIMIZED:
+ ApplyContainerSetting(pContainer, CNT_DONTREPORT, pContainer->dwFlags & CNT_DONTREPORT ? 0 : 1, false);
+ return 0;
+ case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISUNFOCUSED:
+ ApplyContainerSetting(pContainer, CNT_DONTREPORTUNFOCUSED, pContainer->dwFlags & CNT_DONTREPORTUNFOCUSED ? 0 : 1, false);
+ return 0;
+ case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISFOCUSED:
+ ApplyContainerSetting(pContainer, CNT_DONTREPORTFOCUSED, pContainer->dwFlags & CNT_DONTREPORTFOCUSED ? 0 : 1, false);
+ return 0;
+ case ID_EVENTPOPUPS_SHOWPOPUPSFORALLINACTIVESESSIONS:
+ ApplyContainerSetting(pContainer, CNT_ALWAYSREPORTINACTIVE, pContainer->dwFlags & CNT_ALWAYSREPORTINACTIVE ? 0 : 1, false);
+ return 0;
+ case ID_WINDOWFLASHING_DISABLEFLASHING:
+ ApplyContainerSetting(pContainer, CNT_NOFLASH, 1, false);
+ ApplyContainerSetting(pContainer, CNT_FLASHALWAYS, 0, false);
+ return 0;
+ case ID_WINDOWFLASHING_FLASHUNTILFOCUSED:
+ ApplyContainerSetting(pContainer, CNT_NOFLASH, 0, false);
+ ApplyContainerSetting(pContainer, CNT_FLASHALWAYS, 1, false);
+ return 0;
+ case ID_WINDOWFLASHING_USEDEFAULTVALUES:
+ ApplyContainerSetting(pContainer, (CNT_NOFLASH | CNT_FLASHALWAYS), 0, false);
+ return 0;
+ case ID_OPTIONS_SAVECURRENTWINDOWPOSITIONASDEFAULT: {
+ WINDOWPLACEMENT wp = {0};
+
+ wp.length = sizeof(wp);
+ if (GetWindowPlacement(hwndDlg, &wp)) {
+ M->WriteDword(SRMSGMOD_T, "splitx", wp.rcNormalPosition.left);
+ M->WriteDword(SRMSGMOD_T, "splity", wp.rcNormalPosition.top);
+ M->WriteDword(SRMSGMOD_T, "splitwidth", wp.rcNormalPosition.right - wp.rcNormalPosition.left);
+ M->WriteDword(SRMSGMOD_T, "splitheight", wp.rcNormalPosition.bottom - wp.rcNormalPosition.top);
+ }
+ return 0;
+ }
+ case ID_VIEW_INFOPANEL: {
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+ if(dat) {
+ RECT rc;
+ POINT pt;
+ GetWindowRect(pContainer->hwndActive, &rc);
+ pt.x = rc.left + 10;
+ pt.y = rc.top + dat->Panel->getHeight() - 10;
+ dat->Panel->invokeConfigDialog(pt);
+ }
+ return(0);
+ }
+ /*
+ * commands from the message log popup will be routed to the
+ * message log menu handler
+ */
+ case ID_MESSAGELOGSETTINGS_FORTHISCONTACT:
+ case ID_MESSAGELOGSETTINGS_GLOBAL: {
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
+
+ if(dat) {
+ MsgWindowMenuHandler(dat, (int)LOWORD(wParam), MENU_LOGMENU);
+ return(1);
+ }
+ break;
+ }
+ case ID_HELP_ABOUTTABSRMM:
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), 0, DlgProcAbout, 0);
+ break;
+ default:
+ return(0); // not handled
+ }
+ return(1); // handled
+}
+
+/**
+ * initialize rich edit control (log and edit control) for both MUC and
+ * standard IM session windows.
+ */
+void TSAPI DM_InitRichEdit(TWindowData *dat)
+
+{
+ char* szStreamOut = NULL;
+ SETTEXTEX stx = {ST_DEFAULT, CP_UTF8};
+ COLORREF colour;
+ COLORREF inputcharcolor;
+ CHARFORMAT2A cf2;
+ LOGFONTA lf;
+ int i = 0;
+ bool fIsChat = ((dat->bType == SESSIONTYPE_CHAT) ? true : false);
+ HWND hwndLog = GetDlgItem(dat->hwnd, !fIsChat ? IDC_LOG : IDC_CHAT_LOG);
+ HWND hwndEdit= GetDlgItem(dat->hwnd, !fIsChat ? IDC_MESSAGE : IDC_CHAT_MESSAGE);
+ HWND hwndDlg = dat->hwnd;
+
+ ZeroMemory(&cf2, sizeof(CHARFORMAT2A));
+
+ dat->inputbg = fIsChat ? M->GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR) : dat->pContainer->theme.inputbg;
+ colour = fIsChat ? M->GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR_MUC, SRMSGDEFSET_BKGCOLOUR) : dat->pContainer->theme.bg;
+
+ if(!fIsChat) {
+ if (GetWindowTextLengthA(hwndEdit) > 0)
+ szStreamOut = Message_GetFromStream(hwndEdit, dat, (CP_UTF8 << 16) | (SF_RTFNOOBJS | SFF_PLAINRTF | SF_USECODEPAGE));
+ }
+
+ SendMessage(hwndLog, EM_SETBKGNDCOLOR, 0, colour);
+ SendMessage(hwndEdit, EM_SETBKGNDCOLOR, 0, dat->inputbg);
+
+ if(fIsChat)
+ LoadLogfont(MSGFONTID_MESSAGEAREA, &lf, &inputcharcolor, FONTMODULE);
+ else {
+ lf = dat->pContainer->theme.logFonts[MSGFONTID_MESSAGEAREA];
+ inputcharcolor = dat->pContainer->theme.fontColors[MSGFONTID_MESSAGEAREA];
+ }
+ /*
+ * correct the input area text color to avoid a color from the table of usable bbcode colors
+ */
+ if(!fIsChat) {
+ for (i = 0; i < Utils::rtf_ctable_size; i++) {
+ if (Utils::rtf_ctable[i].clr == inputcharcolor)
+ inputcharcolor = RGB(GetRValue(inputcharcolor), GetGValue(inputcharcolor), GetBValue(inputcharcolor) == 0 ? GetBValue(inputcharcolor) + 1 : GetBValue(inputcharcolor) - 1);
+ }
+ }
+ if(fIsChat) {
+ cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_ITALIC | CFM_BACKCOLOR;
+ cf2.cbSize = sizeof(cf2);
+ cf2.crTextColor = inputcharcolor;
+ cf2.bCharSet = lf.lfCharSet;
+ cf2.crBackColor = dat->inputbg;
+ strncpy(cf2.szFaceName, lf.lfFaceName, LF_FACESIZE);
+ cf2.dwEffects = 0;
+ cf2.wWeight = (WORD)lf.lfWeight;
+ cf2.bPitchAndFamily = lf.lfPitchAndFamily;
+ cf2.yHeight = abs(lf.lfHeight) * 15;
+ SetWindowText(hwndEdit, _T(""));
+ SendMessage(hwndEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2);
+ }
+ else {
+ cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_BOLD | CFM_ITALIC;
+ cf2.cbSize = sizeof(cf2);
+ cf2.crTextColor = inputcharcolor;
+ cf2.bCharSet = lf.lfCharSet;
+ strncpy(cf2.szFaceName, lf.lfFaceName, LF_FACESIZE);
+ cf2.dwEffects = ((lf.lfWeight >= FW_BOLD) ? CFE_BOLD : 0) | (lf.lfItalic ? CFE_ITALIC : 0)|(lf.lfUnderline ? CFE_UNDERLINE : 0)|(lf.lfStrikeOut ? CFE_STRIKEOUT : 0);
+ cf2.wWeight = (WORD)lf.lfWeight;
+ cf2.bPitchAndFamily = lf.lfPitchAndFamily;
+ cf2.yHeight = abs(lf.lfHeight) * 15;
+ SendMessageA(hwndEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2);
+ }
+
+ /*
+ * setup the rich edit control(s)
+ * LOG is always set to RTL, because this is needed for proper bidirectional operation later.
+ * The real text direction is then enforced by the streaming code which adds appropiate paragraph
+ * and textflow formatting commands to the
+ */
+
+ PARAFORMAT2 pf2;
+ ZeroMemory(&pf2, sizeof(PARAFORMAT2));
+
+ pf2.cbSize = sizeof(pf2);
+
+ pf2.wEffects = PFE_RTLPARA;
+ pf2.dwMask = PFM_RTLPARA;
+ if (Utils::FindRTLLocale(dat))
+ SendMessage(hwndEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+ if (!(dat->dwFlags & MWF_LOG_RTL)) {
+ pf2.wEffects = 0;
+ SendMessage(hwndEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+ }
+ SendMessage(hwndEdit, EM_SETLANGOPTIONS, 0, (LPARAM) SendMessage(hwndEdit, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
+ pf2.wEffects = PFE_RTLPARA;
+ pf2.dwMask |= PFM_OFFSET;
+ if (dat->dwFlags & MWF_INITMODE) {
+ pf2.dwMask |= (PFM_RIGHTINDENT | PFM_OFFSETINDENT);
+ pf2.dxStartIndent = 30;
+ pf2.dxRightIndent = 30;
+ }
+ pf2.dxOffset = dat->pContainer->theme.left_indent + 30;
+ if(!fIsChat) {
+ SetWindowText(hwndLog, _T(""));
+ SendMessage(hwndLog, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+ SendMessage(hwndLog, EM_SETLANGOPTIONS, 0, (LPARAM) SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
+ }
+
+ /*
+ * set the scrollbars etc to RTL/LTR (only for manual RTL mode)
+ */
+
+ if(!fIsChat) {
+ if (dat->dwFlags & MWF_LOG_RTL) {
+ SetWindowLongPtr(hwndEdit, GWL_EXSTYLE, GetWindowLongPtr(hwndEdit, GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR);
+ SetWindowLongPtr(hwndLog, GWL_EXSTYLE, GetWindowLongPtr(hwndLog, GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR);
+ } else {
+ SetWindowLongPtr(hwndEdit, GWL_EXSTYLE, GetWindowLongPtr(hwndEdit, GWL_EXSTYLE) &~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR));
+ SetWindowLongPtr(hwndLog, GWL_EXSTYLE, GetWindowLongPtr(hwndLog, GWL_EXSTYLE) &~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR));
+ }
+ SetWindowText(hwndEdit, _T(""));
+ }
+ if (szStreamOut != NULL) {
+ SendMessage(hwndEdit, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szStreamOut);
+ free(szStreamOut);
+ }
+}
+
+/*
+* action and callback procedures for the stock button objects
+*/
+
+static void BTN_StockAction(ButtonItem *item, HWND hwndDlg, struct TWindowData *dat, HWND hwndBtn)
+{
+ if (item->dwStockFlags & SBI_HANDLEBYCLIENT && IsWindow(hwndDlg) && dat)
+ SendMessage(hwndDlg, WM_COMMAND, MAKELONG(item->uId, BN_CLICKED), (LPARAM)hwndBtn);
+ else {
+ switch (item->uId) {
+ case IDC_SBAR_CANCEL:
+ PostMessage(hwndDlg, WM_COMMAND, MAKELONG(IDC_SAVE, BN_CLICKED), (LPARAM)hwndBtn);
+ break;
+ case IDC_SBAR_SLIST:
+ SendMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, WM_LBUTTONUP);
+ break;
+ case IDC_SBAR_FAVORITES: {
+ POINT pt;
+ int iSelection;
+ GetCursorPos(&pt);
+ iSelection = TrackPopupMenu(PluginConfig.g_hMenuFavorites, TPM_RETURNCMD, pt.x, pt.y, 0, PluginConfig.g_hwndHotkeyHandler, NULL);
+ HandleMenuEntryFromhContact(iSelection);
+ break;
+ }
+ case IDC_SBAR_RECENT: {
+ POINT pt;
+ int iSelection;
+ GetCursorPos(&pt);
+ iSelection = TrackPopupMenu(PluginConfig.g_hMenuRecent, TPM_RETURNCMD, pt.x, pt.y, 0, PluginConfig.g_hwndHotkeyHandler, NULL);
+ HandleMenuEntryFromhContact(iSelection);
+ break;
+ }
+ case IDC_SBAR_USERPREFS: {
+ HANDLE hContact = 0;
+ SendMessage(hwndDlg, DM_QUERYHCONTACT, 0, (LPARAM)&hContact);
+ if (hContact != 0)
+ CallService(MS_TABMSG_SETUSERPREFS, (WPARAM)hContact, 0);
+ break;
+ }
+ case IDC_SBAR_TOGGLEFORMAT: {
+ if (dat) {
+ if (IsDlgButtonChecked(hwndDlg, IDC_SBAR_TOGGLEFORMAT) == BST_UNCHECKED) {
+ dat->SendFormat = 0;
+ GetSendFormat(dat, 0);
+ } else {
+ dat->SendFormat = SENDFORMAT_BBCODE;
+ GetSendFormat(dat, 0);
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void BTN_StockCallback(ButtonItem *item, HWND hwndDlg, struct TWindowData *dat, HWND hwndBtn)
+{
+}
+
+/*
+* predefined button objects for customizeable buttons
+*/
+
+static struct SIDEBARITEM sbarItems[] = {
+ 0, 0, 0, 0, 0, _T(""), NULL, NULL, _T("")
+};
+
+int TSAPI BTN_GetStockItem(ButtonItem *item, const TCHAR *szName)
+{
+ int i = 0;
+
+ while (sbarItems[i].uId) {
+ if (!_tcsicmp(sbarItems[i].szName, szName)) {
+ item->uId = sbarItems[i].uId;
+ //item->dwFlags |= BUTTON_ISSIDEBAR;
+ //myGlobals.m_SideBarEnabled = TRUE;
+ if (item->dwFlags & BUTTON_ISSIDEBAR) {
+ if (sbarItems[i].dwFlags & SBI_TOP)
+ item->yOff = 0;
+ else if (sbarItems[i].dwFlags & SBI_BOTTOM)
+ item->yOff = -1;
+ }
+ item->dwStockFlags = sbarItems[i].dwFlags;
+ item->dwFlags = sbarItems[i].dwFlags & SBI_TOGGLE ? item->dwFlags | BUTTON_ISTOGGLE : item->dwFlags & ~BUTTON_ISTOGGLE;
+ item->pfnAction = sbarItems[i].pfnAction;
+ item->pfnCallback = sbarItems[i].pfnCallback;
+ lstrcpyn(item->szTip, sbarItems[i].tszTip, 256);
+ item->szTip[255] = 0;
+ if (sbarItems[i].hIcon) {
+ item->normalGlyphMetrics[0] = (LONG_PTR)sbarItems[i].hIcon;
+ item->dwFlags |= BUTTON_NORMALGLYPHISICON;
+ }
+ if (sbarItems[i].hIconPressed) {
+ item->pressedGlyphMetrics[0] = (LONG_PTR)sbarItems[i].hIconPressed;
+ item->dwFlags |= BUTTON_PRESSEDGLYPHISICON;
+ }
+ if (sbarItems[i].hIconHover) {
+ item->hoverGlyphMetrics[0] = (LONG_PTR)sbarItems[i].hIconHover;
+ item->dwFlags |= BUTTON_HOVERGLYPHISICON;
+ }
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+}
+
+/*
+* set the states of defined database action buttons (only if button is a toggle)
+*/
+
+void TSAPI DM_SetDBButtonStates(HWND hwndChild, struct TWindowData *dat)
+{
+ ButtonItem *buttonItem = dat->pContainer->buttonItems;
+ HANDLE hContact = dat->hContact, hFinalContact = 0;
+ char *szModule, *szSetting;
+ HWND hwndContainer = dat->pContainer->hwnd;;
+
+ while (buttonItem) {
+ BOOL result = FALSE;
+ HWND hWnd = GetDlgItem(hwndContainer, buttonItem->uId);
+
+ if (buttonItem->pfnCallback)
+ buttonItem->pfnCallback(buttonItem, hwndChild, dat, hWnd);
+
+ if (!(buttonItem->dwFlags & BUTTON_ISTOGGLE && buttonItem->dwFlags & BUTTON_ISDBACTION)) {
+ buttonItem = buttonItem->nextItem;
+ continue;
+ }
+ szModule = buttonItem->szModule;
+ szSetting = buttonItem->szSetting;
+ if (buttonItem->dwFlags & BUTTON_DBACTIONONCONTACT || buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION) {
+ if (hContact == 0) {
+ SendMessage(hWnd, BM_SETCHECK, BST_UNCHECKED, 0);
+ buttonItem = buttonItem->nextItem;
+ continue;
+ }
+ if (buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION)
+ szModule = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ hFinalContact = hContact;
+ } else
+ hFinalContact = 0;
+
+ if (buttonItem->type == DBVT_ASCIIZ) {
+ DBVARIANT dbv = {0};
+
+ if (!DBGetContactSettingString(hFinalContact, szModule, szSetting, &dbv)) {
+ result = !strcmp((char *)buttonItem->bValuePush, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ } else {
+ switch (buttonItem->type) {
+ case DBVT_BYTE: {
+ BYTE val = M->GetByte(hFinalContact, szModule, szSetting, 0);
+ result = (val == buttonItem->bValuePush[0]);
+ break;
+ }
+ case DBVT_WORD: {
+ WORD val = DBGetContactSettingWord(hFinalContact, szModule, szSetting, 0);
+ result = (val == *((WORD *) & buttonItem->bValuePush));
+ break;
+ }
+ case DBVT_DWORD: {
+ DWORD val = M->GetDword(hFinalContact, szModule, szSetting, 0);
+ result = (val == *((DWORD *) & buttonItem->bValuePush));
+ break;
+ }
+ }
+ }
+ SendMessage(hWnd, BM_SETCHECK, (WPARAM)result, 0);
+ buttonItem = buttonItem->nextItem;
+ }
+}
+
+LRESULT TSAPI DM_ScrollToBottom(TWindowData *dat, WPARAM wParam, LPARAM lParam)
+{
+ if (dat) {
+
+ if (dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED)
+ return 0;
+
+ if (IsIconic(dat->pContainer->hwnd))
+ dat->dwFlags |= MWF_DEFERREDSCROLL;
+
+ if (dat->hwndIEView) {
+ PostMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0);
+ return 0;
+ } else if (dat->hwndHPP) {
+ SendMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0);
+ return 0;
+ } else {
+ HWND hwnd = GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG);
+ if (lParam)
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+
+ if (wParam == 1 && lParam == 1) {
+ RECT rc;
+ int len;
+
+ GetClientRect(hwnd, &rc);
+ len = GetWindowTextLengthA(hwnd);
+ SendMessage(hwnd, EM_SETSEL, len - 1, len - 1);
+ }
+ if (wParam)
+ SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0);
+ else
+ PostMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0);
+ if (lParam)
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+ }
+ return 0;
+}
+
+static unsigned __stdcall LoadKLThread(LPVOID vParam)
+{
+ HANDLE hContact = reinterpret_cast<HANDLE>(vParam);
+ DBVARIANT dbv = {0};
+
+ LRESULT res = M->GetTString(hContact, SRMSGMOD_T, "locale", &dbv);
+ if (res == 0) {
+ HKL hkl = LoadKeyboardLayout(dbv.ptszVal, 0);
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SETLOCALE, (WPARAM)hContact, (LPARAM)hkl);
+ DBFreeVariant(&dbv);
+ }
+ return(0);
+}
+
+
+LRESULT TSAPI DM_LoadLocale(TWindowData *dat)
+{
+ /*
+ * set locale if saved to contact
+ */
+ if (dat) {
+ if (dat->dwFlags & MWF_WASBACKGROUNDCREATE)
+ return 0;
+
+ if (PluginConfig.m_AutoLocaleSupport) {
+ DBVARIANT dbv;
+ int res;
+ TCHAR szKLName[KL_NAMELENGTH+1];
+ UINT flags = KLF_ACTIVATE;
+
+ res = DBGetContactSettingTString(dat->hContact, SRMSGMOD_T, "locale", &dbv);
+ if (res == 0) {
+
+ /*
+ dat->hkl = LoadKeyboardLayout(dbv.ptszVal, KLF_REPLACELANG | KLF_NOTELLSHELL);
+ GetLocaleID(dat, dbv.ptszVal);
+ PostMessage(dat->hwnd, DM_SETLOCALE, 0, 0);*/
+ DBFreeVariant(&dbv);
+ CloseHandle((HANDLE)mir_forkthreadex(LoadKLThread, reinterpret_cast<void *>(dat->hContact), 16000, NULL));
+ } else {
+ if(!PluginConfig.m_dontUseDefaultKbd) {
+ TCHAR szBuf[20];
+
+ GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, szBuf, 20);
+ mir_sntprintf(szKLName, KL_NAMELENGTH, _T("0000%s"), szBuf);
+ M->WriteTString(dat->hContact, SRMSGMOD_T, "locale", szKLName);
+ }
+ else {
+ GetKeyboardLayoutName(szKLName);
+ M->WriteTString(dat->hContact, SRMSGMOD_T, "locale", szKLName);
+ }
+ /*dat->hkl = LoadKeyboardLayout(szKLName, KLF_NOTELLSHELL | KLF_REPLACELANG);
+ GetLocaleID(dat, szKLName);
+ PostMessage(dat->hwnd, DM_SETLOCALE, 0, 0);*/
+ CloseHandle((HANDLE)mir_forkthreadex(LoadKLThread, reinterpret_cast<void *>(dat->hContact), 16000, NULL));
+ }
+ }
+ }
+ return 0;
+}
+
+LRESULT TSAPI DM_RecalcPictureSize(TWindowData *dat)
+{
+ BITMAP bminfo;
+ HBITMAP hbm;
+
+ if (dat) {
+ hbm = ((dat->Panel->isActive()) && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown);
+
+ if (hbm == 0) {
+ dat->pic.cy = dat->pic.cx = 60;
+ return 0;
+ }
+ GetObject(hbm, sizeof(bminfo), &bminfo);
+ CalcDynamicAvatarSize(dat, &bminfo);
+ SendMessage(dat->hwnd, WM_SIZE, 0, 0);
+ }
+ return 0;
+}
+
+LRESULT TSAPI DM_UpdateLastMessage(const TWindowData *dat)
+{
+ if (dat) {
+ if (dat->pContainer->hwndStatus == 0)
+ return 0;
+ if (dat->pContainer->hwndActive != dat->hwnd)
+ return 0;
+ if (dat->showTyping) {
+ TCHAR szBuf[80];
+
+ mir_sntprintf(szBuf, safe_sizeof(szBuf), CTranslator::get(CTranslator::GEN_MTN_STARTWITHNICK), dat->cache->getNick());
+ SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM) szBuf);
+ SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, (LPARAM) PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]);
+ return 0;
+ }
+ else
+ SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, 0);
+
+ if (dat->lastMessage || dat->pContainer->dwFlags & CNT_UINSTATUSBAR) {
+ TCHAR date[64], time[64];
+
+ if (!(dat->pContainer->dwFlags & CNT_UINSTATUSBAR)) {
+ tmi.printTimeStamp(NULL, dat->lastMessage, _T("d"), date, safe_sizeof(date), 0);
+ if (dat->pContainer->dwFlags & CNT_UINSTATUSBAR && lstrlen(date) > 6)
+ date[lstrlen(date) - 5] = 0;
+ tmi.printTimeStamp(NULL, dat->lastMessage, _T("t"), time, safe_sizeof(time), 0);
+ }
+ if (dat->pContainer->dwFlags & CNT_UINSTATUSBAR) {
+ TCHAR fmt[100];
+ mir_sntprintf(fmt, safe_sizeof(fmt), _T("UID: %s"), dat->cache->getUIN());
+ SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)fmt);
+ } else {
+ TCHAR fmt[100];
+ mir_sntprintf(fmt, safe_sizeof(fmt), CTranslator::get(CTranslator::GEN_SBAR_LASTRECEIVED), date, time);
+ SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM) fmt);
+ }
+ } else
+ SendMessageA(dat->pContainer->hwndStatus, SB_SETTEXTA, 0, (LPARAM) "");
+ }
+ return 0;
+}
+
+/*
+* save current keyboard layout for the given contact
+*/
+
+LRESULT TSAPI DM_SaveLocale(TWindowData *dat, WPARAM wParam, LPARAM lParam)
+{
+ if (dat) {
+ if (PluginConfig.m_AutoLocaleSupport && dat->hContact && dat->pContainer->hwndActive == dat->hwnd) {
+ TCHAR szKLName[KL_NAMELENGTH + 1];
+ if ((HKL)lParam != dat->hkl) {
+ dat->hkl = (HKL)lParam;
+ ActivateKeyboardLayout(dat->hkl, 0);
+ GetKeyboardLayoutName(szKLName);
+ M->WriteTString(dat->hContact, SRMSGMOD_T, "locale", szKLName);
+ GetLocaleID(dat, szKLName);
+ UpdateReadChars(dat);
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+* generic handler for the WM_COPY message in message log/chat history richedit control(s).
+* it filters out the invisible event boundary markers from the text copied to the clipboard.
+*/
+
+LRESULT TSAPI DM_WMCopyHandler(HWND hwnd, WNDPROC oldWndProc, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result = CallWindowProc(oldWndProc, hwnd, WM_COPY, wParam, lParam);
+
+ if (OpenClipboard(hwnd)) {
+ HANDLE hClip = GetClipboardData(CF_UNICODETEXT);
+ if (hClip) {
+ HGLOBAL hgbl;
+ TCHAR *tszLocked;
+ TCHAR *tszText = (TCHAR *)malloc((lstrlen((TCHAR *)hClip) + 2) * sizeof(TCHAR));
+
+ lstrcpy(tszText, (TCHAR *)hClip);
+ Utils::FilterEventMarkers(tszText);
+ EmptyClipboard();
+
+ hgbl = GlobalAlloc(GMEM_MOVEABLE, (lstrlen(tszText) + 1) * sizeof(TCHAR));
+ tszLocked = (TCHAR *)GlobalLock(hgbl);
+ lstrcpy(tszLocked, tszText);
+ GlobalUnlock(hgbl);
+ SetClipboardData(CF_UNICODETEXT, hgbl);
+ if (tszText)
+ free(tszText);
+ }
+ CloseClipboard();
+ }
+ return result;
+}
+
+/*
+* create embedded contact list control
+*/
+
+HWND TSAPI DM_CreateClist(TWindowData *dat)
+{
+ if(!sendLater->isAvail()) {
+ CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK|MB_ICONINFORMATION, CTranslator::get(CTranslator::QMGR_ERROR_NOMULTISEND));
+ dat->sendMode &= ~SMODE_MULTIPLE;
+ return(0);
+ }
+ HWND hwndClist = CreateWindowExA(0, "CListControl", "", WS_TABSTOP | WS_VISIBLE | WS_CHILD | 0x248,
+ 184, 0, 30, 30, dat->hwnd, (HMENU)IDC_CLIST, g_hInst, NULL);
+
+ //MAD: fix for little bug, when following code didn't work (another hack :) )
+ HANDLE hItem;
+ SendMessage(hwndClist, WM_TIMER, 14, 0);
+ //
+ hItem = (HANDLE) SendMessage(hwndClist, CLM_FINDCONTACT, (WPARAM) dat->hContact, 0);
+
+ SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) & ~CLS_EX_TRACKSELECT);
+ SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) | (CLS_EX_NOSMOOTHSCROLLING | CLS_EX_NOTRANSLUCENTSEL));
+ //MAD: show offline contacts in multi-send
+ if (!PluginConfig.m_AllowOfflineMultisend)
+ SetWindowLongPtr(hwndClist, GWL_STYLE, GetWindowLongPtr(hwndClist, GWL_STYLE) | CLS_HIDEOFFLINE);
+ //
+ if (hItem)
+ SendMessage(hwndClist, CLM_SETCHECKMARK, (WPARAM) hItem, 1);
+
+ if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_DISABLEGROUPS && !M->GetByte("CList", "UseGroups", SETTING_USEGROUPS_DEFAULT))
+ SendMessage(hwndClist, CLM_SETUSEGROUPS, (WPARAM) FALSE, 0);
+ else
+ SendMessage(hwndClist, CLM_SETUSEGROUPS, (WPARAM) TRUE, 0);
+ if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_HIDEEMPTYGROUPS && M->GetByte("CList", "HideEmptyGroups", SETTING_USEGROUPS_DEFAULT))
+ SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, (WPARAM) TRUE, 0);
+ else
+ SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, (WPARAM) FALSE, 0);
+ SendMessage(hwndClist, CLM_FIRST + 106, 0, 1);
+ SendMessage(hwndClist, CLM_AUTOREBUILD, 0, 0);
+ if(hwndClist)
+ RedrawWindow(hwndClist, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW);
+ return hwndClist;
+}
+
+LRESULT TSAPI DM_MouseWheelHandler(HWND hwnd, HWND hwndParent, struct TWindowData *mwdat, WPARAM wParam, LPARAM lParam)
+{
+ RECT rc, rc1;
+ POINT pt;
+ TCHITTESTINFO hti;
+ HWND hwndTab;
+ UINT uID = mwdat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG;
+ UINT uIDMsg = mwdat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE;
+
+ GetCursorPos(&pt);
+ GetWindowRect(hwnd, &rc);
+ if (PtInRect(&rc, pt))
+ return 1;
+ if (mwdat->pContainer->dwFlags & CNT_SIDEBAR) {
+ GetWindowRect(GetDlgItem(mwdat->pContainer->hwnd, IDC_SIDEBARUP), &rc);
+ GetWindowRect(GetDlgItem(mwdat->pContainer->hwnd, IDC_SIDEBARDOWN), &rc1);
+ rc.bottom = rc1.bottom;
+ if (PtInRect(&rc, pt)) {
+ short amount = (short)(HIWORD(wParam));
+ SendMessage(mwdat->pContainer->hwnd, WM_COMMAND, MAKELONG(amount > 0 ? IDC_SIDEBARUP : IDC_SIDEBARDOWN, 0), (LPARAM)uIDMsg);
+ return 0;
+ }
+ }
+ if (mwdat->bType == SESSIONTYPE_CHAT) { // scroll nick list by just hovering it
+ RECT rcNicklist;
+ GetWindowRect(GetDlgItem(mwdat->hwnd, IDC_LIST), &rcNicklist);
+ if (PtInRect(&rcNicklist, pt)) {
+ SendMessage(GetDlgItem(mwdat->hwnd, IDC_LIST), WM_MOUSEWHEEL, wParam, lParam);
+ return(0);
+ }
+ }
+ if (mwdat->hwndIEView)
+ GetWindowRect(mwdat->hwndIEView, &rc);
+ else if (mwdat->hwndHPP)
+ GetWindowRect(mwdat->hwndHPP, &rc);
+ else
+ GetWindowRect(GetDlgItem(hwndParent, uID), &rc);
+ if (PtInRect(&rc, pt)) {
+ HWND hwnd = (mwdat->hwndIEView || mwdat->hwndHPP) ? mwdat->hwndIWebBrowserControl : GetDlgItem(hwndParent, uID);
+ short wDirection = (short)HIWORD(wParam);
+
+ if (hwnd == 0)
+ hwnd = WindowFromPoint(pt);
+
+ if (LOWORD(wParam) & MK_SHIFT || M->GetByte("fastscroll", 0)) {
+ if (wDirection < 0)
+ SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), 0);
+ else if (wDirection > 0)
+ SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), 0);
+ } else
+ SendMessage(hwnd, WM_MOUSEWHEEL, wParam, lParam);
+ return 0;
+ }
+ hwndTab = GetDlgItem(mwdat->pContainer->hwnd, IDC_MSGTABS);
+ GetCursorPos(&hti.pt);
+ ScreenToClient(hwndTab, &hti.pt);
+ hti.flags = 0;
+ if (TabCtrl_HitTest(hwndTab, &hti) != -1) {
+ SendMessage(hwndTab, WM_MOUSEWHEEL, wParam, -1);
+ return 0;
+ }
+ return 1;
+}
+
+void TSAPI DM_FreeTheme(TWindowData *dat)
+{
+ if(dat) {
+ if (CMimAPI::m_pfnCloseThemeData) {
+ if(dat->hTheme) {
+ CMimAPI::m_pfnCloseThemeData(dat->hTheme);
+ dat->hTheme = 0;
+ }
+ if(dat->hThemeIP) {
+ CMimAPI::m_pfnCloseThemeData(dat->hThemeIP);
+ dat->hThemeIP = 0;
+ }
+ if(dat->hThemeToolbar) {
+ CMimAPI::m_pfnCloseThemeData(dat->hThemeToolbar);
+ dat->hThemeToolbar = 0;
+ }
+ }
+ }
+}
+
+LRESULT TSAPI DM_ThemeChanged(TWindowData *dat)
+{
+ CSkinItem *item_log = &SkinItems[ID_EXTBKHISTORY];
+ CSkinItem *item_msg = &SkinItems[ID_EXTBKINPUTAREA];
+
+ HWND hwnd = dat->hwnd;
+
+ dat->hTheme = (M->isVSAPIState() && CMimAPI::m_pfnOpenThemeData) ? CMimAPI::m_pfnOpenThemeData(hwnd, L"EDIT") : 0;
+
+ if (dat->bType == SESSIONTYPE_IM) {
+ if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_log->IGNORED))
+ SetWindowLongPtr(GetDlgItem(hwnd, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_LOG), GWL_EXSTYLE) & ~WS_EX_STATICEDGE);
+ if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_msg->IGNORED))
+ SetWindowLongPtr(GetDlgItem(hwnd, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_MESSAGE), GWL_EXSTYLE) & ~WS_EX_STATICEDGE);
+ } else {
+ if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_log->IGNORED)) {
+ SetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_LOG), GWL_EXSTYLE) & ~WS_EX_STATICEDGE);
+ SetWindowLongPtr(GetDlgItem(hwnd, IDC_LIST), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_LIST), GWL_EXSTYLE) & ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
+ }
+ if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_msg->IGNORED))
+ SetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_MESSAGE), GWL_EXSTYLE) & ~WS_EX_STATICEDGE);
+ }
+ dat->hThemeIP = M->isAero() ? CMimAPI::m_pfnOpenThemeData(hwnd, L"ButtonStyle") : 0;
+ dat->hThemeToolbar = (M->isAero() || (!CSkin::m_skinEnabled && M->isVSThemed())) ? CMimAPI::m_pfnOpenThemeData(hwnd, L"REBAR") : 0;
+
+ return 0;
+}
+
+/**
+ * send out message typing notifications (MTN) when the
+ * user is typing/editing text in the messgae input area.
+ */
+void TSAPI DM_NotifyTyping(struct TWindowData *dat, int mode)
+{
+ DWORD protoStatus;
+ DWORD protoCaps;
+ DWORD typeCaps;
+ const char* szProto = 0;
+ HANDLE hContact = 0;
+
+ if (dat && dat->hContact) {
+ DeletePopupsForContact(dat->hContact, PU_REMOVE_ON_TYPE);
+
+ if(dat->bIsMeta){
+ szProto = dat->cache->getActiveProto();
+ hContact = dat->cache->getActiveContact();
+ }
+ else {
+ szProto = dat->szProto;
+ hContact = dat->hContact;
+ }
+
+ /*
+ * editing user notes or preparing a message for queued delivery -> don't send MTN
+ */
+ if(dat->fEditNotesActive || dat->sendMode & SMODE_SENDLATER)
+ return;
+
+ /*
+ * allow supression of sending out TN for the contact (NOTE: for metacontacts, do NOT use the subcontact handle)
+ */
+ if (!M->GetByte(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M->GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)))
+ return;
+
+ if (!dat->szProto) // should not, but who knows...
+ return;
+
+ /*
+ * check status and capabilities of the protocol
+ */
+ protoStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ typeCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0);
+
+ if (!(typeCaps & PF4_SUPPORTTYPING))
+ return;
+ if (protoStatus < ID_STATUS_ONLINE)
+ return;
+
+ /*
+ * check visibility/invisibility lists to not "accidentially" send MTN to contacts who
+ * should not see them (privacy issue)
+ */
+ if (protoCaps & PF1_VISLIST && DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE)
+ return;
+
+ if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0) != ID_STATUS_ONLINE)
+ return;
+
+ /*
+ * don't send to contacts which are not permanently added to the contact list,
+ * unless the option to ignore added status is set.
+ */
+ if (M->GetByte(dat->hContact, "CList", "NotOnList", 0)
+ && !M->GetByte(SRMSGMOD, SRMSGSET_TYPINGUNKNOWN, SRMSGDEFSET_TYPINGUNKNOWN))
+ return;
+ // End user check
+ dat->nTypeMode = mode;
+ CallService(MS_PROTO_SELFISTYPING, (WPARAM) hContact, dat->nTypeMode);
+ }
+}
+
+void TSAPI DM_OptionsApplied(TWindowData *dat, WPARAM wParam, LPARAM lParam)
+{
+ if(dat == 0)
+ return;
+
+ HWND hwndDlg = dat->hwnd;
+ TContainerData *m_pContainer = dat->pContainer;
+
+ dat->szMicroLf[0] = 0;
+ if (!(dat->pContainer->theme.isPrivate)) {
+ LoadThemeDefaults(dat->pContainer);
+ dat->dwFlags = dat->pContainer->theme.dwFlags;
+ }
+ LoadLocalFlags(hwndDlg, dat);
+
+ LoadTimeZone(dat);
+
+ if (dat->hContact && dat->szProto != NULL && dat->bIsMeta) {
+ DWORD dwForcedContactNum = 0;
+ CallService(MS_MC_GETFORCESTATE, (WPARAM)dat->hContact, (LPARAM)&dwForcedContactNum);
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "tabSRMM_forced", dwForcedContactNum);
+ }
+
+ dat->showUIElements = m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1;
+
+ dat->dwFlagsEx = M->GetByte(SRMSGSET_SHOWURLS, SRMSGDEFSET_SHOWURLS) ? MWF_SHOW_URLEVENTS : 0;
+ dat->dwFlagsEx |= M->GetByte(SRMSGSET_SHOWFILES, SRMSGDEFSET_SHOWFILES) ? MWF_SHOW_FILEEVENTS : 0;
+ dat->dwFlagsEx |= M->GetByte(dat->hContact, "splitoverride", 0) ? MWF_SHOW_SPLITTEROVERRIDE : 0;
+ dat->Panel->getVisibility();
+
+ // small inner margins (padding) for the text areas
+
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0));
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3));
+
+ GetSendFormat(dat, 1);
+ SetDialogToType(hwndDlg);
+ SendMessage(hwndDlg, DM_CONFIGURETOOLBAR, 0, 0);
+
+ DM_InitRichEdit(dat);
+ if (hwndDlg == m_pContainer->hwndActive)
+ SendMessage(m_pContainer->hwnd, WM_SIZE, 0, 0);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, FALSE);
+ if (!lParam)
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+
+ ShowWindow(dat->hwndPanelPicParent, PluginConfig.g_bDisableAniAvatars ? SW_HIDE : SW_SHOW);
+ EnableWindow(dat->hwndPanelPicParent, PluginConfig.g_bDisableAniAvatars ? FALSE : TRUE);
+
+ SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0);
+}
+
+
+void TSAPI DM_Typing(TWindowData *dat, bool fForceOff)
+{
+ if(dat == 0)
+ return;
+
+ HWND hwndDlg = dat->hwnd;
+ HWND hwndContainer = dat->pContainer->hwnd;
+ HWND hwndStatus = dat->pContainer->hwndStatus;
+
+ if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - dat->nLastTyping > TIMEOUT_TYPEOFF) {
+ DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+ }
+ if (dat->showTyping == 1) {
+ if (dat->nTypeSecs > 0) {
+ dat->nTypeSecs--;
+ if (GetForegroundWindow() == hwndContainer)
+ SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0);
+ } else {
+ struct TWindowData *dat_active = NULL;
+
+ if(!fForceOff) {
+ dat->showTyping = 2;
+ dat->nTypeSecs = 86400;
+
+ mir_sntprintf(dat->szStatusBar, safe_sizeof(dat->szStatusBar),
+ CTranslator::get(CTranslator::GEN_MTN_STOPPED), dat->cache->getNick());
+ if(hwndStatus && dat->pContainer->hwndActive == hwndDlg)
+ SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM) dat->szStatusBar);
+ }
+ SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0);
+ HandleIconFeedback(dat, (HICON) - 1);
+ dat_active = (struct TWindowData *)GetWindowLongPtr(dat->pContainer->hwndActive, GWLP_USERDATA);
+ if (dat_active && dat_active->bType == SESSIONTYPE_IM)
+ SendMessage(hwndContainer, DM_UPDATETITLE, 0, 0);
+ else
+ SendMessage(hwndContainer, DM_UPDATETITLE, (WPARAM)dat->pContainer->hwndActive, (LPARAM)1);
+ if (!(dat->pContainer->dwFlags & CNT_NOFLASH) && PluginConfig.m_FlashOnMTN)
+ ReflashContainer(dat->pContainer);
+ }
+ } else if(dat->showTyping == 2) {
+ if (dat->nTypeSecs > 0)
+ dat->nTypeSecs--;
+ else {
+ dat->szStatusBar[0] = 0;
+ dat->showTyping = 0;
+ }
+ UpdateStatusBar(dat);
+ }
+ else {
+ if (dat->nTypeSecs > 0) {
+ mir_sntprintf(dat->szStatusBar, safe_sizeof(dat->szStatusBar), CTranslator::get(CTranslator::GEN_MTN_STARTWITHNICK), dat->cache->getNick());
+
+ dat->nTypeSecs--;
+ if (hwndStatus && dat->pContainer->hwndActive == hwndDlg) {
+ SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM) dat->szStatusBar);
+ SendMessage(hwndStatus, SB_SETICON, 0, (LPARAM) PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]);
+ }
+ if (IsIconic(hwndContainer) || GetForegroundWindow() != hwndContainer || GetActiveWindow() != hwndContainer) {
+ SetWindowText(hwndContainer, dat->szStatusBar);
+ dat->pContainer->dwFlags |= CNT_NEED_UPDATETITLE;
+ if (!(dat->pContainer->dwFlags & CNT_NOFLASH) && PluginConfig.m_FlashOnMTN)
+ ReflashContainer(dat->pContainer);
+ }
+ if (dat->pContainer->hwndActive != hwndDlg) {
+ if (dat->mayFlashTab)
+ dat->iFlashIcon = PluginConfig.g_IconTypingEvent;
+ HandleIconFeedback(dat, PluginConfig.g_IconTypingEvent);
+ } else { // active tab may show icon if status bar is disabled
+ if (!hwndStatus) {
+ if (TabCtrl_GetItemCount(GetParent(hwndDlg)) > 1 || !(dat->pContainer->dwFlags & CNT_HIDETABS)) {
+ HandleIconFeedback(dat, PluginConfig.g_IconTypingEvent);
+ }
+ }
+ }
+ if ((GetForegroundWindow() != hwndContainer) || (dat->pContainer->hwndStatus == 0) || (dat->pContainer->hwndActive != hwndDlg))
+ SendMessage(hwndContainer, DM_SETICON, (WPARAM)dat, (LPARAM) PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]);
+ dat->showTyping = 1;
+ }
+ }
+}
+
+/**
+ * sync splitter position for all open sessions.
+ * This cares about private / per container / MUC <> IM splitter syncing and everything.
+ * called from IM and MUC windows via DM_SPLITTERGLOBALEVENT
+ */
+int TSAPI DM_SplitterGlobalEvent(TWindowData *dat, WPARAM wParam, LPARAM lParam)
+{
+ RECT rcWin;
+ short newMessagePos;
+ LONG newPos;
+ TWindowData* srcDat = PluginConfig.lastSPlitterPos.pSrcDat;
+ TContainerData* srcCnt = PluginConfig.lastSPlitterPos.pSrcContainer;
+ bool fCntGlobal = (!dat->pContainer->settings->fPrivate ? true : false);
+
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ if(dat->fIsAutosizingInput)
+ return(0);
+#endif
+
+ GetWindowRect(dat->hwnd, &rcWin);
+
+ if(wParam == 0 && lParam == 0) {
+ if((dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE) && dat != srcDat)
+ return(0);
+
+ if(srcDat->bType == dat->bType)
+ newPos = PluginConfig.lastSPlitterPos.pos;
+ else if(srcDat->bType == SESSIONTYPE_IM && dat->bType == SESSIONTYPE_CHAT)
+ newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im;
+ else if(srcDat->bType == SESSIONTYPE_CHAT && dat->bType == SESSIONTYPE_IM)
+ newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im;
+
+ if(dat == srcDat) {
+ if(dat->bType == SESSIONTYPE_IM) {
+ dat->pContainer->settings->splitterPos = dat->splitterY;
+ if(fCntGlobal) {
+ SaveSplitter(dat);
+ if(PluginConfig.lastSPlitterPos.bSync)
+ g_Settings.iSplitterY = dat->splitterY - DPISCALEY_S(23);
+ }
+ }
+ if(dat->bType == SESSIONTYPE_CHAT) {
+ SESSION_INFO *si = dat->si;
+ if(si) {
+ dat->pContainer->settings->splitterPos = si->iSplitterY + DPISCALEY_S(23);
+ if(fCntGlobal) {
+ g_Settings.iSplitterY = si->iSplitterY;
+ if(PluginConfig.lastSPlitterPos.bSync)
+ M->WriteDword(SRMSGMOD_T, "splitsplity", (DWORD)si->iSplitterY + DPISCALEY_S(23));
+ }
+ }
+ }
+ return(0);
+ }
+
+ if(!fCntGlobal && dat->pContainer != srcCnt)
+ return(0);
+ if(srcCnt->settings->fPrivate && dat->pContainer != srcCnt)
+ return(0);
+
+ if(!PluginConfig.lastSPlitterPos.bSync && dat->bType != srcDat->bType)
+ return(0);
+
+ /*
+ * for inactive sessions, delay the splitter repositioning until they become
+ * active (faster, avoid redraw/resize problems for minimized windows)
+ */
+ if (IsIconic(dat->pContainer->hwnd) || dat->pContainer->hwndActive != dat->hwnd) {
+ dat->dwFlagsEx |= MWF_EX_DELAYEDSPLITTER;
+ dat->wParam = newPos;
+ dat->lParam = PluginConfig.lastSPlitterPos.lParam;
+ return(0);
+ }
+ }
+ else
+ newPos = wParam;
+
+ newMessagePos = (short)rcWin.bottom - (short)newPos;
+
+ if(dat->bType == SESSIONTYPE_IM) {
+ LoadSplitter(dat);
+ AdjustBottomAvatarDisplay(dat);
+ DM_RecalcPictureSize(dat);
+ SendMessage(dat->hwnd, WM_SIZE, 0, 0);
+ DM_ScrollToBottom(dat, 1,1);
+ if(dat != srcDat)
+ CSkin::UpdateToolbarBG(dat);
+ }
+ else {
+ SESSION_INFO *si = dat->si;
+ if(si) {
+ si->iSplitterY = g_Settings.iSplitterY;
+ SendMessage(dat->hwnd, WM_SIZE, 0, 0);
+ }
+ }
+ return(0);
+}
+
+/**
+ * incoming event handler
+ */
+
+void TSAPI DM_EventAdded(TWindowData *dat, WPARAM wParam, LPARAM lParam)
+{
+ TContainerData *m_pContainer = dat->pContainer;
+ DBEVENTINFO dbei = {0};
+ DWORD dwTimestamp = 0;
+ BOOL fIsStatusChangeEvent = FALSE, fIsNotifyEvent = FALSE;
+ HWND hwndDlg = dat->hwnd, hwndContainer = m_pContainer->hwnd, hwndTab = GetParent(dat->hwnd);
+
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = 0;
+
+ CallService(MS_DB_EVENT_GET, lParam, (LPARAM) & dbei);
+ if (dat->hDbEventFirst == NULL)
+ dat->hDbEventFirst = (HANDLE) lParam;
+
+ fIsStatusChangeEvent = IsStatusEvent(dbei.eventType);
+ fIsNotifyEvent = (dbei.eventType == EVENTTYPE_MESSAGE || dbei.eventType == EVENTTYPE_FILE);
+
+ if (!fIsStatusChangeEvent) {
+ int heFlags = HistoryEvents_GetFlags(dbei.eventType);
+ if (heFlags != -1 && !(heFlags & HISTORYEVENTS_FLAG_DEFAULT) && !(heFlags & HISTORYEVENTS_FLAG_FLASH_MSG_WINDOW))
+ fIsStatusChangeEvent = TRUE;
+ }
+
+ if (dbei.eventType == EVENTTYPE_MESSAGE && (dbei.flags & DBEF_READ))
+ return;
+
+ if (DbEventIsShown(dat, &dbei)) {
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT))) {
+ dat->lastMessage = dbei.timestamp;
+ dat->szStatusBar[0] = 0;
+ if(dat->showTyping) {
+ dat->nTypeSecs = 0;
+ DM_Typing(dat, true);
+ dat->showTyping = 0;
+ }
+ HandleIconFeedback(dat, (HICON)-1);
+ if(m_pContainer->hwndStatus)
+ PostMessage(hwndDlg, DM_UPDATELASTMESSAGE, 0, 0);
+ }
+ /*
+ * set the message log divider to mark new (maybe unseen) messages, if the container has
+ * been minimized or in the background.
+ */
+ if (!(dbei.flags & DBEF_SENT) && !fIsStatusChangeEvent) {
+
+ if (PluginConfig.m_DividersUsePopupConfig && PluginConfig.m_UseDividers) {
+ if (!MessageWindowOpened((WPARAM)dat->hContact, 0))
+ SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0);
+ } else if (PluginConfig.m_UseDividers) {
+ if ((GetForegroundWindow() != hwndContainer || GetActiveWindow() != hwndContainer))
+ SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0);
+ else {
+ if (m_pContainer->hwndActive != hwndDlg)
+ SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0);
+ }
+ }
+ tabSRMM_ShowPopup(wParam, lParam, dbei.eventType, m_pContainer->fHidden ? 0 : 1, m_pContainer, hwndDlg, dat->cache->getActiveProto(), dat);
+ if(IsWindowVisible(m_pContainer->hwnd))
+ m_pContainer->fHidden = false;
+ }
+ dat->cache->updateStats(TSessionStats::UPDATE_WITH_LAST_RCV, 0);
+
+ if ((HANDLE) lParam != dat->hDbEventFirst) {
+ HANDLE nextEvent = (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, lParam, 0);
+ if (1 || nextEvent == 0) {
+ if (!(dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED))
+ SendMessage(hwndDlg, DM_APPENDTOLOG, lParam, 0);
+ else {
+ TCHAR szBuf[100];
+
+ if (dat->iNextQueuedEvent >= dat->iEventQueueSize) {
+ dat->hQueuedEvents = (HANDLE *)realloc(dat->hQueuedEvents, (dat->iEventQueueSize + 10) * sizeof(HANDLE));
+ dat->iEventQueueSize += 10;
+ }
+ dat->hQueuedEvents[dat->iNextQueuedEvent++] = (HANDLE)lParam;
+ mir_sntprintf(szBuf, safe_sizeof(szBuf), CTranslator::get(CTranslator::GEN_MSG_LOGFROZENQUEUED),
+ dat->iNextQueuedEvent);
+ SetDlgItemText(hwndDlg, IDC_LOGFROZENTEXT, szBuf);
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_LOGFROZENTEXT), NULL, NULL, RDW_INVALIDATE);
+ }
+ } else
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ } else
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+
+ // handle tab flashing
+
+ if ((TabCtrl_GetCurSel(hwndTab) != dat->iTabID) && !(dbei.flags & DBEF_SENT) && !fIsStatusChangeEvent) {
+ switch (dbei.eventType) {
+ case EVENTTYPE_MESSAGE:
+ dat->iFlashIcon = PluginConfig.g_IconMsgEvent;
+ break;
+ case EVENTTYPE_FILE:
+ dat->iFlashIcon = PluginConfig.g_IconFileEvent;
+ break;
+ default:
+ dat->iFlashIcon = PluginConfig.g_IconMsgEvent;
+ break;
+ }
+ SetTimer(hwndDlg, TIMERID_FLASHWND, TIMEOUT_FLASHWND, NULL);
+ dat->mayFlashTab = TRUE;
+ }
+ /*
+ * try to flash the contact list...
+ */
+
+ FlashOnClist(hwndDlg, dat, (HANDLE)lParam, &dbei);
+ /*
+ * autoswitch tab if option is set AND container is minimized (otherwise, we never autoswitch)
+ * never switch for status changes...
+ */
+ if (!(dbei.flags & DBEF_SENT) && !fIsStatusChangeEvent) {
+ if(PluginConfig.haveAutoSwitch() && m_pContainer->hwndActive != hwndDlg) {
+ if ((IsIconic(hwndContainer) && !IsZoomed(hwndContainer)) || (PluginConfig.m_HideOnClose && !IsWindowVisible(m_pContainer->hwnd))) {
+ int iItem = GetTabIndexFromHWND(GetParent(hwndDlg), hwndDlg);
+ if (iItem >= 0) {
+ TabCtrl_SetCurSel(GetParent(hwndDlg), iItem);
+ ShowWindow(m_pContainer->hwndActive, SW_HIDE);
+ m_pContainer->hwndActive = hwndDlg;
+ SendMessage(hwndContainer, DM_UPDATETITLE, (WPARAM)dat->hContact, 0);
+ m_pContainer->dwFlags |= CNT_DEFERREDTABSELECT;
+ }
+ }
+ }
+ }
+ /*
+ * flash window if it is not focused
+ */
+ if ((GetActiveWindow() != hwndContainer || GetForegroundWindow() != hwndContainer || dat->pContainer->hwndActive != hwndDlg) && !(dbei.flags & DBEF_SENT) && !fIsStatusChangeEvent) {
+ if (!(m_pContainer->dwFlags & CNT_NOFLASH) && (GetActiveWindow() != hwndContainer || GetForegroundWindow() != hwndContainer))
+ FlashContainer(m_pContainer, 1, 0);
+ SendMessage(hwndContainer, DM_SETICON, (WPARAM)dat, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE));
+ m_pContainer->dwFlags |= CNT_NEED_UPDATETITLE;
+ }
+ /*
+ * play a sound
+ */
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT)))
+ PostMessage(hwndDlg, DM_PLAYINCOMINGSOUND, 0, 0);
+
+ if(dat->pWnd)
+ dat->pWnd->Invalidate();
+ }
+}
+
+void TSAPI DM_HandleAutoSizeRequest(TWindowData *dat, REQRESIZE* rr)
+{
+ if(dat && rr && GetForegroundWindow() == dat->pContainer->hwnd) {
+ if(dat->fIsAutosizingInput && dat->iInputAreaHeight != -1) {
+ LONG heightLimit = M->GetDword("autoSplitMinLimit", 0);
+ LONG iNewHeight = rr->rc.bottom - rr->rc.top;
+
+ if(CSkin::m_skinEnabled && !SkinItems[ID_EXTBKINPUTAREA].IGNORED)
+ iNewHeight += (SkinItems[ID_EXTBKINPUTAREA].MARGIN_TOP + SkinItems[ID_EXTBKINPUTAREA].MARGIN_BOTTOM - 2);
+
+ if(heightLimit && iNewHeight < heightLimit)
+ iNewHeight = heightLimit;
+
+ if(iNewHeight != dat->iInputAreaHeight) {
+ RECT rc;
+
+ GetClientRect(dat->hwnd, &rc);
+ LONG cy = rc.bottom - rc.top;
+ LONG panelHeight = (dat->Panel->isActive() ? dat->Panel->getHeight() : 0);
+
+ if(iNewHeight > (cy - panelHeight) / 2)
+ iNewHeight = (cy - panelHeight) / 2;
+
+ if(dat->bType == SESSIONTYPE_IM) {
+ dat->dynaSplitter = rc.bottom - (rc.bottom - iNewHeight + DPISCALEY_S(2));
+ if(dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR)
+ dat->dynaSplitter += DPISCALEY_S(22);
+ dat->splitterY = dat->dynaSplitter + DPISCALEY_S(34);
+ DM_RecalcPictureSize(dat);
+ }
+ else if (dat->si) {
+ dat->si->iSplitterY = (rc.bottom - (rc.bottom - iNewHeight + DPISCALEY_S(3))) + DPISCALEY_S(34);
+ if(!(dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR))
+ dat->si->iSplitterY -= DPISCALEY_S(22);
+ SendMessage(dat->hwnd, WM_SIZE, 0, 0);
+ }
+ dat->iInputAreaHeight = iNewHeight;
+ CSkin::UpdateToolbarBG(dat);
+ DM_ScrollToBottom(dat, 1, 0);
+ }
+ }
+ }
+}
+
+void TSAPI DM_UpdateTitle(TWindowData *dat, WPARAM wParam, LPARAM lParam)
+{
+ TCHAR newtitle[128];
+ TCHAR* pszNewTitleEnd;
+ TCHAR newcontactname[128];
+ TCITEM item;
+ DWORD dwOldIdle = dat->idle;
+ const char* szActProto = 0;
+ HANDLE hActContact = 0;
+
+ HWND hwndDlg = dat->hwnd;
+ HWND hwndTab = GetParent(hwndDlg);
+ HWND hwndContainer = dat->pContainer->hwnd;
+ TContainerData* m_pContainer = dat->pContainer;
+
+ ZeroMemory((void *)newcontactname, sizeof(newcontactname));
+ dat->szStatus[0] = 0;
+
+ pszNewTitleEnd = _T("Message Session");
+
+ if (dat->iTabID == -1)
+ return;
+
+ ZeroMemory((void *)&item, sizeof(item));
+ if (dat->hContact) {
+ int iHasName;
+ TCHAR fulluin[256];
+ const TCHAR* szNick = dat->cache->getNick();
+
+ if (dat->szProto) {
+
+ szActProto = dat->cache->getActiveProto();
+ hActContact = dat->hContact;
+
+ iHasName = (dat->cache->getUIN()[0] != 0);
+ dat->idle = dat->cache->getIdleTS();
+ dat->dwFlagsEx = dat->idle ? dat->dwFlagsEx | MWF_SHOW_ISIDLE : dat->dwFlagsEx & ~MWF_SHOW_ISIDLE;
+
+ dat->wStatus = dat->cache->getStatus();
+ mir_sntprintf(dat->szStatus, safe_sizeof(dat->szStatus), _T("%s"), (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, dat->szProto == NULL ? ID_STATUS_OFFLINE : dat->wStatus, GSMDF_TCHAR));
+
+ if (lParam != 0) {
+ if (PluginConfig.m_CutContactNameOnTabs)
+ CutContactName(szNick, newcontactname, safe_sizeof(newcontactname));
+ else
+ lstrcpyn(newcontactname, szNick, safe_sizeof(newcontactname));
+
+ Utils::DoubleAmpersands(newcontactname);
+
+ if (lstrlen(newcontactname) != 0 && dat->szStatus != NULL) {
+ if (PluginConfig.m_StatusOnTabs)
+ mir_sntprintf(newtitle, 127, _T("%s (%s)"), newcontactname, dat->szStatus);
+ else
+ mir_sntprintf(newtitle, 127, _T("%s"), newcontactname);
+ } else
+ mir_sntprintf(newtitle, 127, _T("%s"), _T("Forward"));
+
+ item.mask |= TCIF_TEXT;
+ }
+ SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0);
+ if (dat->bIsMeta)
+ mir_sntprintf(fulluin, safe_sizeof(fulluin),
+ CTranslator::get(CTranslator::GEN_MSG_UINCOPY),
+ iHasName ? dat->cache->getUIN() : CTranslator::get(CTranslator::GEN_MSG_NOUIN));
+ else
+ mir_sntprintf(fulluin, safe_sizeof(fulluin),
+ CTranslator::get(CTranslator::GEN_MSG_UINCOPY_NOMC),
+ iHasName ? dat->cache->getUIN() : CTranslator::get(CTranslator::GEN_MSG_NOUIN));
+
+ SendMessage(GetDlgItem(hwndDlg, IDC_NAME), BUTTONADDTOOLTIP, /*iHasName ?*/ (WPARAM)fulluin /*: (WPARAM)_T("")*/, 0);
+ }
+ } else
+ lstrcpyn(newtitle, pszNewTitleEnd, safe_sizeof(newtitle));
+
+ if (dat->idle != dwOldIdle || lParam != 0) {
+
+ if (item.mask & TCIF_TEXT) {
+ item.pszText = newtitle;
+ _tcsncpy(dat->newtitle, newtitle, safe_sizeof(dat->newtitle));
+ dat->newtitle[127] = 0;
+ item.cchTextMax = 127;
+ if(dat->pWnd)
+ dat->pWnd->updateTitle(dat->cache->getNick());
+ }
+ if (dat->iTabID >= 0) {
+ TabCtrl_SetItem(hwndTab, dat->iTabID, &item);
+ if(m_pContainer->dwFlags & CNT_SIDEBAR)
+ m_pContainer->SideBar->updateSession(dat);
+ }
+ if (m_pContainer->hwndActive == hwndDlg && lParam)
+ SendMessage(hwndContainer, DM_UPDATETITLE, (WPARAM)dat->hContact, 0);
+
+ UpdateTrayMenuState(dat, TRUE);
+ if (dat->cache->isFavorite())
+ AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus,
+ LoadSkinnedProtoIcon(dat->cache->getActiveProto(), dat->cache->getActiveStatus()), 0, PluginConfig.g_hMenuFavorites);
+ if (dat->cache->isRecent()) {
+ AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus,
+ LoadSkinnedProtoIcon(dat->cache->getActiveProto(), dat->cache->getActiveStatus()), 0, PluginConfig.g_hMenuRecent);
+ }
+
+ dat->Panel->Invalidate();
+ if(dat->pWnd)
+ dat->pWnd->Invalidate();
+
+ if (PluginConfig.g_FlashAvatarAvail) {
+ FLASHAVATAR fa = {0};
+
+ fa.hContact = dat->hContact;
+ fa.hWindow = 0;
+ fa.id = 25367;
+ fa.cProto = dat->szProto;
+
+ CallService(MS_FAVATAR_GETINFO, (WPARAM)&fa, 0);
+ dat->hwndFlash = fa.hWindow;
+ if (dat->hwndFlash) {
+ bool isInfoPanel = dat->Panel->isActive();
+ SetParent(dat->hwndFlash, isInfoPanel ? dat->hwndPanelPicParent : GetDlgItem(hwndDlg, IDC_CONTACTPIC));
+ }
+ }
+ }
+ // care about MetaContacts and update the statusbar icon with the currently "most online" contact...
+ if (dat->bIsMeta) {
+ PostMessage(hwndDlg, DM_UPDATEMETACONTACTINFO, 0, 0);
+ PostMessage(hwndDlg, DM_OWNNICKCHANGED, 0, 0);
+ if (m_pContainer->dwFlags & CNT_UINSTATUSBAR)
+ DM_UpdateLastMessage(dat);
+ }
+}
+
+/*
+* status icon stuff (by sje, used for indicating encryption status in the status bar
+* this is now part of the message window api
+*/
+
+static HANDLE hHookIconPressedEvt;
+struct TStatusBarIconNode *status_icon_list = 0;
+int status_icon_list_size = 0;
+
+static INT_PTR SI_AddStatusIcon(WPARAM wParam, LPARAM lParam)
+{
+ StatusIconData *sid = (StatusIconData *)lParam;
+ struct TStatusBarIconNode *siln = (struct TStatusBarIconNode *)mir_alloc(sizeof(struct TStatusBarIconNode));
+
+ siln->sid.cbSize = sid->cbSize;
+ siln->sid.szModule = mir_strdup(sid->szModule);
+ siln->sid.dwId = sid->dwId;
+ siln->sid.hIcon = sid->hIcon;
+ siln->sid.hIconDisabled = sid->hIconDisabled;
+ siln->sid.flags = sid->flags;
+ if (sid->szTooltip) siln->sid.szTooltip = mir_strdup(sid->szTooltip);
+ else siln->sid.szTooltip = 0;
+
+ siln->next = status_icon_list;
+ status_icon_list = siln;
+ status_icon_list_size++;
+
+ M->BroadcastMessage(DM_STATUSICONCHANGE, 0, 0);
+ return 0;
+}
+
+static INT_PTR SI_RemoveStatusIcon(WPARAM wParam, LPARAM lParam)
+{
+ StatusIconData *sid = (StatusIconData *)lParam;
+ struct TStatusBarIconNode *current = status_icon_list, *prev = 0;
+
+ while (current) {
+ if (strcmp(current->sid.szModule, sid->szModule) == 0 && current->sid.dwId == sid->dwId) {
+ if (prev) prev->next = current->next;
+ else status_icon_list = current->next;
+
+ status_icon_list_size--;
+
+ mir_free(current->sid.szModule);
+ DestroyIcon(current->sid.hIcon);
+ if (current->sid.hIconDisabled) DestroyIcon(current->sid.hIconDisabled);
+ if (current->sid.szTooltip) mir_free(current->sid.szTooltip);
+ mir_free(current);
+ M->BroadcastMessage(DM_STATUSICONCHANGE, 0, 0);
+ return 0;
+ }
+
+ prev = current;
+ current = current->next;
+ }
+ return 1;
+}
+
+static void SI_RemoveAllStatusIcons(void)
+{
+ struct TStatusBarIconNode *current;
+
+ while (status_icon_list) {
+ current = status_icon_list;
+ status_icon_list = status_icon_list->next;
+ status_icon_list_size--;
+
+ mir_free(current->sid.szModule);
+ DestroyIcon(current->sid.hIcon);
+ if (current->sid.hIconDisabled) DestroyIcon(current->sid.hIconDisabled);
+ if (current->sid.szTooltip) mir_free(current->sid.szTooltip);
+ mir_free(current);
+ }
+ M->BroadcastMessage(DM_STATUSICONCHANGE, 0, 0);
+}
+
+static INT_PTR SI_ModifyStatusIcon(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)wParam;
+
+ StatusIconData *sid = (StatusIconData *)lParam;
+ struct TStatusBarIconNode *current = status_icon_list;
+
+ while (current) {
+ if (strcmp(current->sid.szModule, sid->szModule) == 0 && current->sid.dwId == sid->dwId) {
+ if (!hContact) {
+ current->sid.flags = sid->flags;
+ if (sid->hIcon) {
+ DestroyIcon(current->sid.hIcon);
+ current->sid.hIcon = sid->hIcon;
+ }
+ if (sid->hIconDisabled) {
+ DestroyIcon(current->sid.hIconDisabled);
+ current->sid.hIconDisabled = sid->hIconDisabled;
+ }
+ if (sid->szTooltip) {
+ if (current->sid.szTooltip) mir_free(current->sid.szTooltip);
+ current->sid.szTooltip = mir_strdup(sid->szTooltip);
+ }
+
+ M->BroadcastMessage(DM_STATUSICONCHANGE, 0, 0);
+ } else {
+ char buff[256];
+ HWND hwnd;
+ if (!(sid->flags&MBF_OWNERSTATE)) {
+ sprintf(buff, "SRMMStatusIconFlags%d", (int)sid->dwId);
+ M->WriteByte(hContact, sid->szModule, buff, (BYTE)sid->flags);
+ }
+ if ((hwnd = M->FindWindow(hContact))) {
+ if (sid->flags&MBF_OWNERSTATE) {
+
+ struct TStatusBarIconNode *siln = NULL;
+ struct TWindowData *dat = (struct TWindowData *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ struct TStatusBarIconNode *psi = dat->pSINod;
+ while (psi) {
+ if (strcmp(psi->sid.szModule, sid->szModule) == 0 && psi->sid.dwId == sid->dwId) {
+ siln = psi;
+ break;
+ }
+ psi = psi->next;
+ }
+ if (!siln) {
+ siln = (struct TStatusBarIconNode *)mir_alloc(sizeof(struct TStatusBarIconNode));
+ siln->sid.szModule = mir_strdup(sid->szModule);
+ siln->sid.dwId = sid->dwId;
+ siln->sid.hIcon = sid->hIcon;
+ siln->sid.hIconDisabled = sid->hIconDisabled;
+ siln->sid.flags = sid->flags;
+
+ if (sid->szTooltip) siln->sid.szTooltip = mir_strdup(sid->szTooltip);
+ else siln->sid.szTooltip = 0;
+
+ siln->next = dat->pSINod;
+ dat->pSINod = siln;
+ } else {
+ siln->sid.hIcon = sid->hIcon;
+ siln->sid.hIconDisabled = sid->hIconDisabled;
+ siln->sid.flags = sid->flags;
+ if (siln->sid.szTooltip) mir_free(siln->sid.szTooltip);
+
+ if (sid->szTooltip) siln->sid.szTooltip = mir_strdup(sid->szTooltip);
+ else siln->sid.szTooltip = 0;
+
+ }
+
+
+ PostMessage(hwnd, DM_STATUSICONCHANGE, 0, 0);
+ } else
+ PostMessage(hwnd, DM_STATUSICONCHANGE, 0, 0);
+ }
+ }
+ return 0;
+ }
+ current = current->next;
+ }
+ return 1;
+}
+
+void DrawStatusIcons(struct TWindowData *dat, HDC hDC, RECT r, int gap)
+{
+ TStatusBarIconNode* current = status_icon_list;
+ HICON hIcon = NULL;
+ char buff[256];
+ int flags;
+ int x = r.left;
+ LONG cx_icon = PluginConfig.m_smcxicon;
+ LONG cy_icon = PluginConfig.m_smcyicon;
+ LONG y = (r.top + r.bottom - cx_icon) >> 1;
+
+ SetBkMode(hDC, TRANSPARENT);
+ while (current) {
+ if (current->sid.flags&MBF_OWNERSTATE) {
+ struct TStatusBarIconNode *currentSIN = dat->pSINod;
+ flags = current->sid.flags;
+ hIcon = current->sid.hIcon;
+ while (currentSIN) {
+ if (strcmp(currentSIN->sid.szModule, current->sid.szModule) == 0 && currentSIN->sid.dwId == current->sid.dwId) {
+ flags = currentSIN->sid.flags;
+ hIcon = currentSIN->sid.hIcon;
+ break;
+ }
+ currentSIN = currentSIN->next;
+ }
+ } else {
+ sprintf(buff, "SRMMStatusIconFlags%d", (int)current->sid.dwId);
+ flags = M->GetByte(dat->hContact, current->sid.szModule, buff, current->sid.flags);
+ }
+
+ if (!(flags & MBF_HIDDEN)) {
+ if (!(flags&MBF_OWNERSTATE) && (flags & MBF_DISABLED) && current->sid.hIconDisabled)
+ hIcon = current->sid.hIconDisabled;
+ else if (!(flags&MBF_OWNERSTATE))
+ hIcon = current->sid.hIcon;
+
+ if (flags & MBF_DISABLED && current->sid.hIconDisabled == (HICON)0)
+ CSkin::DrawDimmedIcon(hDC, x, y, cx_icon, cy_icon, hIcon, 50);
+ else
+ DrawIconEx(hDC, x, y, hIcon, 16, 16, 0, NULL, DI_NORMAL);
+
+ x += 16 + gap;
+ }
+ current = current->next;
+ }
+ DrawIconEx(hDC, x, y, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_SOUNDS],
+ cx_icon, cy_icon, 0, NULL, DI_NORMAL);
+
+ DrawIconEx(hDC, x, y, dat->pContainer->dwFlags & CNT_NOSOUND ?
+ PluginConfig.g_iconOverlayDisabled : PluginConfig.g_iconOverlayEnabled,
+ cx_icon, cy_icon, 0, NULL, DI_NORMAL);
+
+ x += (cx_icon + gap);
+
+ if (dat->bType == SESSIONTYPE_IM) {
+ DrawIconEx(hDC, x, y,
+ PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], cx_icon, cy_icon, 0, NULL, DI_NORMAL);
+ DrawIconEx(hDC, x, y, M->GetByte(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M->GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)) ?
+ PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled, cx_icon, cy_icon, 0, NULL, DI_NORMAL);
+ }
+ else
+ CSkin::DrawDimmedIcon(hDC, x, y, cx_icon, cy_icon,
+ PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], 50);
+
+ x += (cx_icon + gap);
+ DrawIconEx(hDC, x, y, PluginConfig.g_sideBarIcons[0], cx_icon, cy_icon, 0, NULL, DI_NORMAL);
+}
+
+void SI_CheckStatusIconClick(struct TWindowData *dat, HWND hwndFrom, POINT pt, RECT r, int gap, int code)
+{
+ StatusIconClickData sicd;
+ struct TStatusBarIconNode *current = status_icon_list;
+ struct TStatusBarIconNode *clicked = NULL;
+
+ unsigned int iconNum = (pt.x - (r.left + 0)) / (PluginConfig.m_smcxicon + gap);
+ unsigned int list_icons = 0;
+ char buff[100];
+ DWORD flags;
+
+ if (dat && (code == NM_CLICK || code == NM_RCLICK)) {
+ POINT ptScreen;
+
+ GetCursorPos(&ptScreen);
+ if (!PtInRect(&rcLastStatusBarClick, ptScreen))
+ return;
+ }
+ while (current && dat) {
+ if (current->sid.flags&MBF_OWNERSTATE) {
+ struct TStatusBarIconNode *currentSIN = dat->pSINod;
+ flags = current->sid.flags;
+ while (currentSIN) {
+ if (strcmp(currentSIN->sid.szModule, current->sid.szModule) == 0 && currentSIN->sid.dwId == current->sid.dwId) {
+ flags = currentSIN->sid.flags;
+ break;
+ }
+ currentSIN = currentSIN->next;
+ }
+ } else {
+ sprintf(buff, "SRMMStatusIconFlags%d", (int)current->sid.dwId);
+ flags = M->GetByte(dat->hContact, current->sid.szModule, buff, current->sid.flags);
+ }
+ if (!(flags & MBF_HIDDEN)) {
+ if (list_icons++ == iconNum)
+ clicked = current;
+ }
+ current = current->next;
+ }
+
+ if ((int)iconNum == list_icons && code != NM_RCLICK) {
+ if (GetKeyState(VK_SHIFT) & 0x8000) {
+ struct TContainerData *piContainer = pFirstContainer;
+
+ while (piContainer) {
+ piContainer->dwFlags = ((dat->pContainer->dwFlags & CNT_NOSOUND) ? piContainer->dwFlags | CNT_NOSOUND : piContainer->dwFlags & ~CNT_NOSOUND);
+ InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE);
+ piContainer = piContainer->pNextContainer;
+ }
+ } else {
+ dat->pContainer->dwFlags ^= CNT_NOSOUND;
+ InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE);
+ }
+ } else if ((int)iconNum == list_icons + 1 && code != NM_RCLICK && dat->bType == SESSIONTYPE_IM) {
+ SendMessage(dat->pContainer->hwndActive, WM_COMMAND, IDC_SELFTYPING, 0);
+ InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE);
+ } else if ((int)iconNum == list_icons + 2) {
+ if(code == NM_CLICK)
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, WM_LBUTTONUP);
+ else if(code == NM_RCLICK)
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, WM_RBUTTONUP);
+ } else if (clicked) {
+ sicd.cbSize = sizeof(StatusIconClickData);
+ GetCursorPos(&sicd.clickLocation);
+ sicd.dwId = clicked->sid.dwId;
+ sicd.szModule = clicked->sid.szModule;
+ sicd.flags = (code == NM_RCLICK ? MBCF_RIGHTBUTTON : 0);
+ NotifyEventHooks(hHookIconPressedEvt, (WPARAM)dat->hContact, (LPARAM)&sicd);
+ InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE);
+ }
+}
+
+static HANDLE SI_hServiceIcon[3];
+
+int SI_InitStatusIcons()
+{
+ SI_hServiceIcon[0] = CreateServiceFunction(MS_MSG_ADDICON, SI_AddStatusIcon);
+ SI_hServiceIcon[1] = CreateServiceFunction(MS_MSG_REMOVEICON, SI_RemoveStatusIcon);
+ SI_hServiceIcon[2] = CreateServiceFunction(MS_MSG_MODIFYICON, SI_ModifyStatusIcon);
+ hHookIconPressedEvt = CreateHookableEvent(ME_MSG_ICONPRESSED);
+
+ return 0;
+}
+
+
+int SI_DeinitStatusIcons()
+{
+ int i;
+ DestroyHookableEvent(hHookIconPressedEvt);
+ for (i = 0; i < 3; i++)
+ DestroyServiceFunction(SI_hServiceIcon[i]);
+ SI_RemoveAllStatusIcons();
+ return 0;
+}
+
+int SI_GetStatusIconsCount()
+{
+ return status_icon_list_size;
+}
diff --git a/plugins/TabSRMM/src/globals.cpp b/plugins/TabSRMM/src/globals.cpp
new file mode 100644
index 0000000000..689b4cb53b
--- /dev/null
+++ b/plugins/TabSRMM/src/globals.cpp
@@ -0,0 +1,967 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: globals.cpp 13447 2011-03-14 19:55:07Z george.hazan $
+ *
+ * Plugin configuration variables and functions. Implemented as a class
+ * though there will always be only a single instance.
+ *
+ */
+
+#include "commonheaders.h"
+extern PLUGININFOEX pluginInfo;
+
+CGlobals PluginConfig;
+CGlobals* pConfig = &PluginConfig;
+
+static TContainerSettings _cnt_default = {
+ false,
+ CNT_FLAGS_DEFAULT,
+ CNT_FLAGSEX_DEFAULT,
+ 255,
+ CInfoPanel::DEGRADE_THRESHOLD,
+ 60,
+ _T("%n (%s)"),
+ 1,
+ 0
+};
+
+HANDLE CGlobals::m_event_ModulesLoaded = 0, CGlobals::m_event_PrebuildMenu = 0, CGlobals::m_event_SettingChanged = 0;
+HANDLE CGlobals::m_event_ContactDeleted = 0, CGlobals::m_event_Dispatch = 0, CGlobals::m_event_EventAdded = 0;
+HANDLE CGlobals::m_event_IconsChanged = 0, CGlobals::m_event_TypingEvent = 0, CGlobals::m_event_ProtoAck = 0;
+HANDLE CGlobals::m_event_PreShutdown = 0, CGlobals::m_event_OkToExit = 0;
+HANDLE CGlobals::m_event_IcoLibChanged = 0, CGlobals::m_event_AvatarChanged = 0, CGlobals::m_event_MyAvatarChanged = 0, CGlobals::m_event_FontsChanged = 0;
+HANDLE CGlobals::m_event_SmileyAdd = 0, CGlobals::m_event_IEView = 0, CGlobals::m_event_FoldersChanged = 0;
+HANDLE CGlobals::m_event_ME_MC_SUBCONTACTSCHANGED = 0, CGlobals::m_event_ME_MC_FORCESEND = 0, CGlobals::m_event_ME_MC_UNFORCESEND = 0;
+TCHAR* CGlobals::m_default_container_name = _T("default");
+
+extern HANDLE hHookButtonPressedEvt;
+extern HANDLE hHookToolBarLoadedEvt;
+
+EXCEPTION_RECORD CGlobals::m_exRecord = {0};
+CONTEXT CGlobals::m_exCtx = {0};
+LRESULT CGlobals::m_exLastResult = 0;
+char CGlobals::m_exSzFile[MAX_PATH] = "\0";
+wchar_t CGlobals::m_exReason[256] = L"\0";
+int CGlobals::m_exLine = 0;
+bool CGlobals::m_exAllowContinue = false;
+
+#if defined(_WIN64)
+ static char szCurrentVersion[30];
+ static char *szVersionUrl = "http://download.miranda.or.at/tabsrmm/3/version.txt";
+ static char *szUpdateUrl = "http://silvercircle.googlecode.com/files/tabsrmm-3_x64.zip";
+ static char *szFLVersionUrl = "http://addons.miranda-im.org/details.php?action=viewfile&id=3699";
+ static char *szFLUpdateurl = "http://addons.miranda-im.org/feed.php?dlfile=3699";
+#else
+ static char szCurrentVersion[30];
+ static char *szVersionUrl = "http://download.miranda.or.at/tabsrmm/3/version.txt";
+ static char *szUpdateUrl = "http://silvercircle.googlecode.com/files/tabsrmm-3_x86.zip";
+ static char *szFLVersionUrl = ADDONS_UPDATE_URL;
+ static char *szFLUpdateurl = ADDONS_DL_URL;
+#endif
+ static char *szPrefix = "tabsrmm ";
+
+
+CRTException::CRTException(const char *szMsg, const TCHAR *szParam) : std::runtime_error(std::string(szMsg))
+{
+ mir_sntprintf(m_szParam, MAX_PATH, szParam);
+}
+
+void CRTException::display() const
+{
+ TCHAR* tszMsg = mir_a2t(what());
+ TCHAR tszBoxMsg[500];
+
+ mir_sntprintf(tszBoxMsg, 500, _T("%s\n\n(%s)"), tszMsg, m_szParam);
+ ::MessageBox(0, tszBoxMsg, _T("TabSRMM runtime error"), MB_OK | MB_ICONERROR);
+ mir_free(tszMsg);
+}
+
+void CGlobals::RegisterWithUpdater()
+{
+ Update upd = {0};
+
+ if (!ServiceExists(MS_UPDATE_REGISTER))
+ return;
+
+ upd.cbSize = sizeof(upd);
+ upd.szComponentName = pluginInfo.shortName;
+ upd.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szCurrentVersion);
+ upd.cpbVersion = (int)(strlen((char *)upd.pbVersion));
+ upd.szVersionURL = szFLVersionUrl;
+ upd.szUpdateURL = szFLUpdateurl;
+ upd.pbVersionPrefix = (BYTE *)"<span class=\"fileNameHeader\">tabSRMM Unicode 2.0 ";
+ upd.cpbVersionPrefix = (int)(strlen((char *)upd.pbVersionPrefix));
+
+ upd.szBetaUpdateURL = szUpdateUrl;
+ upd.szBetaVersionURL = szVersionUrl;
+ upd.pbVersion = (unsigned char *)szCurrentVersion;
+ upd.cpbVersion = lstrlenA(szCurrentVersion);
+ upd.pbBetaVersionPrefix = (BYTE *)szPrefix;
+ upd.cpbBetaVersionPrefix= (int)(strlen((char *)upd.pbBetaVersionPrefix));
+ upd.szBetaChangelogURL = "http://blog.miranda.or.at/tabsrmm-articles/tabsrmm-version-3-changelog";
+
+ CallService(MS_UPDATE_REGISTER, 0, (LPARAM)&upd);
+}
+/**
+ * reload system values. These are read ONCE and are not allowed to change
+ * without a restart
+ */
+void CGlobals::reloadSystemStartup()
+{
+ HDC hScrnDC;
+ DBVARIANT dbv = {0};
+
+ m_WinVerMajor = WinVerMajor();
+ m_WinVerMinor = WinVerMinor();
+ m_bIsXP = IsWinVerXPPlus();
+ m_bIsVista = IsWinVerVistaPlus();
+ m_bIsWin7 = IsWinVer7Plus();
+
+ ::LoadTSButtonModule();
+ ::RegisterTabCtrlClass();
+ CTip::registerClass();
+
+ dwThreadID = GetCurrentThreadId();
+
+ PluginConfig.g_hMenuContext = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_TABCONTEXT));
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM)g_hMenuContext, 0);
+
+ SkinAddNewSoundEx("RecvMsgActive", "Instant messages", "Incoming (Focused Window)");
+ SkinAddNewSoundEx("RecvMsgInactive", "Instant messages", "Incoming (Unfocused Window)");
+ SkinAddNewSoundEx("AlertMsg", "Instant messages", "Incoming (New Session)");
+ SkinAddNewSoundEx("SendMsg", "Instant messages", "Outgoing");
+ SkinAddNewSoundEx("SendError", "Instant messages", "Message send error");
+
+ hCurSplitNS = LoadCursor(NULL, IDC_SIZENS);
+ hCurSplitWE = LoadCursor(NULL, IDC_SIZEWE);
+ hCurHyperlinkHand = LoadCursor(NULL, IDC_HAND);
+ if (hCurHyperlinkHand == NULL)
+ hCurHyperlinkHand = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_HYPERLINKHAND));
+
+ hScrnDC = GetDC(0);
+ g_DPIscaleX = GetDeviceCaps(hScrnDC, LOGPIXELSX) / 96.0;
+ g_DPIscaleY = GetDeviceCaps(hScrnDC, LOGPIXELSY) / 96.0;
+ ReleaseDC(0, hScrnDC);
+
+ reloadSettings(false);
+ reloadAdv();
+ hookSystemEvents();
+}
+
+/**
+ * this runs ONCE at startup when the Modules Loaded event is fired
+ * by the core. all plugins are loaded and ready to use.
+ *
+ * any initialation for 3rd party plugins must go here.
+ */
+void CGlobals::reloadSystemModulesChanged()
+{
+ BOOL bIEView = FALSE;
+ CLISTMENUITEM mi = { 0 };
+
+ m_MathModAvail = ServiceExists(MATH_RTF_REPLACE_FORMULAE);
+
+ /*
+ * smiley add
+ */
+ if (ServiceExists(MS_SMILEYADD_REPLACESMILEYS)) {
+ PluginConfig.g_SmileyAddAvail = 1;
+ m_event_SmileyAdd = HookEvent(ME_SMILEYADD_OPTIONSCHANGED, ::SmileyAddOptionsChanged);
+ }
+ else
+ m_event_SmileyAdd = 0;
+
+ /*
+ * Flashavatars
+ */
+
+ g_FlashAvatarAvail = (ServiceExists(MS_FAVATAR_GETINFO) ? 1 : 0);
+
+ /*
+ * ieView
+ */
+
+ bIEView = ServiceExists(MS_IEVIEW_WINDOW);
+ if (bIEView) {
+ BOOL bOldIEView = M->GetByte("ieview_installed", 0);
+ if (bOldIEView != bIEView)
+ M->WriteByte(SRMSGMOD_T, "default_ieview", 1);
+ M->WriteByte(SRMSGMOD_T, "ieview_installed", 1);
+ m_event_IEView = HookEvent(ME_IEVIEW_OPTIONSCHANGED, ::IEViewOptionsChanged);
+ } else {
+ M->WriteByte(SRMSGMOD_T, "ieview_installed", 0);
+ m_event_IEView = 0;
+ }
+
+ g_iButtonsBarGap = M->GetByte("ButtonsBarGap", 1);
+ m_hwndClist = (HWND)CallService(MS_CLUI_GETHWND, 0, 0);
+ m_MathModAvail = (ServiceExists(MATH_RTF_REPLACE_FORMULAE) ? 1 : 0);
+ if (m_MathModAvail) {
+ char *szDelim = (char *)CallService(MATH_GET_STARTDELIMITER, 0, 0);
+ if (szDelim) {
+ MultiByteToWideChar(CP_ACP, 0, szDelim, -1, PluginConfig.m_MathModStartDelimiter, safe_sizeof(PluginConfig.m_MathModStartDelimiter));
+ CallService(MTH_FREE_MATH_BUFFER, 0, (LPARAM)szDelim);
+ }
+ }
+ else
+ PluginConfig.m_MathModStartDelimiter[0] = 0;
+
+ g_MetaContactsAvail = (ServiceExists(MS_MC_GETDEFAULTCONTACT) ? 1 : 0);
+
+
+ if(g_MetaContactsAvail) {
+ mir_snprintf(szMetaName, 256, "%s", (char *)CallService(MS_MC_GETPROTOCOLNAME, 0, 0));
+ bMetaEnabled = abs(M->GetByte(0, szMetaName, "Enabled", -1));
+ }
+ else {
+ szMetaName[0] = 0;
+ bMetaEnabled = 0;
+ }
+
+ g_PopupAvail = (ServiceExists(MS_POPUP_ADDPOPUPEX) ? 1 : 0);
+ g_PopupWAvail = (ServiceExists(MS_POPUP_ADDPOPUPW) ? 1 : 0);
+
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000090000;
+ if (ServiceExists(MS_SKIN2_GETICONBYHANDLE)) {
+ mi.flags = CMIF_ICONFROMICOLIB | CMIF_DEFAULT;
+ mi.icolibItem = LoadSkinnedIconHandle(SKINICON_EVENT_MESSAGE);
+ } else {
+ mi.flags = CMIF_DEFAULT;
+ mi.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ }
+ mi.pszName = LPGEN("&Message");
+ mi.pszService = MS_MSG_SENDMESSAGE;
+ PluginConfig.m_hMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+
+ m_useAeroPeek = M->GetByte("useAeroPeek", 1);
+}
+
+/**
+ * reload plugin settings on startup and runtime. Most of these setttings can be
+ * changed while plugin is running.
+ */
+void CGlobals::reloadSettings(bool fReloadSkins)
+{
+ m_ncm.cbSize = sizeof(NONCLIENTMETRICS);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &m_ncm, 0);
+
+ DWORD dwFlags = M->GetDword("mwflags", MWF_LOG_DEFAULT);
+
+ m_SendOnShiftEnter = (int)M->GetByte("sendonshiftenter", 0);
+ m_SendOnEnter = (int)M->GetByte(SRMSGSET_SENDONENTER, SRMSGDEFSET_SENDONENTER);
+ m_SendOnDblEnter = (int)M->GetByte("SendOnDblEnter", 0);
+ m_AutoLocaleSupport = (int)M->GetByte("al", 0);
+ m_AutoSwitchTabs = (int)M->GetByte("autoswitchtabs", 1);
+ m_CutContactNameTo = (int) DBGetContactSettingWord(NULL, SRMSGMOD_T, "cut_at", 15);
+ m_CutContactNameOnTabs = (int)M->GetByte("cuttitle", 0);
+ m_StatusOnTabs = (int)M->GetByte("tabstatus", 1);
+ m_LogStatusChanges = (int)dwFlags & MWF_LOG_STATUSCHANGES;
+ m_UseDividers = (int)M->GetByte("usedividers", 0);
+ m_DividersUsePopupConfig = (int)M->GetByte("div_popupconfig", 0);
+ m_MsgTimeout = (int)M->GetDword(SRMSGMOD, SRMSGSET_MSGTIMEOUT, SRMSGDEFSET_MSGTIMEOUT);
+
+ if (m_MsgTimeout < SRMSGSET_MSGTIMEOUT_MIN)
+ m_MsgTimeout = SRMSGSET_MSGTIMEOUT_MIN;
+
+ m_EscapeCloses = (int)M->GetByte("escmode", 0);
+
+ m_HideOnClose = (int) M->GetByte("hideonclose", 0);
+ m_AllowTab = (int) M->GetByte("tabmode", 0);
+
+ m_FlashOnClist = (int)M->GetByte("flashcl", 0);
+ m_AlwaysFullToolbarWidth = (int)M->GetByte("alwaysfulltoolbar", 1);
+ m_LimitStaticAvatarHeight = (int)M->GetDword("avatarheight", 96);
+ m_SendFormat = (int)M->GetByte("sendformat", 0);
+ m_FormatWholeWordsOnly = 1;
+ m_RTLDefault = (int)M->GetByte("rtldefault", 0);
+ m_TabAppearance = (int)M->GetDword("tabconfig", TCF_FLASHICON | TCF_SINGLEROWTABCONTROL);
+ m_panelHeight = (DWORD)M->GetDword("panelheight", CInfoPanel::DEGRADE_THRESHOLD);
+ m_MUCpanelHeight = M->GetDword("Chat", "panelheight", CInfoPanel::DEGRADE_THRESHOLD);
+ m_IdleDetect = (int)M->GetByte("dimIconsForIdleContacts", 1);
+ m_smcxicon = 16;
+ m_smcyicon = 16;
+ m_PasteAndSend = (int)M->GetByte("pasteandsend", 1);
+ m_szNoStatus = const_cast<TCHAR *>(CTranslator::get(CTranslator::GEN_NO_STATUS));
+ m_LangPackCP = ServiceExists(MS_LANGPACK_GETCODEPAGE) ? CallService(MS_LANGPACK_GETCODEPAGE, 0, 0) : CP_ACP;
+ m_visualMessageSizeIndicator = M->GetByte("msgsizebar", 0);
+ m_autoSplit = M->GetByte("autosplit", 0);
+ m_FlashOnMTN = M->GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINFLASH, SRMSGDEFSET_SHOWTYPINGWINFLASH);
+ if(m_MenuBar == 0) {
+ m_MenuBar = ::LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENUBAR));
+ CallService(MS_LANGPACK_TRANSLATEMENU, WPARAM(m_MenuBar), 0);
+ }
+
+ m_ipBackgroundGradient = M->GetDword(FONTMODULE, "ipfieldsbg", 0x62caff);
+ if(0 == m_ipBackgroundGradient)
+ m_ipBackgroundGradient = 0x62caff;
+
+ m_ipBackgroundGradientHigh = M->GetDword(FONTMODULE, "ipfieldsbgHigh", 0xf0f0f0);
+ if(0 == m_ipBackgroundGradientHigh)
+ m_ipBackgroundGradientHigh = 0xf0f0f0;
+
+ m_tbBackgroundHigh = M->GetDword(FONTMODULE, "tbBgHigh", 0);
+ m_tbBackgroundLow = M->GetDword(FONTMODULE, "tbBgLow", 0);
+ m_fillColor = M->GetDword(FONTMODULE, "fillColor", 0);
+ if(CSkin::m_BrushFill) {
+ ::DeleteObject(CSkin::m_BrushFill);
+ CSkin::m_BrushFill = 0;
+ }
+ m_genericTxtColor = M->GetDword(FONTMODULE, "genericTxtClr", GetSysColor(COLOR_BTNTEXT));
+ m_cRichBorders = M->GetDword(FONTMODULE, "cRichBorders", 0);
+
+ ::CopyMemory(&globalContainerSettings, &_cnt_default, sizeof(TContainerSettings));
+ Utils::ReadContainerSettingsFromDB(0, &globalContainerSettings);
+ globalContainerSettings.fPrivate = false;
+ if(fReloadSkins)
+ Skin->setupAeroSkins();
+}
+
+/**
+ * reload "advanced tweaks" that can be applied w/o a restart
+ */
+void CGlobals::reloadAdv()
+{
+ g_bDisableAniAvatars= M->GetByte("adv_DisableAniAvatars", 0);
+ g_bSoundOnTyping = M->GetByte("adv_soundontyping", 0);
+ m_dontUseDefaultKbd= M->GetByte("adv_leaveKeyboardAlone", 1);
+ g_bClientInStatusBar = M->GetByte("adv_ClientIconInStatusBar", 0);
+
+ if(g_bSoundOnTyping && m_TypingSoundAdded == false) {
+ SkinAddNewSoundEx("SoundOnTyping", "Other", "TABSRMM: Typing");
+ m_TypingSoundAdded = true;
+ }
+ m_AllowOfflineMultisend = M->GetByte("AllowOfflineMultisend", 0);
+}
+
+const HMENU CGlobals::getMenuBar()
+{
+ if(m_MenuBar == 0) {
+ m_MenuBar = ::LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENUBAR));
+ CallService(MS_LANGPACK_TRANSLATEMENU, WPARAM(m_MenuBar), 0);
+ }
+ return(m_MenuBar);
+}
+
+/**
+ * hook core events. This runs in LoadModule()
+ * only core events and services are guaranteed to exist at this time
+ */
+void CGlobals::hookSystemEvents()
+{
+ m_event_ModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded);
+ m_event_IconsChanged = HookEvent(ME_SKIN_ICONSCHANGED, ::IconsChanged);
+ m_event_TypingEvent = HookEvent(ME_PROTO_CONTACTISTYPING, CMimAPI::TypingMessage);
+ m_event_ProtoAck = HookEvent(ME_PROTO_ACK, CMimAPI::ProtoAck);
+ m_event_PreShutdown = HookEvent(ME_SYSTEM_PRESHUTDOWN, PreshutdownSendRecv);
+ m_event_OkToExit = HookEvent(ME_SYSTEM_OKTOEXIT, OkToExit);
+
+ m_event_PrebuildMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, CMimAPI::PrebuildContactMenu);
+
+ m_event_IcoLibChanged = HookEvent(ME_SKIN2_ICONSCHANGED, ::IcoLibIconsChanged);
+ m_event_AvatarChanged = HookEvent(ME_AV_AVATARCHANGED, ::AvatarChanged);
+ m_event_MyAvatarChanged = HookEvent(ME_AV_MYAVATARCHANGED, ::MyAvatarChanged);
+}
+
+/**
+ * second part of the startup initialisation. All plugins are now fully loaded
+ */
+
+int CGlobals::ModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+ MENUITEMINFOA mii = {0};
+ HMENU submenu;
+ CLISTMENUITEM mi = { 0 };
+
+ ::UnhookEvent(m_event_ModulesLoaded);
+
+ M->configureCustomFolders();
+
+ Skin->Init(true);
+ CSkin::initAeroEffect();
+
+ for (i = 0; i < NR_BUTTONBARICONS; i++)
+ PluginConfig.g_buttonBarIcons[i] = 0;
+ ::LoadIconTheme();
+ ::CreateImageList(TRUE);
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_BITMAP;
+ mii.hbmpItem = HBMMENU_CALLBACK;
+ submenu = GetSubMenu(PluginConfig.g_hMenuContext, 7);
+ for (i = 0; i <= 8; i++)
+ SetMenuItemInfoA(submenu, (UINT_PTR)i, TRUE, &mii);
+
+ PluginConfig.reloadSystemModulesChanged();
+
+ ::BuildContainerMenu();
+
+ ::CB_InitDefaultButtons();
+ ::ModPlus_Init(wParam, lParam);
+ ::NotifyEventHooks(hHookToolBarLoadedEvt, (WPARAM)0, (LPARAM)0);
+ //
+
+ if (M->GetByte("avatarmode", -1) == -1)
+ M->WriteByte(SRMSGMOD_T, "avatarmode", 2);
+
+ PluginConfig.g_hwndHotkeyHandler = CreateWindowEx(0, _T("TSHK"), _T(""), WS_POPUP,
+ 0, 0, 40, 40, 0, 0, g_hInst, NULL);
+
+ ::CreateTrayMenus(TRUE);
+ if (nen_options.bTraySupport)
+ ::CreateSystrayIcon(TRUE);
+
+ mi.cbSize = sizeof(mi);
+ mi.position = -500050005;
+ mi.hIcon = PluginConfig.g_iconContainer;
+ mi.pszContactOwner = NULL;
+ mi.pszName = LPGEN("&Messaging settings...");
+ mi.pszService = MS_TABMSG_SETUSERPREFS;
+ PluginConfig.m_UserMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+
+ if(sendLater->isAvail()) {
+ mi.cbSize = sizeof(mi);
+ mi.position = -500050006;
+ mi.hIcon = 0;
+ mi.pszContactOwner = NULL;
+ mi.pszName = LPGEN("&Send later job list...");
+ mi.pszService = MS_TABMSG_SLQMGR;
+ PluginConfig.m_UserMenuItem = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM) & mi);
+ }
+ RestoreUnreadMessageAlerts();
+
+ RegisterWithUpdater();
+
+ ::RegisterFontServiceFonts();
+ ::CacheLogFonts();
+ ::Chat_ModulesLoaded(wParam, lParam);
+ if(PluginConfig.g_PopupWAvail||PluginConfig.g_PopupAvail)
+ TN_ModuleInit();
+
+ m_event_SettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, DBSettingChanged);
+ m_event_ContactDeleted = HookEvent(ME_DB_CONTACT_DELETED, DBContactDeleted);
+
+ m_event_Dispatch = HookEvent(ME_DB_EVENT_ADDED, CMimAPI::DispatchNewEvent);
+ m_event_EventAdded = HookEvent(ME_DB_EVENT_ADDED, CMimAPI::MessageEventAdded);
+ if(PluginConfig.g_MetaContactsAvail) {
+ m_event_ME_MC_SUBCONTACTSCHANGED = HookEvent(ME_MC_SUBCONTACTSCHANGED, MetaContactEvent);
+ m_event_ME_MC_FORCESEND = HookEvent(ME_MC_FORCESEND, MetaContactEvent);
+ m_event_ME_MC_UNFORCESEND = HookEvent(ME_MC_UNFORCESEND, MetaContactEvent);
+ }
+ m_event_FontsChanged = HookEvent(ME_FONT_RELOAD, ::FontServiceFontsChanged);
+ return 0;
+}
+
+/**
+ * watches various important database settings and reacts accordingly
+ * needed to catch status, nickname and other changes in order to update open message
+ * sessions.
+ */
+
+int CGlobals::DBSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ const char *szProto = NULL;
+ const char *setting = cws->szSetting;
+ HWND hwnd = 0;
+ CContactCache* c = 0;
+ bool fChanged = false, fNickChanged = false, fExtendedStatusChange = false;
+
+ hwnd = M->FindWindow((HANDLE)wParam);
+
+ if (hwnd == 0 && wParam != 0) { // we are not interested in this event if there is no open message window/tab
+ if(!strcmp(setting, "Status") || !strcmp(setting, "MyHandle") || !strcmp(setting, "Nick") || !strcmp(cws->szModule, SRMSGMOD_T)) {
+ c = CContactCache::getContactCache((HANDLE)wParam);
+ if(c) {
+ fChanged = c->updateStatus();
+ if(strcmp(setting, "Status"))
+ c->updateNick();
+ if(!strcmp(setting, "isFavorite") || !strcmp(setting, "isRecent"))
+ c->updateFavorite();
+ }
+ }
+ return(0);
+ }
+
+ if (wParam == 0 && !strcmp("Nick", setting)) {
+ M->BroadcastMessage(DM_OWNNICKCHANGED, 0, (LPARAM)cws->szModule);
+ return(0);
+ }
+
+ if(wParam) {
+ c = CContactCache::getContactCache((HANDLE)wParam);
+ if(c) {
+ szProto = c->getProto();
+ if(!strcmp(cws->szModule, SRMSGMOD_T)) { // catch own relevant settings
+ if(!strcmp(setting, "isFavorite") || !strcmp(setting, "isRecent"))
+ c->updateFavorite();
+ }
+ }
+ }
+
+ if(wParam == 0 && !lstrcmpA(setting, "Enabled")) {
+ if(PluginConfig.g_MetaContactsAvail && !lstrcmpA(cws->szModule, PluginConfig.szMetaName)) { // catch the disabled meta contacts
+ PluginConfig.bMetaEnabled = abs(M->GetByte(0, PluginConfig.szMetaName, "Enabled", -1));
+ cacheUpdateMetaChanged();
+ }
+ }
+
+ if (lstrcmpA(cws->szModule, "CList") && (szProto == NULL || lstrcmpA(cws->szModule, szProto)))
+ return(0);
+
+ if (PluginConfig.g_MetaContactsAvail && !lstrcmpA(cws->szModule, PluginConfig.szMetaName)) {
+ if(wParam != 0 && !lstrcmpA(setting, "Nick")) // filter out this setting to avoid infinite loops while trying to obtain the most online contact
+ return(0);
+ }
+
+ if (hwnd) {
+ if(c) {
+ fChanged = c->updateStatus();
+ fNickChanged = c->updateNick();
+ }
+ if (lstrlenA(setting) > 6 && lstrlenA(setting) < 9 && !strncmp(setting, "Status", 6)) {
+ fChanged = true;
+ if(c) {
+ c->updateMeta(true);
+ c->updateUIN();
+ }
+ }
+ else if (!strcmp(setting, "MirVer"))
+ PostMessage(hwnd, DM_CLIENTCHANGED, 0, 0);
+ else if (!strcmp(setting, "display_uid")) {
+ if(c)
+ c->updateUIN();
+ PostMessage(hwnd, DM_UPDATEUIN, 0, 0);
+ }
+ else if(lstrlenA(setting) > 6 && strstr("StatusMsg,XStatusMsg,XStatusName,XStatusId,ListeningTo", setting)) {
+ if(c) {
+ c->updateStatusMsg(setting);
+ fExtendedStatusChange = true;
+ }
+ }
+ if(fChanged || fNickChanged || fExtendedStatusChange)
+ PostMessage(hwnd, DM_UPDATETITLE, 0, 1);
+ if(fExtendedStatusChange)
+ PostMessage(hwnd, DM_UPDATESTATUSMSG, 0, 0);
+ if(fChanged) {
+ if(c && c->getStatus() == ID_STATUS_OFFLINE) { // clear typing notification in the status bar when contact goes offline
+ TWindowData* dat = c->getDat();
+ if(dat) {
+ dat->nTypeSecs = 0;
+ dat->showTyping = 0;
+ dat->szStatusBar[0] = 0;
+ PostMessage(c->getHwnd(), DM_UPDATELASTMESSAGE, 0, 0);
+ }
+ }
+ if(c)
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_LOGSTATUSCHANGE, MAKELONG(c->getStatus(), c->getOldStatus()), (LPARAM)c);
+ }
+ }
+ return(0);
+}
+
+/**
+ * event fired when a contact has been deleted. Make sure to close its message session
+ */
+
+int CGlobals::DBContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ if(wParam) {
+ CContactCache *c = CContactCache::getContactCache((HANDLE)wParam);
+ if(c)
+ c->deletedHandler();
+ }
+ return 0;
+}
+
+/**
+ * Handle events from metacontacts protocol. Basically, just update
+ * our contact cache and, if a message window exists, tell it to update
+ * relevant information.
+ */
+int CGlobals::MetaContactEvent(WPARAM wParam, LPARAM lParam)
+{
+ if(wParam) {
+ CContactCache *c = CContactCache::getContactCache((HANDLE)wParam);
+ if(c) {
+ c->updateMeta(true);
+ if(c->getHwnd()) {
+ c->updateUIN(); // only do this for open windows, not needed normally
+ ::PostMessage(c->getHwnd(), DM_UPDATETITLE, 0, 0);
+ }
+ }
+ }
+ return(0);
+}
+
+int CGlobals::PreshutdownSendRecv(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact;
+ int i;
+
+#if defined(__USE_EX_HANDLERS)
+ __try {
+#endif
+ if (PluginConfig.m_chat_enabled)
+ ::Chat_PreShutdown();
+
+ ::TN_ModuleDeInit();
+
+ while(pFirstContainer){
+ if (PluginConfig.m_HideOnClose)
+ PluginConfig.m_HideOnClose = FALSE;
+ ::SendMessage(pFirstContainer->hwnd, WM_CLOSE, 0, 1);
+ }
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ M->WriteDword(hContact, SRMSGMOD_T, "messagecount", 0);
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+
+ for(i = 0; i < SERVICE_LAST; i++) {
+ if(PluginConfig.hSvc[i])
+ DestroyServiceFunction(PluginConfig.hSvc[i]);
+ }
+
+ ::SI_DeinitStatusIcons();
+ ::CB_DeInitCustomButtons();
+ /*
+ * the event API
+ */
+
+ DestroyHookableEvent(PluginConfig.m_event_MsgWin);
+ DestroyHookableEvent(PluginConfig.m_event_MsgPopup);
+
+ ::NEN_WriteOptions(&nen_options);
+ ::DestroyWindow(PluginConfig.g_hwndHotkeyHandler);
+
+ ::UnregisterClass(_T("TSStatusBarClass"), g_hInst);
+ ::UnregisterClass(_T("SideBarClass"), g_hInst);
+ ::UnregisterClassA("TSTabCtrlClass", g_hInst);
+ ::UnregisterClass(_T("RichEditTipClass"), g_hInst);
+ ::UnregisterClass(_T("TSHK"), g_hInst);
+#if defined(__USE_EX_HANDLERS)
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"SHUTDOWN_STAGE2", false)) {
+ return(0);
+ }
+#endif
+ return 0;
+}
+
+int CGlobals::OkToExit(WPARAM wParam, LPARAM lParam)
+{
+ UnhookEvent(m_event_OkToExit);
+#if defined(__USE_EX_HANDLERS)
+ __try {
+#endif
+ ::CreateSystrayIcon(0);
+ ::CreateTrayMenus(0);
+
+ CWarning::destroyAll();
+
+ CMimAPI::m_shutDown = true;
+ UnhookEvent(m_event_EventAdded);
+ UnhookEvent(m_event_Dispatch);
+ UnhookEvent(m_event_PrebuildMenu);
+ UnhookEvent(m_event_SettingChanged);
+ UnhookEvent(m_event_ContactDeleted);
+ UnhookEvent(m_event_AvatarChanged);
+ UnhookEvent(m_event_MyAvatarChanged);
+ UnhookEvent(m_event_ProtoAck);
+ UnhookEvent(m_event_TypingEvent);
+ UnhookEvent(m_event_FontsChanged);
+ UnhookEvent(m_event_IcoLibChanged);
+ UnhookEvent(m_event_IconsChanged);
+
+ if(m_event_SmileyAdd)
+ UnhookEvent(m_event_SmileyAdd);
+
+ if(m_event_IEView)
+ UnhookEvent(m_event_IEView);
+
+ if(m_event_FoldersChanged)
+ UnhookEvent(m_event_FoldersChanged);
+
+ if(m_event_ME_MC_FORCESEND) {
+ UnhookEvent(m_event_ME_MC_FORCESEND);
+ UnhookEvent(m_event_ME_MC_SUBCONTACTSCHANGED);
+ UnhookEvent(m_event_ME_MC_UNFORCESEND);
+ }
+ ::ModPlus_PreShutdown(wParam, lParam);
+ PluginConfig.globalContainerSettings.fPrivate = false;
+ ::DBWriteContactSettingBlob(0, SRMSGMOD_T, CNT_KEYNAME, &PluginConfig.globalContainerSettings, sizeof(TContainerSettings));
+#if defined(__USE_EX_HANDLERS)
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"SHUTDOWN_STAGE1", false)) {
+ return(0);
+ }
+#endif
+ return 0;
+}
+
+/**
+ * used on startup to restore flashing tray icon if one or more messages are
+ * still "unread"
+ */
+
+void CGlobals::RestoreUnreadMessageAlerts(void)
+{
+ CLISTEVENT cle = { 0 };
+ DBEVENTINFO dbei = { 0 };
+ TCHAR toolTip[256];
+ int windowAlreadyExists;
+ int usingReadNext = 0;
+
+ int autoPopup = M->GetByte(SRMSGMOD, SRMSGSET_AUTOPOPUP, SRMSGDEFSET_AUTOPOPUP);
+ HANDLE hDbEvent, hContact;
+
+ dbei.cbSize = sizeof(dbei);
+ cle.cbSize = sizeof(cle);
+ cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ cle.pszService = "SRMsg/ReadMessage";
+ cle.flags = CLEF_TCHAR;
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+
+ if(M->GetDword(hContact, "SendLater", "count", 0))
+ sendLater->addContact(hContact);
+
+ hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDFIRSTUNREAD, (WPARAM) hContact, 0);
+ while (hDbEvent) {
+ dbei.cbBlob = 0;
+ CallService(MS_DB_EVENT_GET, (WPARAM) hDbEvent, (LPARAM) & dbei);
+ if (!(dbei.flags & (DBEF_SENT | DBEF_READ)) && dbei.eventType == EVENTTYPE_MESSAGE) {
+ windowAlreadyExists = M->FindWindow(hContact) != NULL;
+ if (!usingReadNext && windowAlreadyExists)
+ continue;
+
+ cle.hContact = hContact;
+ cle.hDbEvent = hDbEvent;
+ mir_sntprintf(toolTip, safe_sizeof(toolTip), CTranslator::get(CTranslator::GEN_STRING_MESSAGEFROM),
+ (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR));
+ cle.ptszTooltip = toolTip;
+ CallService(MS_CLIST_ADDEVENT, 0, (LPARAM) & cle);
+ }
+ hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, (WPARAM) hDbEvent, 0);
+ }
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+}
+
+void CGlobals::logStatusChange(WPARAM wParam, const CContactCache *c)
+{
+ if(c == 0)
+ return;
+
+ HANDLE hContact = c->getContact();
+
+ bool fGlobal = PluginConfig.m_LogStatusChanges ? true : false;
+ DWORD dwMask = M->GetDword(hContact, SRMSGMOD_T, "mwmask", 0);
+ DWORD dwFlags = M->GetDword(hContact, SRMSGMOD_T, "mwflags", 0);
+
+ bool fLocal = ((dwMask & MWF_LOG_STATUSCHANGES) ? (dwFlags & MWF_LOG_STATUSCHANGES ? true : false) : false);
+
+ if(fGlobal || fLocal) {
+ /*
+ * don't log them if WE are logging off
+ */
+ if(CallProtoService(c->getProto(), PS_GETSTATUS, 0, 0) == ID_STATUS_OFFLINE)
+ return;
+
+ WORD wStatus, wOldStatus;
+
+ wStatus = LOWORD(wParam);
+ wOldStatus = HIWORD(wParam);
+
+ if(wStatus == wOldStatus)
+ return;
+
+ DBEVENTINFO dbei;
+ TCHAR buffer[450];
+ HANDLE hNewEvent;
+
+ TCHAR* szOldStatus = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)wOldStatus, GSMDF_TCHAR);
+ TCHAR* szNewStatus = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)wStatus, GSMDF_TCHAR);
+
+ if(szOldStatus == 0 || szNewStatus == 0)
+ return;
+
+ if (c->isValid()) {
+ if (wStatus == ID_STATUS_OFFLINE)
+ mir_sntprintf(buffer, safe_sizeof(buffer), CTranslator::get(CTranslator::GEN_MSG_SIGNEDOFF));
+ else if (wOldStatus == ID_STATUS_OFFLINE)
+ mir_sntprintf(buffer, safe_sizeof(buffer), CTranslator::get(CTranslator::GEN_MSG_SIGNEDON), szNewStatus);
+ else
+ mir_sntprintf(buffer, safe_sizeof(buffer), CTranslator::get(CTranslator::GEN_MSG_CHANGEDSTATUS), szOldStatus, szNewStatus);
+ }
+
+ char *szMsg = M->utf8_encodeT(buffer);
+
+ dbei.pBlob = (PBYTE)szMsg;
+ dbei.cbBlob = lstrlenA(szMsg) + 1;
+ dbei.flags = DBEF_UTF | DBEF_READ;
+ dbei.cbSize = sizeof(dbei);
+ dbei.eventType = EVENTTYPE_STATUSCHANGE;
+ dbei.timestamp = time(NULL);
+ dbei.szModule = const_cast<char *>(c->getProto());
+ hNewEvent = (HANDLE) CallService(MS_DB_EVENT_ADD, (WPARAM) hContact, (LPARAM) & dbei);
+
+ mir_free(szMsg);
+ }
+}
+
+/**
+ * when the state of the meta contacts protocol changes from enabled to disabled
+ * (or vice versa), this updates the contact cache
+ *
+ * it is ONLY called from the DBSettingChanged() event handler when the relevant
+ * database value is touched.
+ */
+void CGlobals::cacheUpdateMetaChanged()
+{
+ CContactCache* c = CContactCache::m_cCache;
+ bool fMetaActive = (PluginConfig.g_MetaContactsAvail && PluginConfig.bMetaEnabled) ? true : false;
+
+ while(c) {
+ if(c->isMeta() && PluginConfig.bMetaEnabled == false) {
+ c->closeWindow();
+ c->resetMeta();
+ }
+
+ // meta contacts are enabled, but current contact is a subcontact - > close window
+
+ if(fMetaActive && c->isSubContact())
+ c->closeWindow();
+
+ // reset meta contact information, if metacontacts protocol became avail
+
+ if(fMetaActive && !strcmp(c->getProto(), PluginConfig.szMetaName))
+ c->resetMeta();
+
+ c = c->m_next;
+ }
+}
+
+/**
+ * on Windows 7, when using new task bar features (grouping mode and per tab
+ * previews), autoswitching does not work relieably, so it is disabled.
+ *
+ * @return: true if configuration dictates autoswitch
+ */
+bool CGlobals::haveAutoSwitch()
+{
+ if(m_bIsWin7) {
+ if(m_useAeroPeek && !CSkin::m_skinEnabled)
+ return(false);
+ }
+ return(m_AutoSwitchTabs ? true : false);
+}
+/**
+ * exception handling - copy error message to clip board
+ * @param hWnd: window handle of the edit control containing the error message
+ */
+void CGlobals::Ex_CopyEditToClipboard(HWND hWnd)
+{
+ SendMessage(hWnd, EM_SETSEL, 0, 65535L);
+ SendMessage(hWnd, WM_COPY, 0 , 0);
+ SendMessage(hWnd, EM_SETSEL, 0, 0);
+}
+
+INT_PTR CALLBACK CGlobals::Ex_DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WORD wNotifyCode, wID;
+
+ switch(uMsg) {
+ case WM_INITDIALOG: {
+ char szBuffer[2048];
+#ifdef _WIN64
+ sprintf(szBuffer,
+ "Exception %16.16X at address %16.16X occured in %s at line %d.\r\n\r\nEAX=%16.16X EBX=%16.16X ECX=%16.16X\r\nEDX=%16.16X ESI=%16.16X EDI=%16.16X\r\nEBP=%16.16X ESP=%16.16X EIP=%16.16X",
+ m_exRecord.ExceptionCode, m_exRecord.ExceptionAddress, m_exSzFile, m_exLine,
+ m_exCtx.Rax,m_exCtx.Rbx, m_exCtx.Rcx, m_exCtx.Rdx,
+ m_exCtx.Rsi, m_exCtx.Rdi, m_exCtx.Rbp, m_exCtx.Rsp, m_exCtx.Rip);
+#else
+ sprintf(szBuffer,
+ "Exception %8.8X at address %8.8X occured in %s at line %d.\r\n\r\nEAX=%8.8X EBX=%8.8X ECX=%8.8X\r\nEDX=%8.8X ESI=%8.8X EDI=%8.8X\r\nEBP=%8.8X ESP=%8.8X EIP=%8.8X",
+ m_exRecord.ExceptionCode, m_exRecord.ExceptionAddress, m_exSzFile, m_exLine,
+ m_exCtx.Eax,m_exCtx.Ebx, m_exCtx.Ecx, m_exCtx.Edx,
+ m_exCtx.Esi, m_exCtx.Edi, m_exCtx.Ebp, m_exCtx.Esp, m_exCtx.Eip);
+#endif
+ SetDlgItemTextA(hwndDlg, IDC_EXCEPTION_DETAILS, szBuffer);
+ SetFocus(GetDlgItem(hwndDlg, IDC_EXCEPTION_DETAILS));
+ SendDlgItemMessage(hwndDlg, IDC_EXCEPTION_DETAILS, WM_SETFONT, (WPARAM)GetStockObject(OEM_FIXED_FONT), 0);
+ SetDlgItemTextW(hwndDlg, IDC_EX_REASON, m_exReason);
+ Utils::enableDlgControl(hwndDlg, IDOK, m_exAllowContinue ? TRUE : FALSE);
+ }
+ break;
+
+ case WM_COMMAND:
+ wNotifyCode = HIWORD(wParam);
+ wID = LOWORD(wParam);
+ if (wNotifyCode == BN_CLICKED)
+ {
+ if (wID == IDOK || wID == IDCANCEL)
+ EndDialog(hwndDlg, wID);
+
+ if (wID == IDC_COPY_EXCEPTION)
+ Ex_CopyEditToClipboard(GetDlgItem(hwndDlg, IDC_EXCEPTION_DETAILS));
+ }
+
+ break;
+ }
+ return FALSE;
+}
+
+void CGlobals::Ex_Handler()
+{
+ if (m_exLastResult == IDCANCEL)
+ ExitProcess(1);
+}
+
+int CGlobals::Ex_ShowDialog(EXCEPTION_POINTERS *ep, const char *szFile, int line, wchar_t* szReason, bool fAllowContinue)
+{
+ char szDrive[MAX_PATH], szDir[MAX_PATH], szName[MAX_PATH], szExt[MAX_PATH];
+
+ _splitpath(szFile, szDrive, szDir, szName, szExt);
+ memcpy(&m_exRecord, ep->ExceptionRecord, sizeof(EXCEPTION_RECORD));
+ memcpy(&m_exCtx, ep->ContextRecord, sizeof(CONTEXT));
+
+ _snprintf(m_exSzFile, MAX_PATH, "%s%s", szName, szExt);
+ mir_sntprintf(m_exReason, 256, L"An application error has occured: %s", szReason);
+ m_exLine = line;
+ m_exLastResult = DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXCEPTION), 0, CGlobals::Ex_DlgProc, 0);
+ m_exAllowContinue = fAllowContinue;
+ if(IDCANCEL == m_exLastResult)
+ ExitProcess(1);
+ return 1;
+}
diff --git a/plugins/TabSRMM/src/hotkeyhandler.cpp b/plugins/TabSRMM/src/hotkeyhandler.cpp
new file mode 100644
index 0000000000..d203e2fd4d
--- /dev/null
+++ b/plugins/TabSRMM/src/hotkeyhandler.cpp
@@ -0,0 +1,688 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: hotkeyhandler.cpp 13596 2011-04-15 19:07:23Z george.hazan $
+ *
+ * The hotkeyhandler is a small, invisible window which handles the following things:
+
+ a) event notify stuff, messages posted from the popups to avoid threading
+ issues.
+
+ b) tray icon handling
+
+ c) send later job management. Periodically process the queue of open
+ deferred send jobs.
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+extern HICON hIcons[];
+extern INT_PTR SendMessageCommand(WPARAM wParam, LPARAM lParam);
+extern INT_PTR SendMessageCommand_W(WPARAM wParam, LPARAM lParam);
+
+static UINT WM_TASKBARCREATED;
+static HANDLE hSvcHotkeyProcessor = 0;
+
+static HOTKEYDESC _hotkeydescs[] = {
+ { 0, "tabsrmm_mostrecent", "Most recent unread session", TABSRMM_HK_SECTION_IM, MS_TABMSG_HOTKEYPROCESS, HOTKEYCODE(HOTKEYF_CONTROL|HOTKEYF_SHIFT, 'R'), TABSRMM_HK_LASTUNREAD },
+ { 0, "tabsrmm_paste_and_send", "Paste and send", TABSRMM_HK_SECTION_GENERIC, 0, HOTKEYCODE(HOTKEYF_CONTROL|HOTKEYF_SHIFT, 'D'), TABSRMM_HK_PASTEANDSEND },
+ { 0, "tabsrmm_uprefs", "Contact's messaging prefs", TABSRMM_HK_SECTION_IM, 0, HOTKEYCODE(HOTKEYF_CONTROL|HOTKEYF_SHIFT, 'C'), TABSRMM_HK_SETUSERPREFS },
+ { 0, "tabsrmm_copts", "Container options", TABSRMM_HK_SECTION_GENERIC, 0, HOTKEYCODE(HOTKEYF_CONTROL, 'O'), TABSRMM_HK_CONTAINEROPTIONS },
+ { 0, "tabsrmm_nudge", "Send nudge", TABSRMM_HK_SECTION_IM, 0, HOTKEYCODE(HOTKEYF_CONTROL, 'N'), TABSRMM_HK_NUDGE },
+ { 0, "tabsrmm_sendfile", "Send a file", TABSRMM_HK_SECTION_IM, 0, HOTKEYCODE(HOTKEYF_ALT, 'F'), TABSRMM_HK_SENDFILE },
+ { 0, "tabsrmm_quote", "Quote message", TABSRMM_HK_SECTION_IM, 0, HOTKEYCODE(HOTKEYF_ALT, 'Q'), TABSRMM_HK_QUOTEMSG },
+ { 0, "tabsrmm_sendlater", "Toggle send later", TABSRMM_HK_SECTION_IM, 0, HOTKEYCODE(HOTKEYF_CONTROL|HOTKEYF_SHIFT, 'S'), TABSRMM_HK_TOGGLESENDLATER },
+
+ { 0, "tabsrmm_send", "Send message", TABSRMM_HK_SECTION_GENERIC, 0, 0, TABSRMM_HK_SEND },
+ { 0, "tabsrmm_emot", "Smiley selector", TABSRMM_HK_SECTION_GENERIC, 0, HOTKEYCODE(HOTKEYF_ALT, 'E'), TABSRMM_HK_EMOTICONS },
+ { 0, "tabsrmm_hist", "Show message history", TABSRMM_HK_SECTION_GENERIC, 0, HOTKEYCODE(HOTKEYF_ALT, 'H'), TABSRMM_HK_HISTORY },
+ { 0, "tabsrmm_umenu", "Show user menu", TABSRMM_HK_SECTION_IM, 0, HOTKEYCODE(HOTKEYF_ALT, 'D'), TABSRMM_HK_USERMENU },
+ { 0, "tabsrmm_udet", "Show user details", TABSRMM_HK_SECTION_IM, 0, HOTKEYCODE(HOTKEYF_ALT, 'U'), TABSRMM_HK_USERDETAILS },
+ { 0, "tabsrmm_tbar", "Toggle tool bar", TABSRMM_HK_SECTION_GENERIC, 0, HOTKEYCODE(HOTKEYF_ALT|HOTKEYF_SHIFT, 'T'), TABSRMM_HK_TOGGLETOOLBAR },
+ { 0, "tabsrmm_ipanel", "Toggle info panel", TABSRMM_HK_SECTION_GENERIC, 0, HOTKEYCODE(HOTKEYF_ALT|HOTKEYF_CONTROL, 'I'), TABSRMM_HK_TOGGLEINFOPANEL },
+ { 0, "tabsrmm_rtl", "Toggle text direction", TABSRMM_HK_SECTION_IM, 0, HOTKEYCODE(HOTKEYF_ALT|HOTKEYF_CONTROL, 'B'), TABSRMM_HK_TOGGLERTL },
+ { 0, "tabsrmm_msend", "Toggle multi send", TABSRMM_HK_SECTION_IM, 0, HOTKEYCODE(HOTKEYF_ALT|HOTKEYF_CONTROL, 'M'), TABSRMM_HK_TOGGLEMULTISEND },
+ { 0, "tabsrmm_clearlog", "Clear message log", TABSRMM_HK_SECTION_GENERIC, 0, HOTKEYCODE(HOTKEYF_CONTROL, 'L'), TABSRMM_HK_CLEARLOG },
+ { 0, "tabsrmm_notes", "Edit user notes", TABSRMM_HK_SECTION_IM, 0, HOTKEYCODE(HOTKEYF_SHIFT | HOTKEYF_CONTROL, 'N'), TABSRMM_HK_EDITNOTES },
+ { 0, "tabsrmm_sbar", "Collapse side bar", TABSRMM_HK_SECTION_GENERIC, 0, HOTKEYCODE(0, VK_F9), TABSRMM_HK_TOGGLESIDEBAR },
+ { 0, "tabsrmm_muc_cmgr", "Channel manager", TABSRMM_HK_SECTION_GC, 0, HOTKEYCODE(HOTKEYF_SHIFT | HOTKEYF_CONTROL, 'C'), TABSRMM_HK_CHANNELMGR },
+ { 0, "tabsrmm_muc_filter", "Toggle filter", TABSRMM_HK_SECTION_GC, 0, HOTKEYCODE(HOTKEYF_SHIFT | HOTKEYF_CONTROL, 'F'), TABSRMM_HK_FILTERTOGGLE },
+ { 0, "tabsrmm_muc_nick", "Toggle nick list", TABSRMM_HK_SECTION_GC, 0, HOTKEYCODE(HOTKEYF_SHIFT | HOTKEYF_CONTROL, 'N'), TABSRMM_HK_LISTTOGGLE },
+ { 0, "tabsrmm_muc_server_show", "Show server window", TABSRMM_HK_SECTION_GC, 0, HOTKEYCODE(HOTKEYF_SHIFT | HOTKEYF_CONTROL, '1'), TABSRMM_HK_MUC_SHOWSERVER }
+};
+
+static SendLaterJobIterator g_jobs;
+
+LRESULT ProcessHotkeysByMsgFilter(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR ctrlId)
+{
+ MSGFILTER mf;
+ mf.nmhdr.code = EN_MSGFILTER;
+ mf.nmhdr.hwndFrom = hwnd;
+ mf.nmhdr.idFrom = ctrlId;
+
+ mf.lParam = lParam;
+ mf.wParam = wParam;
+ mf.msg = msg;
+
+ return(SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&mf));
+}
+static INT_PTR HotkeyProcessor(WPARAM wParam, LPARAM lParam)
+{
+ switch(lParam) {
+ case TABSRMM_HK_LASTUNREAD:
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, WM_MBUTTONDOWN);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+void TSAPI HandleMenuEntryFromhContact(int iSelection)
+{
+ HWND hWnd = M->FindWindow((HANDLE)iSelection);
+ SESSION_INFO *si = NULL;
+
+ if (iSelection == 0)
+ return;
+
+ if (hWnd && IsWindow(hWnd)) {
+ struct TContainerData *pContainer = 0;
+ SendMessage(hWnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
+ if (pContainer) {
+ ActivateExistingTab(pContainer, hWnd);
+ pContainer->hwndSaved = 0;
+ SetForegroundWindow(pContainer->hwnd);
+ } else
+ CallService(MS_MSG_SENDMESSAGE, (WPARAM)iSelection, 0);
+ } else if ((si = SM_FindSessionByHCONTACT((HANDLE)iSelection)) != NULL) {
+ if (si->hWnd) { // session does exist, but no window is open for it
+ struct TContainerData *pContainer = 0;
+
+ SendMessage(si->hWnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
+ if (pContainer) {
+ ActivateExistingTab(pContainer, si->hWnd);
+ if (GetForegroundWindow() != pContainer->hwnd)
+ SetForegroundWindow(pContainer->hwnd);
+ SetFocus(GetDlgItem(pContainer->hwndActive, IDC_CHAT_MESSAGE));
+ } else
+ goto nothing_open;
+ } else
+ goto nothing_open;
+ } else {
+nothing_open:
+ CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)iSelection, 0);
+ }
+}
+
+void TSAPI DrawMenuItem(DRAWITEMSTRUCT *dis, HICON hIcon, DWORD dwIdle)
+{
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_MENU));
+ if (dwIdle) {
+ CSkin::DrawDimmedIcon(dis->hDC, 2, (dis->rcItem.bottom + dis->rcItem.top - 16) / 2, 16, 16, hIcon, 180);
+ } else
+ DrawIconEx(dis->hDC, 2, (dis->rcItem.bottom + dis->rcItem.top - 16) / 2, hIcon, 16, 16, 0, 0, DI_NORMAL | DI_COMPAT);
+}
+
+LONG_PTR CALLBACK HotkeyHandlerDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static POINT ptLast;
+ static int iMousedown;
+
+ if (msg == WM_TASKBARCREATED) {
+ CreateSystrayIcon(FALSE);
+ if (nen_options.bTraySupport)
+ CreateSystrayIcon(TRUE);
+ return 0;
+ }
+ switch (msg) {
+ case WM_CREATE:
+ int i;
+
+ for(i = 0; i < safe_sizeof(_hotkeydescs); i++) {
+ _hotkeydescs[i].cbSize = sizeof(HOTKEYDESC);
+ CallService(MS_HOTKEY_REGISTER, 0, (LPARAM)&_hotkeydescs[i]);
+ }
+
+ WM_TASKBARCREATED = RegisterWindowMessageA("TaskbarCreated");
+ ShowWindow(hwndDlg, SW_HIDE);
+ hSvcHotkeyProcessor = CreateServiceFunction(MS_TABMSG_HOTKEYPROCESS, HotkeyProcessor);
+ SetTimer(hwndDlg, TIMERID_SENDLATER, TIMEOUT_SENDLATER, NULL);
+ break;
+ case WM_HOTKEY: {
+ CLISTEVENT *cli = 0;
+
+ cli = (CLISTEVENT *)CallService(MS_CLIST_GETEVENT, (WPARAM)INVALID_HANDLE_VALUE, (LPARAM)0);
+ if (cli != NULL) {
+ if (strncmp(cli->pszService, "SRMsg/TypingMessage", strlen(cli->pszService))) {
+ CallService(cli->pszService, 0, (LPARAM)cli);
+ break;
+ }
+ }
+ if (wParam == 0xc001)
+ SendMessage(hwndDlg, DM_TRAYICONNOTIFY, 101, WM_MBUTTONDOWN);
+
+ break;
+ }
+ /*
+ * handle the popup menus (session list, favorites, recents...
+ * just draw some icons, nothing more :)
+ */
+ case WM_MEASUREITEM: {
+ LPMEASUREITEMSTRUCT lpmi = (LPMEASUREITEMSTRUCT) lParam;
+ lpmi->itemHeight = 0;
+ lpmi->itemWidth = 6;
+ return TRUE;
+ }
+ case WM_DRAWITEM: {
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT) lParam;
+ struct TWindowData *dat = 0;
+ if (dis->CtlType == ODT_MENU && (dis->hwndItem == (HWND)PluginConfig.g_hMenuFavorites || dis->hwndItem == (HWND)PluginConfig.g_hMenuRecent)) {
+ HICON hIcon = (HICON)dis->itemData;
+
+ DrawMenuItem(dis, hIcon, 0);
+ return TRUE;
+ } else if (dis->CtlType == ODT_MENU) {
+ HWND hWnd = M->FindWindow((HANDLE)dis->itemID);
+ DWORD idle = 0;
+
+ if (hWnd == NULL) {
+ SESSION_INFO *si = SM_FindSessionByHCONTACT((HANDLE)dis->itemID);
+
+ hWnd = si ? si->hWnd : 0;
+ }
+
+ if (hWnd)
+ dat = (struct TWindowData *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+
+ if (dis->itemData >= 0) {
+ HICON hIcon;
+ BOOL fNeedFree = FALSE;
+
+ if (dis->itemData > 0)
+ hIcon = dis->itemData & 0x10000000 ? hIcons[ICON_HIGHLIGHT] : PluginConfig.g_IconMsgEvent;
+ else if (dat != NULL) {
+ hIcon = MY_GetContactIcon(dat);
+ idle = dat->idle;
+ } else
+ hIcon = PluginConfig.g_iconContainer;
+
+ DrawMenuItem(dis, hIcon, idle);
+ if (fNeedFree)
+ DestroyIcon(hIcon);
+
+ return TRUE;
+ }
+ }
+ }
+ break;
+ case DM_TRAYICONNOTIFY: {
+ int iSelection;
+
+ if (wParam == 100 || wParam == 101) {
+ switch (lParam) {
+ case WM_LBUTTONUP: {
+ POINT pt;
+ GetCursorPos(&pt);
+ if (wParam == 100)
+ SetForegroundWindow(hwndDlg);
+ if (GetMenuItemCount(PluginConfig.g_hMenuTrayUnread) > 0) {
+ iSelection = TrackPopupMenu(PluginConfig.g_hMenuTrayUnread, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL);
+ HandleMenuEntryFromhContact(iSelection);
+ } else
+ TrackPopupMenu(GetSubMenu(PluginConfig.g_hMenuContext, 8), TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL);
+ if (wParam == 100)
+ PostMessage(hwndDlg, WM_NULL, 0, 0);
+ break;
+ }
+ case WM_MBUTTONDOWN: {
+ MENUITEMINFOA mii = {0};
+ int i, iCount = GetMenuItemCount(PluginConfig.g_hMenuTrayUnread);
+
+ if (wParam == 100)
+ SetForegroundWindow(hwndDlg);
+
+ if (iCount > 0) {
+ UINT uid = 0;
+ mii.fMask = MIIM_DATA;
+ mii.cbSize = sizeof(mii);
+ i = iCount - 1;
+ do {
+ GetMenuItemInfoA(PluginConfig.g_hMenuTrayUnread, i, TRUE, &mii);
+ if (mii.dwItemData > 0) {
+ uid = GetMenuItemID(PluginConfig.g_hMenuTrayUnread, i);
+ HandleMenuEntryFromhContact(uid);
+ break;
+ }
+ } while (--i >= 0);
+ if (uid == 0 && pLastActiveContainer != NULL) { // no session found, restore last active container
+ if (IsIconic(pLastActiveContainer->hwnd) || !IsWindowVisible(pLastActiveContainer->hwnd)) {
+ SendMessage(pLastActiveContainer->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+ SetForegroundWindow(pLastActiveContainer->hwnd);
+ SetFocus(GetDlgItem(pLastActiveContainer->hwndActive, IDC_MESSAGE));
+ } else if (GetForegroundWindow() != pLastActiveContainer->hwnd) {
+ SetForegroundWindow(pLastActiveContainer->hwnd);
+ SetFocus(GetDlgItem(pLastActiveContainer->hwndActive, IDC_MESSAGE));
+ } else {
+ if(PluginConfig.m_HideOnClose)
+ ShowWindow(pLastActiveContainer->hwnd, SW_HIDE);
+ else
+ SendMessage(pLastActiveContainer->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+ }
+ }
+ }
+ if (wParam == 100)
+ PostMessage(hwndDlg, WM_NULL, 0, 0);
+ break;
+ }
+ case WM_RBUTTONUP: {
+ HMENU submenu = PluginConfig.g_hMenuTrayContext;
+ POINT pt;
+
+ if (wParam == 100)
+ SetForegroundWindow(hwndDlg);
+ GetCursorPos(&pt);
+ CheckMenuItem(submenu, ID_TRAYCONTEXT_DISABLEALLPOPUPS, MF_BYCOMMAND | (nen_options.iDisable ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(submenu, ID_TRAYCONTEXT_DON40223, MF_BYCOMMAND | (nen_options.iNoSounds ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(submenu, ID_TRAYCONTEXT_DON, MF_BYCOMMAND | (nen_options.iNoAutoPopup ? MF_CHECKED : MF_UNCHECKED));
+ EnableMenuItem(submenu, ID_TRAYCONTEXT_HIDEALLMESSAGECONTAINERS, MF_BYCOMMAND | (nen_options.bTraySupport) ? MF_ENABLED : MF_GRAYED);
+ CheckMenuItem(submenu, ID_TRAYCONTEXT_SHOWTHETRAYICON, MF_BYCOMMAND | (nen_options.bTraySupport ? MF_CHECKED : MF_UNCHECKED));
+ iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL);
+
+ if (iSelection) {
+ MENUITEMINFO mii = {0};
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA | MIIM_ID;
+ GetMenuItemInfo(submenu, (UINT_PTR)iSelection, FALSE, &mii);
+ if (mii.dwItemData != 0) { // this must be an itm of the fav or recent menu
+ HandleMenuEntryFromhContact(iSelection);
+ } else {
+ switch (iSelection) {
+ case ID_TRAYCONTEXT_SHOWTHETRAYICON:
+ nen_options.bTraySupport = !nen_options.bTraySupport;
+ CreateSystrayIcon(nen_options.bTraySupport ? TRUE : FALSE);
+ break;
+ case ID_TRAYCONTEXT_DISABLEALLPOPUPS:
+ nen_options.iDisable ^= 1;
+ break;
+ case ID_TRAYCONTEXT_DON40223:
+ nen_options.iNoSounds ^= 1;
+ break;
+ case ID_TRAYCONTEXT_DON:
+ nen_options.iNoAutoPopup ^= 1;
+ break;
+ case ID_TRAYCONTEXT_HIDEALLMESSAGECONTAINERS: {
+ struct TContainerData *pContainer = pFirstContainer;
+
+ while (pContainer) {
+ ShowWindow(pContainer->hwnd, SW_HIDE);
+ pContainer = pContainer->pNextContainer;
+ }
+ break;
+ }
+ case ID_TRAYCONTEXT_RESTOREALLMESSAGECONTAINERS: {
+ struct TContainerData *pContainer = pFirstContainer;
+
+ while (pContainer) {
+ ShowWindow(pContainer->hwnd, SW_SHOW);
+ pContainer = pContainer->pNextContainer;
+ }
+ break;
+ }
+ case ID_TRAYCONTEXT_BE: {
+ struct TContainerData *pContainer = pFirstContainer;
+
+ nen_options.iDisable = 1;
+ nen_options.iNoSounds = 1;
+ nen_options.iNoAutoPopup = 1;
+
+ while (pContainer) {
+ SendMessage(pContainer->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 1);
+ pContainer = pContainer->pNextContainer;
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (wParam == 100)
+ PostMessage(hwndDlg, WM_NULL, 0, 0);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ /*
+ * handle an event from the popup module (mostly window activation). Since popups may run in different threads, the message
+ * is posted to our invisible hotkey handler which does always run within the main thread.
+ * wParam is the hContact
+ * lParam the event handle
+ */
+ case DM_HANDLECLISTEVENT: {
+ CLISTEVENT *cle = (CLISTEVENT *)CallService(MS_CLIST_GETEVENT, wParam, 0);
+
+ /*
+ * if lParam == NULL, don't consider clist events, just open the message tab
+ */
+
+ if(lParam == 0) {
+ HandleMenuEntryFromhContact((int)wParam);
+ break;
+ }
+
+ /*
+ * first try, if the clist returned an event...
+ */
+ if (cle) {
+ if (ServiceExists(cle->pszService)) {
+ CallService(cle->pszService, (WPARAM)NULL, (LPARAM)cle);
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM)cle->hContact, (LPARAM)cle->hDbEvent);
+ }
+ } else { // still, we got that message posted.. the event may be waiting in tabSRMMs tray...
+ HandleMenuEntryFromhContact((int)wParam);
+ }
+ break;
+ }
+ case DM_DOCREATETAB: {
+ HWND hWnd = M->FindWindow((HANDLE)lParam);
+ if (hWnd && IsWindow(hWnd)) {
+ struct TContainerData *pContainer = 0;
+
+ SendMessage(hWnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
+ if (pContainer) {
+ int iTabs = TabCtrl_GetItemCount(GetDlgItem(pContainer->hwnd, IDC_MSGTABS));
+ if (iTabs == 1)
+ SendMessage(pContainer->hwnd, WM_CLOSE, 0, 1);
+ else
+ SendMessage(hWnd, WM_CLOSE, 0, 1);
+
+ CreateNewTabForContact((struct TContainerData *)wParam, (HANDLE)lParam, 0, NULL, TRUE, TRUE, FALSE, 0);
+ }
+ }
+ break;
+ }
+ case DM_DOCREATETAB_CHAT: {
+ SESSION_INFO *si = SM_FindSessionByHWND((HWND)lParam);
+
+ if (si && IsWindow(si->hWnd)) {
+ struct TContainerData *pContainer = 0;
+
+ SendMessage(si->hWnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
+ if (pContainer) {
+ int iTabs = TabCtrl_GetItemCount(GetDlgItem(pContainer->hwnd, 1159));
+ if (iTabs == 1)
+ SendMessage(pContainer->hwnd, WM_CLOSE, 0, 1);
+ else
+ SendMessage(si->hWnd, WM_CLOSE, 0, 1);
+
+ si->hWnd = CreateNewRoom((struct TContainerData *)wParam, si, TRUE, 0, 0);
+ }
+ }
+ break;
+ }
+ case DM_SENDMESSAGECOMMANDW:
+ SendMessageCommand_W(wParam, lParam);
+ if (lParam)
+ free((void *)lParam);
+ return(0);
+
+ case DM_SENDMESSAGECOMMAND:
+ SendMessageCommand(wParam, lParam);
+ if (lParam)
+ free((void *)lParam);
+ return(0);
+ /*
+ * sent from the popup to "dismiss" the event. we should do this in the main thread
+ */
+ case DM_REMOVECLISTEVENT:
+ CallService(MS_CLIST_REMOVEEVENT, wParam, lParam);
+ CallService(MS_DB_EVENT_MARKREAD, wParam, lParam);
+ return(0);
+
+ case DM_SETLOCALE: {
+ HKL hkl = (HKL)lParam;
+ HANDLE hContact = (HANDLE)wParam;
+
+ HWND hWnd = M->FindWindow(hContact);
+
+ if(hWnd) {
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ if(dat) {
+ DBVARIANT dbv;
+
+ if(hkl) {
+ dat->hkl = hkl;
+ PostMessage(dat->hwnd, DM_SETLOCALE, 0, 0);
+ }
+ if(0 == M->GetTString(hContact, SRMSGMOD_T, "locale", &dbv)) {
+ GetLocaleID(dat, dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ UpdateReadChars(dat);
+ }
+ }
+ }
+ return(0);
+ }
+ /*
+ * react to changes in the desktop composition state
+ * (enable/disable DWM, change to a non-aero visual style
+ * or classic Windows theme
+ */
+ case WM_DWMCOMPOSITIONCHANGED: {
+ bool fNewAero = M->getAeroState(); // refresh dwm state
+ SendMessage(hwndDlg, WM_THEMECHANGED, 0, 0);
+ TContainerData *pContainer = pFirstContainer;
+
+ while (pContainer) {
+ if(fNewAero)
+ SetAeroMargins(pContainer);
+ else {
+ MARGINS m = {0};
+
+ if(M->m_pfnDwmExtendFrameIntoClientArea)
+ M->m_pfnDwmExtendFrameIntoClientArea(pContainer->hwnd, &m);
+ }
+ if(pContainer->SideBar->isActive())
+ RedrawWindow(GetDlgItem(pContainer->hwnd, 5000), NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW); // the container for the sidebar buttons
+ RedrawWindow(pContainer->hwnd, NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
+ pContainer = pContainer->pNextContainer;
+ }
+ M->BroadcastMessage(WM_DWMCOMPOSITIONCHANGED, 0, 0);
+ break;
+ }
+
+ /*
+ * this message is fired when the user changes desktop color
+ * settings (Desktop->personalize)
+ * the handler reconfigures the aero-related skin images for
+ * tabs and buttons to match the new desktop color theme.
+ */
+ case WM_DWMCOLORIZATIONCOLORCHANGED: {
+ M->getAeroState();
+ Skin->setupAeroSkins();
+ CSkin::initAeroEffect();
+ break;
+ }
+
+ /*
+ * user has changed the visual style or switched to/from
+ * classic Windows theme
+ */
+ case WM_THEMECHANGED: {
+ struct TContainerData *pContainer = pFirstContainer;
+
+ M->getAeroState();
+ Skin->setupTabCloseBitmap();
+ CSkin::initAeroEffect();
+ PluginConfig.m_ncm.cbSize = sizeof(NONCLIENTMETRICS);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &PluginConfig.m_ncm, 0);
+ FreeTabConfig();
+ ReloadTabConfig();
+ while (pContainer) {
+ SendMessage(GetDlgItem(pContainer->hwnd, IDC_MSGTABS), EM_THEMECHANGED, 0, 0);
+ BroadCastContainer(pContainer, EM_THEMECHANGED, 0, 0);
+ pContainer = pContainer->pNextContainer;
+ }
+ break;
+ }
+
+ case DM_SPLITSENDACK: {
+ ACKDATA ack = {0};
+ struct SendJob *job = sendQueue->getJobByIndex((int)wParam);
+
+ ack.hContact = job->hOwner;
+ ack.hProcess = job->hSendId;
+ ack.type = ACKTYPE_MESSAGE;
+ ack.result = ACKRESULT_SUCCESS;
+
+ if (job->hOwner && job->iAcksNeeded && job->hOwner && job->iStatus == SendQueue::SQ_INPROGRESS) {
+ if (IsWindow(job->hwndOwner))
+ ::SendMessage(job->hwndOwner, HM_EVENTSENT, (WPARAM)MAKELONG(wParam, 0), (LPARAM)&ack);
+ else
+ sendQueue->ackMessage(0, (WPARAM)MAKELONG(wParam, 0), (LPARAM)&ack);
+ }
+ return 0;
+ }
+
+ case DM_LOGSTATUSCHANGE:
+ CGlobals::logStatusChange(wParam, reinterpret_cast<CContactCache *>(lParam));
+ return(0);
+
+ case DM_MUCFLASHWORKER: {
+ FLASH_PARAMS *p = reinterpret_cast<FLASH_PARAMS*>(lParam);
+
+ if(1 == wParam) {
+ CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)p->hContact, 1);
+ p->bActiveTab = TRUE;
+ p->bInactive = FALSE;
+ p->bMustAutoswitch = p->bMustFlash = FALSE;
+ }
+
+ if(2 == wParam) {
+ p->bActiveTab = TRUE;
+ p->bInactive = FALSE;
+ p->bMustAutoswitch = p->bMustFlash = FALSE;
+ SendMessage(p->hWnd, DM_ACTIVATEME, 0, 0);
+ }
+ DoFlashAndSoundWorker(p);
+ return(0);
+ }
+
+ case WM_POWERBROADCAST:
+ case WM_DISPLAYCHANGE: {
+ struct TContainerData *pContainer = pFirstContainer;
+
+ while (pContainer) {
+ if (CSkin::m_skinEnabled) { // invalidate cached background DCs for skinned containers
+ pContainer->oldDCSize.cx = pContainer->oldDCSize.cy = 0;
+ SelectObject(pContainer->cachedDC, pContainer->oldHBM);
+ DeleteObject(pContainer->cachedHBM);
+ DeleteDC(pContainer->cachedDC);
+ pContainer->cachedDC = 0;
+ RedrawWindow(pContainer->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME);
+ }
+ pContainer = pContainer->pNextContainer;
+ }
+ break;
+ }
+
+ case WM_ACTIVATE:
+ if (LOWORD(wParam) != WA_ACTIVE)
+ SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
+ return 0;
+
+ case WM_CLOSE:
+ return 0;
+
+ case WM_TIMER:
+ if(wParam == TIMERID_SENDLATER) {
+ /*
+ * send heartbeat to each open container (to manage autoclose
+ * feature)
+ */
+ TContainerData *pContainer = pFirstContainer;
+ /*
+ * send heartbeat to each container, they use this to update
+ * dynamic content (i.e. local time in the info panel).
+ */
+ while(pContainer) {
+ SendMessage(pContainer->hwnd, WM_TIMER, TIMERID_HEARTBEAT, 0);
+ pContainer = pContainer->pNextContainer;
+ }
+ /*
+ * process send later contacts and jobs, if enough time has elapsed
+ */
+ if(sendLater->isAvail() && !sendLater->isInteractive() && (time(0) - sendLater->lastProcessed()) > CSendLater::SENDLATER_PROCESS_INTERVAL) {
+ sendLater->setLastProcessed(time(0));
+
+ /*
+ * check the list of contacts that may have new send later jobs
+ * (added on user's request)
+ */
+ sendLater->processContacts();
+
+ /*
+ * start processing the job list
+ */
+ if(!sendLater->isJobListEmpty()) {
+ KillTimer(hwndDlg, wParam);
+ sendLater->startJobListProcess();
+ SetTimer(hwndDlg, TIMERID_SENDLATER_TICK, TIMEOUT_SENDLATER_TICK, 0);
+ }
+ }
+ }
+ /*
+ * process one entry per tick (default: 200ms)
+ * TODO better timings, possibly slow down when many jobs are in the
+ * queue.
+ */
+ else if(wParam == TIMERID_SENDLATER_TICK) {
+ if(!sendLater->haveJobs()) {
+ KillTimer(hwndDlg, wParam);
+ SetTimer(hwndDlg, TIMERID_SENDLATER, TIMEOUT_SENDLATER, 0);
+ sendLater->qMgrUpdate(true);
+ }
+ else
+ sendLater->processCurrentJob();
+ }
+ break;
+
+ case WM_DESTROY: {
+ KillTimer(hwndDlg, TIMERID_SENDLATER_TICK);
+ KillTimer(hwndDlg, TIMERID_SENDLATER);
+ DestroyServiceFunction(hSvcHotkeyProcessor);
+ break;
+ }
+ }
+ return(DefWindowProc(hwndDlg, msg, wParam, lParam));
+}
diff --git a/plugins/TabSRMM/src/infopanel.cpp b/plugins/TabSRMM/src/infopanel.cpp
new file mode 100644
index 0000000000..1f6b978493
--- /dev/null
+++ b/plugins/TabSRMM/src/infopanel.cpp
@@ -0,0 +1,1696 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: infopanel.cpp 12702 2010-09-16 02:36:17Z borkra $
+ *
+ * the info area for both im and chat sessions
+ */
+
+#include "commonheaders.h"
+
+TCHAR *xStatusDescr[] = { _T("Angry"), _T("Duck"), _T("Tired"), _T("Party"), _T("Beer"), _T("Thinking"), _T("Eating"),
+ _T("TV"), _T("Friends"), _T("Coffee"), _T("Music"), _T("Business"), _T("Camera"), _T("Funny"),
+ _T("Phone"), _T("Games"), _T("College"), _T("Shopping"), _T("Sick"), _T("Sleeping"),
+ _T("Surfing"), _T("@Internet"), _T("Engineering"), _T("Typing"), _T("Eating... yummy"),
+ _T("Having fun"), _T("Chit chatting"), _T("Crashing"), _T("Going to toilet"), _T("<undef>"),
+ _T("<undef>"), _T("<undef>")
+ };
+
+
+TInfoPanelConfig CInfoPanel::m_ipConfig = {0};
+WNDPROC CTip::m_OldMessageEditProc = 0;
+
+int CInfoPanel::setPanelHandler(TWindowData *dat, WPARAM wParam, LPARAM lParam)
+{
+ if(wParam == 0 && lParam == 0) {
+ dat->Panel->getVisibility();
+ dat->Panel->loadHeight();
+ dat->Panel->showHide();
+ }
+ else {
+ TWindowData *srcDat = (TWindowData *)wParam;
+ if(lParam == 0)
+ dat->Panel->loadHeight();
+ else {
+ if(srcDat && lParam && dat != srcDat && !dat->Panel->isPrivateHeight()) {
+ if(srcDat->bType != dat->bType && M->GetByte("syncAllPanels", 0) == 0)
+ return(0);
+
+ if(dat->pContainer->settings->fPrivate && srcDat->pContainer != dat->pContainer)
+ return(0);
+ dat->panelWidth = -1;
+ dat->Panel->setHeight((LONG)lParam);
+ }
+ }
+ SendMessage(dat->hwnd, WM_SIZE, 0, 0);
+ }
+ return(0);
+}
+
+void CInfoPanel::setActive(const int newActive)
+{
+ m_active = newActive ? true : false;
+}
+
+/**
+ * Load height. Private panel height is indicated by 0xffff for the high word
+ */
+void CInfoPanel::loadHeight()
+{
+ BYTE bSync = M->GetByte("syncAllPanels", 0); // sync muc <> im panels
+
+ m_height = M->GetDword(m_dat->hContact, "panelheight", -1);
+
+ if(m_height == -1 || HIWORD(m_height) == 0) {
+ if(m_dat->pContainer->settings->fPrivate)
+ m_height = m_dat->pContainer->settings->panelheight;
+ else
+ m_height = bSync ? m_defaultHeight : (m_isChat ? m_defaultMUCHeight : m_defaultHeight);
+ m_fPrivateHeight = false;
+ }
+ else {
+ m_fPrivateHeight = true;
+ m_height &= 0x0000ffff;
+ }
+
+ if (m_height <= 0 || m_height > 120) // ensure, corrupted values don't stand a chance
+ m_height = DEGRADE_THRESHOLD; // standard height for 2 lines
+}
+
+/**
+ * Save current panel height to the database
+ *
+ * @param fFlush bool: flush values to database (usually only requested by destructor)
+ */
+void CInfoPanel::saveHeight(bool fFlush)
+{
+ BYTE bSync = M->GetByte("syncAllPanels", 0);
+
+ if (m_height < 110 && m_height >= MIN_PANELHEIGHT) { // only save valid panel splitter positions
+ if(!m_fPrivateHeight) {
+ if(!m_isChat || bSync) {
+ if(m_dat->pContainer->settings->fPrivate)
+ m_dat->pContainer->settings->panelheight = m_height;
+ else {
+ PluginConfig.m_panelHeight = m_height;
+ m_defaultHeight = m_height;
+ if(fFlush)
+ M->WriteDword(SRMSGMOD_T, "panelheight", m_height);
+ }
+ }
+ else if(m_isChat && !bSync) {
+ if(m_dat->pContainer->settings->fPrivate)
+ m_dat->pContainer->settings->panelheight = m_height;
+ else {
+ PluginConfig.m_MUCpanelHeight = m_height;
+ m_defaultMUCHeight = m_height;
+ if(fFlush)
+ M->WriteDword("Chat", "panelheight", m_height);
+ }
+ }
+ }
+ else
+ M->WriteDword(m_dat->hContact, SRMSGMOD_T, "panelheight", MAKELONG(m_height, 0xffff));
+ }
+}
+
+/**
+ * Sets the new height of the panel and broadcasts it to all
+ * open sessions
+ *
+ * @param newHeight LONG: the new height.
+ * @param fBroadcast bool: broadcast the new height to all open sessions, respect
+ * container's private setting flag.
+ */
+void CInfoPanel::setHeight(LONG newHeight, bool fBroadcast)
+{
+ if(newHeight < MIN_PANELHEIGHT || newHeight > 100)
+ return;
+
+ m_height = newHeight;
+
+ if(fBroadcast) {
+ if(!m_fPrivateHeight) {
+ if(!m_dat->pContainer->settings->fPrivate)
+ M->BroadcastMessage(DM_SETINFOPANEL, (WPARAM)m_dat, (LPARAM)newHeight);
+ else
+ ::BroadCastContainer(m_dat->pContainer, DM_SETINFOPANEL, (WPARAM)m_dat, (LPARAM)newHeight);
+ }
+ saveHeight();
+ }
+}
+
+void CInfoPanel::Configure() const
+{
+ Utils::showDlgControl(m_dat->hwnd, IDC_PANELSPLITTER, m_active ? SW_SHOW : SW_HIDE);
+}
+
+void CInfoPanel::showHide() const
+{
+ HBITMAP hbm = (m_active && m_dat->pContainer->avatarMode != 3) ? m_dat->hOwnPic : (m_dat->ace ? m_dat->ace->hbmPic : PluginConfig.g_hbmUnknown);
+ BITMAP bm;
+ HWND hwndDlg = m_dat->hwnd;
+
+ if(!m_isChat) {
+ ::ShowWindow(m_dat->hwndPanelPicParent, m_active && (m_dat->hwndPanelPic || m_dat->hwndFlash) ? SW_SHOW : SW_HIDE);
+ //
+ m_dat->iRealAvatarHeight = 0;
+ ::AdjustBottomAvatarDisplay(m_dat);
+ ::GetObject(hbm, sizeof(bm), &bm);
+ ::CalcDynamicAvatarSize(m_dat, &bm);
+
+ if (m_active) {
+ if(m_dat->hwndContactPic) {
+ ::DestroyWindow(m_dat->hwndContactPic);
+ m_dat->hwndContactPic=NULL;
+ }
+ ::GetAvatarVisibility(hwndDlg, m_dat);
+ Configure();
+ InvalidateRect(hwndDlg, NULL, FALSE);
+ }
+ Utils::showDlgControl(hwndDlg, IDC_PANELSPLITTER, m_active ? SW_SHOW : SW_HIDE);
+ ::SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ ::InvalidateRect(GetDlgItem(hwndDlg, IDC_CONTACTPIC), NULL, TRUE);
+ ::SetAeroMargins(m_dat->pContainer);
+ if(M->isAero())
+ ::InvalidateRect(GetParent(hwndDlg), NULL, FALSE);
+ ::DM_ScrollToBottom(m_dat, 0, 1);
+ }
+ else {
+ Utils::showDlgControl(hwndDlg, IDC_PANELSPLITTER, m_active ? SW_SHOW : SW_HIDE);
+
+ if (m_active) {
+ Configure();
+ ::InvalidateRect(hwndDlg, NULL, FALSE);
+ }
+
+ ::SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ ::SetAeroMargins(m_dat->pContainer);
+ if(M->isAero())
+ ::InvalidateRect(GetParent(hwndDlg), NULL, FALSE);
+ ::DM_ScrollToBottom(m_dat, 0, 1);
+ }
+}
+
+/**
+ * Decide if info panel must be visible for this session. Uses container setting and,
+ * if applicable, local (per contact) override.
+ *
+ * @return bool: panel is visible for this session
+ */
+bool CInfoPanel::getVisibility()
+{
+ if (m_dat->hContact == 0) {
+ setActive(false); // no info panel, if no hcontact
+ return(false);
+ }
+
+ BYTE bDefault = (m_dat->pContainer->dwFlags & CNT_INFOPANEL) ? 1 : 0;
+ BYTE bContact = M->GetByte(m_dat->hContact, "infopanel", 0);
+
+ BYTE visible = (bContact == 0 ? bDefault : (bContact == (BYTE)-1 ? 0 : 1));
+ setActive(visible);
+ return(m_active);
+}
+
+void CInfoPanel::mapRealRect(const RECT& rcSrc, RECT& rcDest, const SIZE& sz)
+{
+ rcDest.left = rcSrc.left;
+ rcDest.right = rcDest.left + sz.cx;
+ rcDest.top = rcSrc.top + (((rcSrc.bottom - rcSrc.top) - sz.cy) / 2);
+ rcDest.bottom = rcDest.top + sz.cy;
+}
+
+/**
+ * create an underlined version of the original font and select it
+ * in the given device context
+ *
+ * returns the previosuly selected font
+ *
+ * caller should not forget to delete the font!
+ */
+HFONT CInfoPanel::setUnderlinedFont(const HDC hdc, HFONT hFontOrig)
+{
+ LOGFONT lf;
+
+ ::GetObject(hFontOrig, sizeof(lf), &lf);
+ lf.lfUnderline = 1;
+
+ HFONT hFontNew = ::CreateFontIndirect(&lf);
+ return(reinterpret_cast<HFONT>(::SelectObject(hdc, hFontNew)));
+}
+/**
+ * Render the info panel background.
+ *
+ * @param hdc HDC: target device context
+ * @param rc RECT&: target rectangle
+ * @param item CSkinItem *: The item to render in non-aero mode
+ * @param fAero bool: aero active
+ */
+void CInfoPanel::renderBG(const HDC hdc, RECT& rc, CSkinItem *item, bool fAero, bool fAutoCalc) const
+{
+ if(m_active) {
+
+ if(fAutoCalc)
+ rc.bottom = m_height + 1;
+ if(fAero) {
+ RECT rcBlack = rc;
+ rc.bottom -= 2;
+ ::FillRect(hdc, &rc, CSkin::m_BrushBack);
+ CSkin::ApplyAeroEffect(hdc, &rc, CSkin::AERO_EFFECT_AREA_INFOPANEL);
+ rcBlack.top = rc.bottom;// + 1;
+ rcBlack.bottom = rcBlack.top + 2;
+ if(CSkin::m_pCurrentAeroEffect && CSkin::m_pCurrentAeroEffect->m_clrBack != 0)
+ ::DrawAlpha(hdc, &rcBlack, CSkin::m_pCurrentAeroEffect->m_clrBack, 90, CSkin::m_pCurrentAeroEffect->m_clrBack, 0,
+ 0, 0, 1, 0);
+ }
+ else {
+ if(CSkin::m_skinEnabled) {
+ rc.bottom -= 2;
+ CSkin::SkinDrawBG(m_dat->hwnd, m_dat->pContainer->hwnd, m_dat->pContainer, &rc, hdc);
+ item = &SkinItems[ID_EXTBKINFOPANELBG];
+ /*
+ * if new (= tabsrmm 3.x) skin item is not defined, use the old info panel
+ * field background items. That should break less skins
+ */
+ if(!item->IGNORED)
+ CSkin::DrawItem(hdc, &rc, item);
+ } else {
+ rc.bottom -= 2;
+ ::DrawAlpha(hdc, &rc, PluginConfig.m_ipBackgroundGradient, 100, PluginConfig.m_ipBackgroundGradientHigh, 0, 17,
+ 0, 0, 0);
+ if(fAutoCalc) {
+ rc.top = rc.bottom - 1;
+ rc.left--; rc.right++;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * render the content of the info panel. The target area is derived from the
+ * precalculated RECT structures in _MessageWindowData (calculated in the
+ * message window's WM_SIZE handler).
+ *
+ * @param hdc HDC: target device context
+ */
+void CInfoPanel::renderContent(const HDC hdc)
+{
+ if(m_active) {
+ if(!m_isChat) {
+ RECT rc;
+
+ /*
+ * panel picture
+ */
+
+ DRAWITEMSTRUCT dis = {0};
+
+ dis.rcItem = m_dat->rcPic;
+ dis.hDC = hdc;
+ dis.hwndItem = m_dat->hwnd;
+ if(::MsgWindowDrawHandler(0, (LPARAM)&dis, m_dat) == 0) {
+ ::PostMessage(m_dat->hwnd, WM_SIZE, 0, 1);
+ ::PostMessage(m_dat->hwnd, DM_FORCEREDRAW, 0, 0);
+ }
+
+ rc = m_dat->rcNick;
+ if(m_height >= DEGRADE_THRESHOLD) {
+ rc.top -= 2;// rc.bottom += 6;
+ }
+ RenderIPNickname(hdc, rc);
+ if(m_height >= DEGRADE_THRESHOLD) {
+ rc = m_dat->rcUIN;
+ RenderIPUIN(hdc, rc);
+ }
+ rc = m_dat->rcStatus;
+ RenderIPStatus(hdc, rc);
+ }
+ else {
+ RECT rc;
+ rc = m_dat->rcNick;
+
+ if(m_height >= DEGRADE_THRESHOLD)
+ rc.top -= 2; rc.bottom -= 2;
+
+ Chat_RenderIPNickname(hdc, rc);
+ if(m_height >= DEGRADE_THRESHOLD) {
+ rc = m_dat->rcUIN;
+ Chat_RenderIPSecondLine(hdc, rc);
+ }
+ }
+ }
+}
+
+/**
+ * Render the nickname in the info panel.
+ * This will also show the status message (if one is available)
+ * The field will dynamically adjust itself to the available info panel space. If
+ * the info panel is too small to show both nick and UIN fields, this field will show
+ * the UIN _instead_ of the nickname (most people have the nickname in the title
+ * bar anyway).
+ *
+ * @param hdc HDC: target DC for drawing
+ *
+ * @param rcItem RECT &: target rectangle
+ */
+void CInfoPanel::RenderIPNickname(const HDC hdc, RECT& rcItem)
+{
+ const TCHAR* szStatusMsg = NULL;
+ CSkinItem* item = &SkinItems[ID_EXTBKINFOPANEL];
+ const TCHAR* szTextToShow = 0;
+ bool fShowUin = false;
+ COLORREF clr = 0;
+
+ if(m_height < DEGRADE_THRESHOLD) {
+ szTextToShow = m_dat->cache->getUIN();
+ fShowUin = true;
+ } else
+ szTextToShow = m_dat->cache->getNick();
+
+ szStatusMsg = m_dat->cache->getStatusMsg();
+
+ ::SetBkMode(hdc, TRANSPARENT);
+
+ rcItem.left += 2;
+ if (szTextToShow[0]) {
+ HFONT hOldFont = 0;
+ HICON xIcon = 0;
+
+ xIcon = ::GetXStatusIcon(m_dat);
+
+ if (xIcon) {
+ ::DrawIconEx(hdc, rcItem.left, (rcItem.bottom + rcItem.top - PluginConfig.m_smcyicon) / 2, xIcon, PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, 0, 0, DI_NORMAL | DI_COMPAT);
+ ::DestroyIcon(xIcon);
+ rcItem.left += 21;
+ }
+
+ if(fShowUin) {
+ hOldFont = reinterpret_cast<HFONT>(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_UIN]));
+ clr = m_ipConfig.clrs[IPFONTID_UIN];
+ }
+ else {
+ hOldFont = reinterpret_cast<HFONT>(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_NICK]));
+ clr = m_ipConfig.clrs[IPFONTID_NICK];
+ }
+
+ m_szNick.cx = m_szNick.cy = 0;
+
+ if (szStatusMsg) {
+ SIZE sStatusMsg, sMask;
+ DWORD dtFlags, dtFlagsNick;
+
+ ::GetTextExtentPoint32(hdc, szTextToShow, lstrlen(szTextToShow), &m_szNick);
+ ::GetTextExtentPoint32(hdc, _T("A"), 1, &sMask);
+ ::GetTextExtentPoint32(hdc, szStatusMsg, lstrlen(szStatusMsg), &sStatusMsg);
+ dtFlagsNick = DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_NOPREFIX;
+ if ((m_szNick.cx + sStatusMsg.cx + 6) < (rcItem.right - rcItem.left) || (rcItem.bottom - rcItem.top) < (2 * sMask.cy))
+ dtFlagsNick |= DT_VCENTER;
+ mapRealRect(rcItem, m_rcNick, m_szNick);
+
+ if(m_hoverFlags & HOVER_NICK)
+ setUnderlinedFont(hdc, fShowUin ? m_ipConfig.hFonts[IPFONTID_UIN] : m_ipConfig.hFonts[IPFONTID_NICK]);
+
+ CSkin::RenderText(hdc, m_dat->hThemeIP, szTextToShow, &rcItem, dtFlagsNick, CSkin::m_glowSize, clr);
+
+ HFONT hFont = reinterpret_cast<HFONT>(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_STATUS]));
+ if(m_hoverFlags & HOVER_NICK)
+ ::DeleteObject(hFont);
+
+ clr = m_ipConfig.clrs[IPFONTID_STATUS];
+
+ rcItem.left += (m_szNick.cx + 10);
+
+ if (!(dtFlagsNick & DT_VCENTER))
+ dtFlags = DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX;
+ else
+ dtFlags = DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX | DT_VCENTER;
+
+
+ rcItem.right -= 3;
+ if (rcItem.left + 30 < rcItem.right)
+ CSkin::RenderText(hdc, m_dat->hThemeIP, szStatusMsg, &rcItem, dtFlags, CSkin::m_glowSize, clr);
+ } else {
+ GetTextExtentPoint32(hdc, szTextToShow, lstrlen(szTextToShow), &m_szNick);
+ mapRealRect(rcItem, m_rcNick, m_szNick);
+ if(m_hoverFlags & HOVER_NICK)
+ setUnderlinedFont(hdc, fShowUin ? m_ipConfig.hFonts[IPFONTID_UIN] : m_ipConfig.hFonts[IPFONTID_NICK]);
+ CSkin::RenderText(hdc, m_dat->hThemeIP, szTextToShow, &rcItem, DT_SINGLELINE | DT_VCENTER | DT_WORD_ELLIPSIS | DT_NOPREFIX, CSkin::m_glowSize, clr);
+ if(m_hoverFlags & HOVER_NICK)
+ ::DeleteObject(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_UIN]));
+ }
+ if (hOldFont)
+ ::SelectObject(hdc, hOldFont);
+ }
+}
+
+/**
+ * Draws the UIN field for the info panel.
+ *
+ * @param hdc HDC: device context for drawing.
+ * @param rcItem RECT &: target rectangle for drawing
+ */
+void CInfoPanel::RenderIPUIN(const HDC hdc, RECT& rcItem)
+{
+ TCHAR szBuf[256];
+ HFONT hOldFont = 0;
+ CSkinItem* item = &SkinItems[ID_EXTBKINFOPANEL];
+ const TCHAR* tszUin = m_dat->cache->getUIN();
+ COLORREF clr = 0;
+
+ ::SetBkMode(hdc, TRANSPARENT);
+
+ rcItem.left += 2;
+
+ if(m_hoverFlags & HOVER_UIN)
+ hOldFont = setUnderlinedFont(hdc, m_ipConfig.hFonts[IPFONTID_UIN]);
+ else
+ hOldFont = reinterpret_cast<HFONT>(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_UIN]));
+ clr = m_ipConfig.clrs[IPFONTID_UIN];
+
+ if (tszUin[0]) {
+ SIZE sUIN;
+ if (m_dat->idle) {
+ time_t diff = time(NULL) - m_dat->idle;
+ int i_hrs = diff / 3600;
+ int i_mins = (diff - i_hrs * 3600) / 60;
+ mir_sntprintf(szBuf, safe_sizeof(szBuf), CTranslator::get(CTranslator::GEN_IP_IDLENOTICE), tszUin, i_hrs, i_mins);
+ ::GetTextExtentPoint32(hdc, szBuf, lstrlen(szBuf), &sUIN);
+ mapRealRect(rcItem, m_rcUIN, sUIN);
+ CSkin::RenderText(hdc, m_dat->hThemeIP, szBuf, &rcItem, DT_SINGLELINE | DT_VCENTER, CSkin::m_glowSize, clr);
+ } else {
+ ::GetTextExtentPoint32(hdc, tszUin, lstrlen(tszUin), &sUIN);
+ mapRealRect(rcItem, m_rcUIN, sUIN);
+ CSkin::RenderText(hdc, m_dat->hThemeIP, tszUin, &rcItem, DT_SINGLELINE | DT_VCENTER, CSkin::m_glowSize, clr);
+ }
+ }
+ if(m_hoverFlags & HOVER_UIN)
+ ::DeleteObject(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_UIN]));
+
+ if (hOldFont)
+ ::SelectObject(hdc, hOldFont);
+}
+
+/**
+ * Render the info panel status field. Usually in the 2nd line, right aligned
+ * @param hdc : target device context
+ */
+void CInfoPanel::RenderIPStatus(const HDC hdc, RECT& rcItem)
+{
+ const char* szProto = m_dat->cache->getActiveProto();
+ SIZE sProto = {0}, sStatus = {0}, sTime = {0};
+ DWORD oldPanelStatusCX = m_dat->panelStatusCX;
+ RECT rc;
+ HFONT hOldFont = 0;
+ CSkinItem *item = &SkinItems[ID_EXTBKINFOPANEL];
+ const TCHAR *szFinalProto = NULL;
+ TCHAR szResult[80];
+ COLORREF clr = 0;
+
+ szResult[0] = 0;
+
+ if (m_dat->szStatus[0])
+ GetTextExtentPoint32(hdc, m_dat->szStatus, lstrlen(m_dat->szStatus), &sStatus);
+
+ /*
+ * figure out final account name
+ */
+ szFinalProto = m_dat->cache->getRealAccount();
+
+ if (szFinalProto) {
+ SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_PROTO]);
+ GetTextExtentPoint32(hdc, szFinalProto, lstrlen(szFinalProto), &sProto);
+ }
+
+ if (m_dat->hTimeZone) {
+ tmi.printDateTime(m_dat->hTimeZone, _T("t"), szResult, SIZEOF(szResult), 0);
+ GetTextExtentPoint32(hdc, szResult, lstrlen(szResult), &sTime);
+ }
+
+ m_dat->panelStatusCX = 3 + sStatus.cx + sProto.cx + 14 + (m_dat->hClientIcon ? 20 : 0) + sTime.cx + 13;;
+
+ if(m_dat->panelStatusCX != oldPanelStatusCX) {
+ SendMessage(m_dat->hwnd, WM_SIZE, 0, 0);
+ rcItem = m_dat->rcStatus;
+ }
+
+ SetBkMode(hdc, TRANSPARENT);
+ rc = rcItem;
+ rc.left += 2;
+ rc.right -=3;
+
+ if(szResult[0]) {
+ HFONT oldFont = 0;
+
+ ::DrawIconEx(hdc, rcItem.left, (rcItem.bottom - rcItem.top) / 2 - 8 + rcItem.top, PluginConfig.g_iconClock, 16, 16, 0, 0, DI_NORMAL);
+
+ oldFont = (HFONT)SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_TIME]);
+
+ clr = m_ipConfig.clrs[IPFONTID_TIME];
+ rcItem.left += 16;
+ CSkin::RenderText(hdc, m_dat->hThemeIP, szResult, &rcItem, DT_SINGLELINE | DT_VCENTER, CSkin::m_glowSize, clr);
+ SelectObject(hdc, oldFont);
+ rc.left += (sTime.cx + 20);
+ }
+
+ hOldFont = (HFONT)SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_STATUS]);
+
+ if (m_dat->szStatus[0]) {
+ SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_STATUS]);
+ clr = m_ipConfig.clrs[IPFONTID_STATUS];
+ mapRealRect(rc, m_rcStatus, sStatus);
+ if(m_hoverFlags & HOVER_STATUS)
+ setUnderlinedFont(hdc, m_ipConfig.hFonts[IPFONTID_STATUS]);
+ CSkin::RenderText(hdc, m_dat->hThemeIP, m_dat->szStatus, &rc, DT_SINGLELINE | DT_VCENTER, CSkin::m_glowSize, clr);
+ if(m_hoverFlags & HOVER_STATUS)
+ ::DeleteObject(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_STATUS]));
+ }
+ if (szFinalProto) {
+ rc.left = rc.right - sProto.cx - 3 - (m_dat->hClientIcon ? 20 : 0);
+ SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_PROTO]);
+ clr = m_ipConfig.clrs[IPFONTID_PROTO];
+ CSkin::RenderText(hdc, m_dat->hThemeIP, szFinalProto, &rc, DT_SINGLELINE | DT_VCENTER, CSkin::m_glowSize, clr);
+ }
+
+ if (m_dat->hClientIcon)
+ DrawIconEx(hdc, rc.right - 19, (rc.bottom + rc.top - 16) / 2, m_dat->hClientIcon, 16, 16, 0, 0, DI_NORMAL);
+
+ if (hOldFont)
+ SelectObject(hdc, hOldFont);
+}
+
+/**
+ * Draws the Nickname field (first line) in a MUC window
+ *
+ * @param hdc HDC: device context for drawing.
+ * @param rcItem RECT &: target rectangle for drawing
+ */
+void CInfoPanel::Chat_RenderIPNickname(const HDC hdc, RECT& rcItem)
+{
+ SESSION_INFO *si = reinterpret_cast<SESSION_INFO *>(m_dat->si);
+
+ HFONT hOldFont = 0;
+
+ if(si == 0)
+ return;
+
+ ::SetBkMode(hdc, TRANSPARENT);
+ m_szNick.cx = m_szNick.cy = 0;
+
+ if(m_height < DEGRADE_THRESHOLD) {
+ TCHAR tszText[2048];
+
+ mir_sntprintf(tszText, safe_sizeof(tszText), CTranslator::get(CTranslator::GEN_MUC_TOPIC_IS), si->ptszTopic ? si->ptszTopic :
+ CTranslator::get(CTranslator::GEN_MUC_NO_TOPIC));
+
+ hOldFont = reinterpret_cast<HFONT>(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_UIN]));
+ CSkin::RenderText(hdc, m_dat->hThemeIP, tszText, &rcItem, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX | DT_VCENTER,
+ CSkin::m_glowSize, m_ipConfig.clrs[IPFONTID_UIN]);
+ } else {
+ const TCHAR *tszNick = m_dat->cache->getNick();
+
+ hOldFont = reinterpret_cast<HFONT>(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_NICK]));
+ ::GetTextExtentPoint32(hdc, tszNick, lstrlen(tszNick), &m_szNick);
+ mapRealRect(rcItem, m_rcNick, m_szNick);
+
+ if(m_hoverFlags & HOVER_NICK)
+ setUnderlinedFont(hdc, m_ipConfig.hFonts[IPFONTID_NICK]);
+
+ CSkin::RenderText(hdc, m_dat->hThemeIP, tszNick, &rcItem, DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER,
+ CSkin::m_glowSize, m_ipConfig.clrs[IPFONTID_NICK]);
+
+ if(m_hoverFlags & HOVER_NICK)
+ ::DeleteObject(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_NICK]));
+
+ rcItem.left += (m_szNick.cx + 4);
+
+ ::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_STATUS]);
+ if(si->ptszStatusbarText) {
+ TCHAR *pTmp = _tcschr(si->ptszStatusbarText, ']');
+ pTmp += 2;
+ TCHAR tszTemp[30];
+ if(si->ptszStatusbarText[0] == '[' && pTmp > si->ptszStatusbarText && ((pTmp - si->ptszStatusbarText) < (size_t)30)) {
+ mir_sntprintf(tszTemp, pTmp - si->ptszStatusbarText, _T("%s"), si->ptszStatusbarText);
+ CSkin::RenderText(hdc, m_dat->hThemeIP, tszTemp, &rcItem, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX | DT_VCENTER,
+ CSkin::m_glowSize, m_ipConfig.clrs[IPFONTID_STATUS]);
+ }
+ }
+ }
+ if (hOldFont)
+ ::SelectObject(hdc, hOldFont);
+}
+/**
+ * Draw 2nd line of text in the info panel.
+ * @param hdc : target device context
+ * @param rcItem : target rectangle
+ */
+void CInfoPanel::Chat_RenderIPSecondLine(const HDC hdc, RECT& rcItem)
+{
+ HFONT hOldFont = 0;
+ SIZE szTitle;
+ TCHAR szPrefix[100];
+ COLORREF clr = 0;
+
+ SESSION_INFO *si = reinterpret_cast<SESSION_INFO *>(m_dat->si);
+
+ if(si == 0)
+ return;
+
+ hOldFont = reinterpret_cast<HFONT>(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_UIN]));
+ clr = m_ipConfig.clrs[IPFONTID_UIN];
+
+ const TCHAR *szTopicTitle = CTranslator::get(CTranslator::GEN_MUC_TOPIC_IS);
+ mir_sntprintf(szPrefix, 100, szTopicTitle, _T(""));
+ ::GetTextExtentPoint32(hdc, szPrefix, lstrlen(szPrefix), &szTitle);
+ mapRealRect(rcItem, m_rcUIN, szTitle);
+ if(m_hoverFlags & HOVER_UIN)
+ setUnderlinedFont(hdc, m_ipConfig.hFonts[IPFONTID_UIN]);
+ rcItem.right -= 3;
+ CSkin::RenderText(hdc, m_dat->hThemeIP, szPrefix, &rcItem, DT_SINGLELINE | DT_NOPREFIX | DT_TOP, CSkin::m_glowSize, clr);
+ rcItem.left += (szTitle.cx + 4);
+ if(m_hoverFlags & HOVER_UIN)
+ ::DeleteObject(::SelectObject(hdc, m_ipConfig.hFonts[IPFONTID_UIN]));
+ if(si->ptszTopic && lstrlen(si->ptszTopic) > 1)
+ CSkin::RenderText(hdc, m_dat->hThemeIP, si->ptszTopic, &rcItem, DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX | DT_TOP, CSkin::m_glowSize, clr);
+ else
+ CSkin::RenderText(hdc, m_dat->hThemeIP, CTranslator::get(CTranslator::GEN_MUC_NO_TOPIC), &rcItem, DT_TOP| DT_SINGLELINE | DT_NOPREFIX, CSkin::m_glowSize, clr);
+
+ if(hOldFont)
+ ::SelectObject(hdc, hOldFont);
+}
+/**
+ * Invalidate the info panel rectangle
+ */
+void CInfoPanel::Invalidate(BOOL fErase) const
+{
+ RECT rc;
+
+ if(m_active) {
+ ::GetClientRect(m_dat->hwnd, &rc);
+ rc.bottom = m_height;
+ ::InvalidateRect(m_dat->hwnd, &rc, fErase);
+ }
+}
+
+/**
+ * build the left click contextual menu for the info panel
+ * @return HMENU: menu handle for the fully prepared menu
+ */
+HMENU CInfoPanel::constructContextualMenu() const
+{
+ MENUITEMINFO mii = {0};
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA | MIIM_ID | MIIM_BITMAP | MIIM_STRING;
+ mii.hbmpItem = HBMMENU_CALLBACK;
+
+ if(!(m_hoverFlags & HOVER_NICK))
+ return(0);
+
+ HMENU m = ::CreatePopupMenu();
+
+ if(m_hoverFlags & HOVER_NICK) {
+ Utils::addMenuItem(m, mii, ::LoadSkinnedIcon(SKINICON_OTHER_USERDETAILS), CTranslator::get(CTranslator::GEN_IP_MENU_USER_DETAILS),
+ IDC_NAME, 0);
+ Utils::addMenuItem(m, mii, ::LoadSkinnedIcon(SKINICON_OTHER_HISTORY), CTranslator::get(CTranslator::GEN_IP_MENU_HISTORY),
+ m_isChat ? IDC_CHAT_HISTORY : IDC_HISTORY, 0);
+ if(!m_isChat)
+ Utils::addMenuItem(m, mii, PluginConfig.g_iconContainer, CTranslator::get(CTranslator::GEN_IP_MENU_MSGPREFS),
+ ID_MESSAGELOGSETTINGS_FORTHISCONTACT, 1);
+ else {
+ ::AppendMenu(m, MF_STRING, IDC_CHANMGR, CTranslator::get(CTranslator::GEN_IP_MENU_ROOMPREFS));
+ if(GCW_SERVER & m_dat->si->iType)
+ ::EnableMenuItem(m, IDC_CHANMGR, MF_BYCOMMAND | MF_GRAYED);
+ }
+ ::AppendMenu(m, MF_SEPARATOR, 1000, 0);
+ Utils::addMenuItem(m, mii, PluginConfig.g_buttonBarIcons[6], CTranslator::get(CTranslator::GEN_MSG_CLOSE), IDC_SAVE, 4);
+ }
+ ::AppendMenu(m, MF_SEPARATOR, 1000, 0);
+ ::AppendMenu(m, MF_STRING, CMD_IP_COPY, CTranslator::get(CTranslator::GEN_IP_MENU_COPY));
+
+ return(m);
+}
+
+/**
+ * process internal menu commands from info panel fields
+ * if this does not handle the selected command, Utils::CmdDispatcher() will be called
+ * to chain the command through message window command handlers.
+ *
+ * @param cmd command id
+ * @return 0 if command was processed, != 0 otherwise
+ */
+
+LRESULT CInfoPanel::cmdHandler(UINT cmd)
+{
+ switch(cmd) {
+ case CMD_IP_COPY:
+ if(m_hoverFlags & HOVER_NICK) {
+ Utils::CopyToClipBoard(const_cast<wchar_t *>(m_dat->cache->getNick()), m_dat->hwnd);
+ return(S_OK);
+ }
+ else if(m_hoverFlags & HOVER_UIN) {
+ Utils::CopyToClipBoard(m_isChat ? m_dat->si->ptszTopic : const_cast<wchar_t *>(m_dat->cache->getUIN()), m_dat->hwnd);
+ return(S_OK);
+ }
+ break;
+ case IDC_CHAT_HISTORY:
+ case IDC_CHANMGR:
+ if(m_isChat) {
+ SendMessage(m_dat->hwnd, WM_COMMAND, cmd, 0);
+ return(S_OK);
+ }
+ break;
+ default:
+ break;
+ }
+ return(S_FALSE); // not handled
+}
+
+/**
+ * handle mouse clicks on the info panel.
+ *
+ * @param pt: mouse cursor pos
+ */
+void CInfoPanel::handleClick(const POINT& pt)
+{
+ if(!m_active || m_hoverFlags == 0)
+ return;
+
+ if(!m_isChat) {
+ ::KillTimer(m_dat->hwnd, TIMERID_AWAYMSG);
+ m_dat->dwFlagsEx &= ~MWF_SHOW_AWAYMSGTIMER;
+ }
+ HMENU m = constructContextualMenu();
+ if(m) {
+ LRESULT r = ::TrackPopupMenu(m, TPM_RETURNCMD, pt.x, pt.y, 0, m_dat->hwnd, NULL);
+
+ ::DestroyMenu(m);
+ if(S_OK != cmdHandler(r))
+ Utils::CmdDispatcher(Utils::CMD_INFOPANEL, m_dat->hwnd, r, 0, 0, m_dat, m_dat->pContainer);
+ }
+ m_hoverFlags = 0;
+ Invalidate(TRUE);
+}
+
+/**
+ * peforms a hit test on the given position. returns 0, if cursor is NOT
+ * inside any of the 3 relevant hovering areas.
+ *
+ * @param pt POINT (in screen coordinates)
+ * @return Hit test result or 0 if none applies.
+ */
+int CInfoPanel::hitTest(POINT pt)
+{
+ ::ScreenToClient(m_dat->hwnd, &pt);
+
+ if(!m_isChat && ::PtInRect(&m_rcStatus, pt))
+ return(HTSTATUS);
+ else if(::PtInRect(&m_rcNick, pt))
+ return(HTNICK);
+ else if(::PtInRect(&m_rcUIN, pt))
+ return(HTUIN);
+
+ return(HTNIRVANA);
+}
+/**
+ * track mouse movements inside the panel. Needed for tooltip activation
+ * and to hover the info panel fields.
+ *
+ * @param pt : mouse coordinates (screen)
+ */
+void CInfoPanel::trackMouse(POINT& pt)
+{
+ if(!m_active)
+ return;
+
+ int result = hitTest(pt);
+
+ DWORD dwOldHovering = m_hoverFlags;
+ m_hoverFlags = 0;
+
+ switch(result) {
+ case HTSTATUS:
+ m_hoverFlags |= HOVER_STATUS;
+ ::SetCursor(LoadCursor(0, IDC_HAND));
+ break;
+
+ case HTNICK:
+ m_hoverFlags |= HOVER_NICK;
+ ::SetCursor(LoadCursor(0, IDC_HAND));
+ break;
+
+ case HTUIN:
+ ::SetCursor(LoadCursor(0, IDC_HAND));
+ m_hoverFlags |= HOVER_UIN;
+ break;
+ }
+
+ if(m_hoverFlags) {
+ if (!(m_dat->dwFlagsEx & MWF_SHOW_AWAYMSGTIMER)) {
+ ::SetTimer(m_dat->hwnd, TIMERID_AWAYMSG, 1000, 0);
+ m_dat->dwFlagsEx |= MWF_SHOW_AWAYMSGTIMER;
+ }
+ }
+ if(dwOldHovering != m_hoverFlags)
+ Invalidate(TRUE);
+ if(m_hoverFlags == 0)
+ m_dat->dwFlagsEx &= ~MWF_SHOW_AWAYMSGTIMER;
+}
+
+/**
+ * activate a tooltip
+ * @param ctrlId : control id
+ * @param lParam : typically a TCHAR * for the tooltip text
+ */
+void CInfoPanel::showTip(UINT ctrlId, const LPARAM lParam)
+{
+ if (m_active && m_dat->hwndTip) {
+ RECT rc;
+ TCHAR szTitle[256];
+ HWND hwndDlg = m_dat->hwnd;
+
+ ::GetWindowRect(GetDlgItem(hwndDlg, ctrlId), &rc);
+
+ ::SendMessage(m_dat->hwndTip, TTM_TRACKPOSITION, 0, (LPARAM)MAKELONG(rc.left, rc.bottom));
+ if (lParam)
+ m_dat->ti.lpszText = reinterpret_cast<TCHAR *>(lParam);
+ else {
+ TCHAR temp[1024];
+ DBVARIANT dbv = {0};
+ size_t pos;
+ BYTE xStatus = 0;
+
+ if(m_hwndConfig)
+ return;
+
+ mir_sntprintf(temp, 1024, RTF_DEFAULT_HEADER, 0, 0, 0, 30*15);
+
+ tstring *str = new tstring(temp);
+
+ mir_sntprintf(temp, 1024, CTranslator::get(CTranslator::GEN_INFOTIP_STATUSMSG),
+ m_dat->cache->getStatusMsg() ? m_dat->cache->getStatusMsg() : CTranslator::get(CTranslator::GEN_NO_STATUS));
+ str->append(temp);
+
+ if((xStatus = m_dat->cache->getXStatusId())) {
+ TCHAR *tszXStatusName = 0;
+ if(0 == M->GetTString(m_dat->cache->getContact(), m_dat->cache->getProto(), "XStatusName", &dbv))
+ tszXStatusName = dbv.ptszVal;
+ else if(xStatus > 0 && xStatus <= 31)
+ tszXStatusName = xStatusDescr[xStatus - 1];
+
+ if(tszXStatusName) {
+ str->append(CTranslator::get(CTranslator::GEN_INFOTIP_XSTATUS));
+ mir_sntprintf(temp, 1024, _T("%s%s%s"), tszXStatusName, m_dat->cache->getXStatusMsg() ? _T(" / ") : _T(""),
+ m_dat->cache->getXStatusMsg() ? m_dat->cache->getXStatusMsg() : _T(""));
+ str->append(temp);
+ if(dbv.ptszVal)
+ mir_free(dbv.ptszVal);
+ }
+ }
+
+ if(m_dat->cache->getListeningInfo()) {
+ mir_sntprintf(temp, 1024, CTranslator::get(CTranslator::GEN_INFOTIP_LISTENING), m_dat->cache->getListeningInfo());
+ str->append(temp);
+ }
+
+ if(0 == M->GetTString(m_dat->cache->getActiveContact(), m_dat->cache->getActiveProto(), "MirVer", &dbv)) {
+ mir_sntprintf(temp, 1024, CTranslator::get(CTranslator::GEN_INFOTIP_CLIENT), dbv.ptszVal);
+ ::DBFreeVariant(&dbv);
+ str->append(temp);
+ }
+ str->append(_T("}"));
+
+ /*
+ * convert line breaks to rtf
+ */
+ /*
+ while((pos = str.find(_T("\r\n"))) != str.npos) {
+ str.erase(pos, 2);
+ str.insert(pos, _T("\\line "));
+ }
+ */
+ while((pos = str->find(_T("\n"))) != str->npos) {
+ str->erase(pos, 1);
+ str->insert(pos, _T("\\line "));
+ }
+
+ POINT pt;
+ RECT rc = {0, 0, 400, 600};
+ GetCursorPos(&pt);
+ m_tip = new CTip(m_dat->hwnd, m_dat->hContact, str->c_str(), this);
+ delete str;
+ m_tip->show(rc, pt, m_dat->hTabIcon, m_dat->szStatus);
+ return;
+ }
+ mir_sntprintf(szTitle, safe_sizeof(szTitle), CTranslator::get(CTranslator::GEN_IP_TIP_TITLE));
+ ::SendMessage(m_dat->hwndTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&m_dat->ti);
+ ::SendMessage(m_dat->hwndTip, TTM_SETMAXTIPWIDTH, 0, 350);
+
+ ::SendMessage(m_dat->hwndTip, TTM_SETTITLE, 1, (LPARAM)szTitle);
+ ::SendMessage(m_dat->hwndTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&m_dat->ti);
+ ::GetCursorPos(&m_dat->ptTipActivation);
+ }
+}
+
+/**
+ * hide a tooltip (if it was created)
+ * this is only used from outside (i.e. container window dialog)
+ *
+ * hwndNew = window to become active (as reported by WM_ACTIVATE).
+ */
+void CInfoPanel::hideTip(const HWND hwndNew)
+{
+ if(m_tip) {
+ if(hwndNew == m_tip->getHwnd())
+ return;
+ if(::IsWindow(m_tip->getHwnd()))
+ ::DestroyWindow(m_tip->getHwnd());
+ m_tip = 0;
+ }
+}
+
+/**
+ * draw the background (and border) of the parent control that holds the avs-based avatar display
+ * (ACC window class). Only required when support for animated avatars is enabled because
+ * native avatar rendering does not support animated images.
+ * To avoid clipping issues, this is done during WM_ERASEBKGND.
+ */
+INT_PTR CALLBACK CInfoPanel::avatarParentSubclass(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_ERASEBKGND:
+ {
+ /*
+ * parent window of the infopanel ACC control
+ */
+ RECT rc, rcItem;
+ TWindowData* dat = (TWindowData *)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
+
+ if(dat == 0)
+ break;
+
+ GetClientRect(hwnd, &rcItem);
+ rc = rcItem;
+ if(!IsWindowEnabled(hwnd) || !dat->Panel->isActive() || dat->showInfoPic == 0)
+ return(TRUE);
+
+ HDC dcWin = (HDC)wParam;
+
+ if(M->isAero()) {
+ HDC hdc;
+ HBITMAP hbm, hbmOld;
+ LONG cx = rcItem.right - rcItem.left;
+ LONG cy = rcItem.bottom - rcItem.top;
+
+ rc.left -= 3; rc.right += 3;
+ rc.bottom += 2;
+
+ hdc = CreateCompatibleDC(dcWin);
+ hbm = CSkin::CreateAeroCompatibleBitmap(rc, dcWin);
+ hbmOld = (HBITMAP)SelectObject(hdc, hbm);
+
+ if(CSkin::m_pCurrentAeroEffect == 0)
+ FillRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ else {
+ if(CSkin::m_pCurrentAeroEffect->m_finalAlpha == 0)
+ CSkin::ApplyAeroEffect(hdc, &rc, CSkin::AERO_EFFECT_AREA_INFOPANEL, 0);
+ else {
+ FillRect(hdc, &rc, CSkin::m_BrushBack);
+ CSkin::ApplyAeroEffect(hdc, &rc, CSkin::AERO_EFFECT_AREA_INFOPANEL, 0);
+ }
+ }
+ BitBlt(dcWin, 0, 0, cx, cy, hdc, 0, 0, SRCCOPY);
+ SelectObject(hdc, hbmOld);
+ DeleteObject(hbm);
+ DeleteDC(hdc);
+ }
+ else {
+ rc.bottom += 2;
+ rc.left -= 3; rc.right += 3;
+ dat->Panel->renderBG(dcWin, rc, &SkinItems[ID_EXTBKINFOPANELBG], M->isAero(), false);
+ }
+ if(CSkin::m_bAvatarBorderType == 1) {
+ HRGN clipRgn = 0;
+
+ if(dat->hwndPanelPic) {
+ RECT rcPic;
+ GetClientRect(dat->hwndPanelPic, &rcPic);
+ LONG ix = ((rcItem.right - rcItem.left) - rcPic.right) / 2 - 1;
+ LONG iy = ((rcItem.bottom - rcItem.top) - rcPic.bottom) / 2 - 1;
+
+ clipRgn = CreateRectRgn(ix, iy, ix + rcPic.right + 2, iy + rcPic.bottom + 2);
+ }
+ else
+ clipRgn = CreateRectRgn(rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
+ HBRUSH hbr = CreateSolidBrush(CSkin::m_avatarBorderClr);
+ FrameRgn(dcWin, clipRgn, hbr, 1, 1);
+ DeleteObject(hbr);
+ DeleteObject(clipRgn);
+ }
+ return(TRUE);
+ }
+ default:
+ break;
+ }
+ return(DefWindowProc(hwnd, msg, wParam, lParam));
+}
+
+/**
+ * Stub for the dialog procedure. Just handles INITDIALOG and sets
+ * our userdata. Real processing is done by ConfigDlgProc()
+ *
+ * @params Like a normal dialog procedure
+ */
+INT_PTR CALLBACK CInfoPanel::ConfigDlgProcStub(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CInfoPanel *infoPanel = reinterpret_cast<CInfoPanel *>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
+
+ if(infoPanel)
+ return(infoPanel->ConfigDlgProc(hwnd, msg, wParam, lParam));
+
+ switch(msg) {
+ case WM_INITDIALOG: {
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
+ infoPanel = reinterpret_cast<CInfoPanel *>(lParam);
+ return(infoPanel->ConfigDlgProc(hwnd, msg, wParam, lParam));
+ }
+ default:
+ break;
+ }
+ return(FALSE);
+}
+
+/**
+ * dialog procedure for the info panel config popup
+ */
+INT_PTR CALLBACK CInfoPanel::ConfigDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG: {
+ TCHAR tszTitle[100];
+
+ mir_sntprintf(tszTitle, 100, CTranslator::getOpt(CTranslator::OPT_IPANEL_VISBILITY_TITLE),
+ m_isChat ? CTranslator::getOpt(CTranslator::OPT_IPANEL_VISIBILTY_CHAT) : CTranslator::getOpt(CTranslator::OPT_IPANEL_VISIBILTY_IM));
+ ::SetDlgItemText(hwnd, IDC_STATIC_VISIBILTY, tszTitle);
+
+ mir_sntprintf(tszTitle, 100, m_isChat ? CTranslator::getOpt(CTranslator::OPT_IPANEL_SYNC_TITLE_IM) :
+ CTranslator::getOpt(CTranslator::OPT_IPANEL_SYNC_TITLE_MUC));
+
+ ::SetDlgItemText(hwnd, IDC_NOSYNC, tszTitle);
+
+ ::SendDlgItemMessage(hwnd, IDC_PANELVISIBILITY, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_IPANEL_VIS_INHERIT));
+ ::SendDlgItemMessage(hwnd, IDC_PANELVISIBILITY, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_IPANEL_VIS_OFF));
+ ::SendDlgItemMessage(hwnd, IDC_PANELVISIBILITY, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_IPANEL_VIS_ON));
+
+ BYTE v = M->GetByte(m_dat->hContact, "infopanel", 0);
+ ::SendDlgItemMessage(hwnd, IDC_PANELVISIBILITY, CB_SETCURSEL, (WPARAM)(v == 0 ? 0 : (v == (BYTE)-1 ? 1 : 2)), 0);
+
+ ::SendDlgItemMessage(hwnd, IDC_PANELSIZE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_IPANEL_SIZE_GLOBAL));
+ ::SendDlgItemMessage(hwnd, IDC_PANELSIZE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_IPANEL_SIZE_PRIVATE));
+
+ ::SendDlgItemMessage(hwnd, IDC_PANELSIZE, CB_SETCURSEL, (WPARAM)(m_fPrivateHeight ? 1 : 0), 0);
+
+ ::CheckDlgButton(hwnd, IDC_NOSYNC, M->GetByte("syncAllPanels", 0) ? BST_UNCHECKED : BST_CHECKED);
+
+ Utils::showDlgControl(hwnd, IDC_IPCONFIG_PRIVATECONTAINER, m_dat->pContainer->settings->fPrivate ? SW_SHOW : SW_HIDE);
+
+ if(!m_isChat) {
+ v = M->GetByte(m_dat->hContact, SRMSGMOD_T, "hideavatar", -1);
+ ::SendDlgItemMessage(hwnd, IDC_PANELPICTUREVIS, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_IPGLOBAL));
+ ::SendDlgItemMessage(hwnd, IDC_PANELPICTUREVIS, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_AVON));
+ ::SendDlgItemMessage(hwnd, IDC_PANELPICTUREVIS, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_AVOFF));
+ ::SendDlgItemMessage(hwnd, IDC_PANELPICTUREVIS, CB_SETCURSEL, (v == (BYTE)-1 ? 0 : (v == 1 ? 1 : 2)), 0);
+ }
+ else
+ Utils::enableDlgControl(hwnd, IDC_PANELPICTUREVIS, FALSE);
+
+ return(FALSE);
+ }
+
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ {
+ HWND hwndChild = (HWND)lParam;
+ UINT id = ::GetDlgCtrlID(hwndChild);
+
+ if(m_configDlgFont == 0) {
+ HFONT hFont = (HFONT)::SendDlgItemMessage(hwnd, IDC_IPCONFIG_TITLE, WM_GETFONT, 0, 0);
+ LOGFONT lf = {0};
+
+ ::GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ m_configDlgBoldFont = ::CreateFontIndirect(&lf);
+
+ lf.lfHeight = (int)(lf.lfHeight * 1.2);
+ m_configDlgFont = ::CreateFontIndirect(&lf);
+ ::SendDlgItemMessage(hwnd, IDC_IPCONFIG_TITLE, WM_SETFONT, (WPARAM)m_configDlgFont, FALSE);
+ }
+
+ if(hwndChild == ::GetDlgItem(hwnd, IDC_IPCONFIG_TITLE)) {
+ ::SetTextColor((HDC)wParam, RGB(60, 60, 150));
+ ::SendMessage(hwndChild, WM_SETFONT, (WPARAM)m_configDlgFont, FALSE);
+ } else if(id == IDC_IPCONFIG_FOOTER || id == IDC_SIZE_TIP || id == IDC_IPCONFIG_PRIVATECONTAINER)
+ ::SetTextColor((HDC)wParam, RGB(160, 50, 50));
+ else if(id == IDC_GROUP_SIZE || id == IDC_GROUP_SCOPE || id == IDC_GROUP_OTHER)
+ ::SendMessage(hwndChild, WM_SETFONT, (WPARAM)m_configDlgBoldFont, FALSE);
+
+ ::SetBkColor((HDC)wParam, ::GetSysColor(COLOR_WINDOW));
+ return reinterpret_cast<INT_PTR>(::GetSysColorBrush(COLOR_WINDOW));
+ }
+
+ case WM_COMMAND: {
+ LONG lOldHeight = m_height;
+
+ switch(LOWORD(wParam)) {
+ case IDC_PANELSIZE: {
+ LRESULT iResult = ::SendDlgItemMessage(hwnd, IDC_PANELSIZE, CB_GETCURSEL, 0, 0);
+
+ if(iResult == 0) {
+ if(m_fPrivateHeight) {
+ M->WriteDword(m_dat->hContact, SRMSGMOD_T, "panelheight", m_height);
+ loadHeight();
+ }
+ }
+ else if(iResult == 1) {
+ M->WriteDword(m_dat->hContact, SRMSGMOD_T, "panelheight",
+ MAKELONG(M->GetDword(m_dat->hContact, "panelheight", m_height), 0xffff));
+ loadHeight();
+ }
+ break;
+ }
+
+ case IDC_PANELPICTUREVIS: {
+ BYTE vOld = M->GetByte(m_dat->hContact, SRMSGMOD_T, "hideavatar", -1);
+ LRESULT iResult = ::SendDlgItemMessage(hwnd, IDC_PANELPICTUREVIS, CB_GETCURSEL, 0, 0);
+
+ BYTE vNew = (iResult == 0 ? (BYTE)-1 : (iResult == 1 ? 1 : 0));
+ if(vNew != vOld) {
+ if(vNew == (BYTE)-1)
+ DBDeleteContactSetting(m_dat->hContact, SRMSGMOD_T, "hideavatar");
+ else
+ M->WriteByte(m_dat->hContact, SRMSGMOD_T, "hideavatar", vNew);
+ m_dat->panelWidth = -1;
+ ::ShowPicture(m_dat, FALSE);
+ ::SendMessage(m_dat->hwnd, WM_SIZE, 0, 0);
+ ::DM_ScrollToBottom(m_dat, 0, 1);
+ }
+ break;
+ }
+
+ case IDC_PANELVISIBILITY: {
+ BYTE vOld = M->GetByte(m_dat->hContact, SRMSGMOD_T, "infopanel", 0);
+ LRESULT iResult = ::SendDlgItemMessage(hwnd, IDC_PANELVISIBILITY, CB_GETCURSEL, 0, 0);
+
+ BYTE vNew = (iResult == 0 ? 0 : (iResult == 1 ? (BYTE)-1 : 1));
+ if(vNew != vOld) {
+ M->WriteByte(m_dat->hContact, SRMSGMOD_T, "infopanel", vNew);
+ getVisibility();
+ showHide();
+ }
+ break;
+ }
+
+ case IDC_SIZECOMPACT:
+ setHeight(MIN_PANELHEIGHT + 2, true);
+ break;
+
+ case IDC_SIZENORMAL:
+ setHeight(DEGRADE_THRESHOLD, true);
+ break;
+
+ case IDC_SIZELARGE:
+ setHeight(51, true);
+ break;
+
+ case IDC_NOSYNC:
+ M->WriteByte(SRMSGMOD_T, "syncAllPanels", ::IsDlgButtonChecked(hwnd, IDC_NOSYNC) ? 0 : 1);
+ if(!IsDlgButtonChecked(hwnd, IDC_NOSYNC)) {
+ loadHeight();
+ if(!m_dat->pContainer->settings->fPrivate)
+ M->BroadcastMessage(DM_SETINFOPANEL, (WPARAM)m_dat, (LPARAM)m_defaultHeight);
+ else
+ ::BroadCastContainer(m_dat->pContainer, DM_SETINFOPANEL, (WPARAM)m_dat, (LPARAM)m_defaultHeight);
+ } else {
+ if(!m_dat->pContainer->settings->fPrivate)
+ M->BroadcastMessage(DM_SETINFOPANEL, (WPARAM)m_dat, 0);
+ else
+ ::BroadCastContainer(m_dat->pContainer,DM_SETINFOPANEL, (WPARAM)m_dat, 0);
+ }
+ break;
+ }
+ if(m_height != lOldHeight) {
+ ::SendMessage(m_dat->hwnd, WM_SIZE, 0, 0);
+ m_dat->panelWidth = -1;
+ ::SetAeroMargins(m_dat->pContainer);
+ ::RedrawWindow(m_dat->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+ ::RedrawWindow(GetParent(m_dat->hwnd), NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+ }
+ break;
+ }
+
+ case WM_CLOSE:
+ if(wParam == 1 && lParam == 1) {
+ ::DestroyWindow(hwnd);
+ }
+ break;
+
+ case WM_DESTROY: {
+ ::DeleteObject(m_configDlgBoldFont);
+ ::DeleteObject(m_configDlgFont);
+
+ m_configDlgBoldFont = m_configDlgFont = 0;
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, 0L);
+ break;
+ }
+ }
+ return(FALSE);
+}
+
+/**
+ * invoke info panel config popup dialog
+ * @param pt : mouse coordinates (screen)
+ * @return : always 0
+ */
+int CInfoPanel::invokeConfigDialog(const POINT& pt)
+{
+ RECT rc;
+ POINT ptTest = pt;
+
+ if(!m_active)
+ return(0);
+
+ ::GetWindowRect(m_dat->hwnd, &rc);
+ rc.bottom = rc.top + m_height;
+ rc.right -= m_dat->panelWidth;
+
+ if(!::PtInRect(&rc, ptTest))
+ return(0);
+
+ if(m_hwndConfig == 0) {
+ m_configDlgBoldFont = m_configDlgFont = 0;
+ m_hwndConfig = ::CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_INFOPANEL), 0 /*m_dat->pContainer->hwnd */,
+ ConfigDlgProcStub, (LPARAM)this);
+ if(m_hwndConfig) {
+ RECT rc, rcLog;
+ POINT pt;
+
+ TranslateDialogDefault(m_hwndConfig);
+
+ ::GetClientRect(m_hwndConfig, &rc);
+ ::GetWindowRect(GetDlgItem(m_dat->hwnd, m_isChat ? IDC_CHAT_LOG : IDC_LOG), &rcLog);
+ pt.x = rcLog.left;
+ pt.y = rcLog.top;
+ //::ScreenToClient(m_dat->pContainer->hwnd, &pt);
+
+ m_fDialogCreated = true;
+ ::SetWindowPos(m_hwndConfig, HWND_TOP, pt.x + 10, pt.y - (m_active ? 10 : 0), 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
+ return(1);
+ }
+ }
+ return(0);
+}
+
+/**
+ * remove the info panel configuration dialog
+ * @param fForced: bool, if true, dismiss it under any circumstances, even
+ * with the pointer still inside the dialog.
+ */
+void CInfoPanel::dismissConfig(bool fForced)
+{
+ if(m_hwndConfig == 0)
+ return;
+
+ POINT pt;
+ RECT rc;
+
+ if(!m_fDialogCreated) {
+ ::GetCursorPos(&pt);
+ ::GetWindowRect(m_hwndConfig, &rc);
+ if(fForced || !PtInRect(&rc, pt)) {
+ SendMessage(m_hwndConfig, WM_CLOSE, 1, 1);
+ m_hwndConfig = 0;
+ }
+ }
+ m_fDialogCreated = false;
+}
+
+/**
+ * construct a richedit tooltip object.
+ *
+ * @param hwndParent HWND owner (used only for position calculation)
+ * @param hContact HANDLE contact handle
+ * @param pszText TCHAR* the content of the rich edit control
+ * @param panel CInfoPanel* the panel which owns it
+ */
+CTip::CTip(const HWND hwndParent, const HANDLE hContact, const TCHAR *pszText, const CInfoPanel* panel)
+{
+ m_hwnd = ::CreateWindowEx(WS_EX_TOOLWINDOW, _T("RichEditTipClass"), _T(""), (M->isAero() ? WS_THICKFRAME : WS_BORDER)|WS_POPUPWINDOW|WS_TABSTOP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ 0, 0, 40, 40, 0, 0, g_hInst, this);
+
+ m_hRich = ::CreateWindowEx(0, RICHEDIT_CLASS, _T(""), WS_CHILD | ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL | ES_READONLY | WS_VSCROLL | WS_TABSTOP,
+ 0, 0, 40, 40, m_hwnd, reinterpret_cast<HMENU>(1000), g_hInst, NULL);
+
+ ::SendMessage(m_hRich, EM_AUTOURLDETECT, (WPARAM) TRUE, 0);
+ ::SendMessage(m_hRich, EM_SETEVENTMASK, 0, ENM_LINK);
+ ::SendMessage(m_hRich, WM_SETFONT, (WPARAM)CInfoPanel::m_ipConfig.hFonts[IPFONTID_STATUS], 0);
+
+ m_hContact = hContact;
+ if(pszText)
+ m_pszText = M->utf8_encodeT(pszText);
+ else
+ m_pszText = 0;
+ m_panel = panel;
+ m_hwndParent = hwndParent;
+ m_OldMessageEditProc = (WNDPROC)SetWindowLongPtr(m_hRich, GWLP_WNDPROC, (LONG_PTR)RichEditProc);
+}
+
+/**
+ * Show the tooltip at the given position (the position can be adjusted to keep it on screen and
+ * inside its parent window.
+ *
+ * it will auto-adjust the size (height only) of the richedit control to fit the m_pszText
+ *
+ * @param rc dimensions of the tip (left and top should be 0)
+ * @param pt point in screen coordinates
+ * @param hIcon optional icon to display in the tip header
+ * @param szTitle optional title to display in the tip header
+ */
+void CTip::show(const RECT& rc, POINT& pt, const HICON hIcon, const TCHAR *szTitle)
+{
+ HDC hdc = ::GetDC(m_hwnd);
+ FORMATRANGE fr = {0};
+ RECT rcPage = {0, 0, 0, 0};
+ RECT rcParent;
+ SETTEXTEX stx = {ST_SELECTION, CP_UTF8};
+ int twips = (int)(15.0f / PluginConfig.g_DPIscaleY);
+
+ int xBorder, yBorder;
+ m_leftWidth = (m_panel->getDat()->hClientIcon || m_panel->getDat()->hXStatusIcon ? LEFT_BAR_WIDTH : 0);
+
+ xBorder = M->isAero() ? GetSystemMetrics(SM_CXSIZEFRAME) : 1;
+ yBorder = M->isAero() ? GetSystemMetrics(SM_CYSIZEFRAME) : 1;
+
+ m_hIcon = hIcon;
+ m_szTitle = szTitle;
+
+ ::SendMessage(m_hRich, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(4, 4));
+ ::SendMessage(m_hRich, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)m_pszText);
+
+ if (PluginConfig.g_SmileyAddAvail) {
+ SMADD_RICHEDIT3 smadd;
+ CContactCache* c = CContactCache::getContactCache(m_hContact);
+ ::SendMessage(m_hRich, EM_SETBKGNDCOLOR, 0, (LPARAM)PluginConfig.m_ipBackgroundGradientHigh);
+ if(c) {
+ ZeroMemory(&smadd, sizeof(smadd));
+
+ smadd.cbSize = sizeof(smadd);
+ smadd.hwndRichEditControl = m_hRich;
+ smadd.Protocolname = const_cast<char *>(c->getActiveProto());
+ smadd.hContact = c->getActiveContact();
+ smadd.flags = 0;
+ smadd.rangeToReplace = NULL;
+ smadd.disableRedraw = TRUE;
+ CallService(MS_SMILEYADD_REPLACESMILEYS, TABSRMM_SMILEYADD_BKGCOLORMODE, (LPARAM)&smadd);
+ }
+ }
+
+ ::GetWindowRect(m_hwndParent, &rcParent);
+ if(pt.x + rc.right > rcParent.right)
+ pt.x = rcParent.right - rc.right - 5;
+
+ m_rcRich = rc;
+
+ m_rcRich.bottom = 800;
+ m_rcRich.left = LEFT_BORDER + m_leftWidth; m_rcRich.top = TOP_BORDER;
+ m_rcRich.right -= (LEFT_BORDER + RIGHT_BORDER + m_leftWidth);
+
+ m_rcRich.right = m_rcRich.left + (twips * (m_rcRich.right - m_rcRich.left)) - 10 * twips;
+ m_rcRich.bottom = m_rcRich.top + (twips * (m_rcRich.bottom - m_rcRich.top));
+
+ fr.hdc = hdc;
+ fr.hdcTarget = hdc;
+ fr.rc = m_rcRich;
+ fr.rcPage = rcPage;
+ fr.chrg.cpMax = -1;
+ fr.chrg.cpMin = 0;
+ LRESULT lr = ::SendMessage(m_hRich, EM_FORMATRANGE, 0, (LPARAM)&fr);
+ m_szRich.cx = ((fr.rc.right - fr.rc.left) / twips) + 8;
+ m_szRich.cy = ((fr.rc.bottom - fr.rc.top) / twips) + 3;
+
+ m_rcRich.right = m_rcRich.left + m_szRich.cx;
+ m_rcRich.bottom = m_rcRich.top + m_szRich.cy;
+
+ ::SendMessage(m_hRich, EM_FORMATRANGE, 0, (LPARAM)NULL); // required, clear cached painting data in the richedit
+
+ ::SetWindowPos(m_hwnd, HWND_TOP, pt.x - 5, pt.y - 5, m_szRich.cx + m_leftWidth + LEFT_BORDER + RIGHT_BORDER + 2 * xBorder,
+ m_szRich.cy + TOP_BORDER + BOTTOM_BORDER + 2 * yBorder, SWP_NOACTIVATE|SWP_SHOWWINDOW);
+
+ ::SetWindowPos(m_hRich, 0, LEFT_BORDER + m_leftWidth, TOP_BORDER, m_szRich.cx, m_szRich.cy, SWP_SHOWWINDOW);
+
+ ::ReleaseDC(m_hwnd, hdc);
+}
+
+/**
+ * register richedit tooltip window class
+ */
+void CTip::registerClass()
+{
+ WNDCLASSEX wc;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = _T("RichEditTipClass");
+ wc.lpfnWndProc = (WNDPROC)CTip::WndProcStub;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(CTip *);
+ wc.hbrBackground = 0;
+ wc.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_PARENTDC;
+ RegisterClassEx(&wc);
+}
+
+/**
+ * subclass the rich edit control inside the tip. Needed to hide the blinking
+ * caret and prevent all scrolling actions.
+ */
+INT_PTR CALLBACK CTip::RichEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_SETCURSOR:
+ ::HideCaret(hwnd);
+ break;
+
+ case WM_ERASEBKGND:
+ return(1);
+
+ case WM_NCCALCSIZE:
+ SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_VSCROLL);
+ EnableScrollBar(hwnd, SB_VERT, ESB_DISABLE_BOTH);
+ ShowScrollBar(hwnd, SB_VERT, FALSE);
+ break;
+
+ case WM_VSCROLL:
+ return(0);
+ }
+ return(::CallWindowProc(m_OldMessageEditProc, hwnd, msg, wParam, lParam));
+}
+
+/**
+ * stub for the tip control window procedure. Just handle WM_CREATE and set the
+ * this pointer.
+ */
+INT_PTR CALLBACK CTip::WndProcStub(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CTip *tip = reinterpret_cast<CTip *>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
+
+ if(tip)
+ return(tip->WndProc(hwnd, msg, wParam, lParam));
+
+ switch(msg) {
+ case WM_CREATE: {
+ CREATESTRUCT *cs = reinterpret_cast<CREATESTRUCT *>(lParam);
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
+ }
+ default:
+ break;
+ }
+ return(::DefWindowProc(hwnd, msg, wParam, lParam));
+}
+
+/**
+ * the window procedure for the tooltip window.
+ */
+INT_PTR CALLBACK CTip::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_ACTIVATE:
+ case WM_SETCURSOR:
+ ::KillTimer(hwnd, 1000);
+ ::SetTimer(hwnd, 1000, 200, 0);
+
+ if(msg == WM_ACTIVATE && LOWORD(wParam) == WA_INACTIVE)
+ ::DestroyWindow(hwnd);
+ break;
+
+ /* prevent resizing */
+ case WM_NCHITTEST:
+ return(HTCLIENT);
+ break;
+
+ case WM_ERASEBKGND: {
+ HDC hdc = (HDC) wParam;
+ RECT rc;
+ TCHAR szTitle[128];
+ COLORREF clr = CInfoPanel::m_ipConfig.clrs[IPFONTID_NICK];
+ GetClientRect(hwnd, &rc);
+ CContactCache* c = CContactCache::getContactCache(m_hContact);
+ RECT rcText = {0, 0, rc.right, TOP_BORDER};
+ LONG cx = rc.right;
+ LONG cy = rc.bottom;
+ HANDLE hTheme = 0;
+
+ mir_sntprintf(szTitle, 128, m_szTitle ? _T("%s (%s)") : _T("%s%s"), c->getNick(), m_szTitle ? m_szTitle : _T(""));
+
+ if(m_panel) {
+ HDC hdcMem = ::CreateCompatibleDC(hdc);
+ HBITMAP hbm = ::CSkin::CreateAeroCompatibleBitmap(rc, hdc);
+ HBITMAP hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(hdcMem, hbm));
+ HFONT hOldFont = reinterpret_cast<HFONT>(::SelectObject(hdcMem, CInfoPanel::m_ipConfig.hFonts[IPFONTID_NICK]));
+
+
+ ::SetBkMode(hdcMem, TRANSPARENT);
+ rc.bottom += 2;
+ rc.left -= 4;rc.right += 4;
+ HBRUSH br = ::CreateSolidBrush(PluginConfig.m_ipBackgroundGradientHigh);
+ if(M->isAero()) {
+ ::FillRect(hdcMem, &rc, reinterpret_cast<HBRUSH>(::GetStockObject(BLACK_BRUSH)));
+ CSkin::ApplyAeroEffect(hdcMem, &rcText, CSkin::AERO_EFFECT_AREA_MENUBAR, 0);
+ ::FillRect(hdcMem, &m_rcRich, br);
+
+ hTheme = CMimAPI::m_pfnOpenThemeData(m_hwnd, L"BUTTON");
+ MARGINS m;
+ m.cxLeftWidth = LEFT_BORDER + m_leftWidth;
+ m.cxRightWidth = RIGHT_BORDER;
+ m.cyBottomHeight = BOTTOM_BORDER;
+ m.cyTopHeight = TOP_BORDER;
+ CMimAPI::m_pfnDwmExtendFrameIntoClientArea(m_hwnd, &m);
+ }
+ else {
+ ::FillRect(hdcMem, &rc, br);
+ ::DrawAlpha(hdcMem, &rcText, PluginConfig.m_ipBackgroundGradientHigh, 100, PluginConfig.m_ipBackgroundGradient,
+ 0, GRADIENT_TB + 1, 0, 2, 0);
+ }
+ ::DeleteObject(br);
+ rcText.left = 20;
+
+ LONG dy = 4;
+
+ if(m_hIcon) {
+ ::DrawIconEx(hdcMem, 2, dy, m_hIcon, 16, 16, 0, 0, DI_NORMAL);
+ dy = TOP_BORDER + 4;
+ }
+ if(m_panel->getDat()->hXStatusIcon) {
+ ::DrawIconEx(hdcMem, 2, dy, m_panel->getDat()->hXStatusIcon, 16, 16, 0, 0, DI_NORMAL);
+ dy += 18;
+ }
+ if(m_panel->getDat()->hClientIcon)
+ ::DrawIconEx(hdcMem, 2, dy, m_panel->getDat()->hClientIcon, 16, 16, 0, 0, DI_NORMAL);
+
+ CSkin::RenderText(hdcMem, hTheme, szTitle, &rcText, DT_SINGLELINE|DT_END_ELLIPSIS|DT_VCENTER, CSkin::m_glowSize, clr);
+ if(hTheme)
+ CMimAPI::m_pfnCloseThemeData(hTheme);
+ ::SelectObject(hdcMem, hOldFont);
+ ::BitBlt(hdc, 0, 0, cx, cy, hdcMem, 0, 0, SRCCOPY);
+ ::SelectObject(hdcMem, hbmOld);
+ ::DeleteObject(hbm);
+ ::DeleteDC(hdcMem);
+ }
+ return(1);
+ }
+
+ case WM_NOTIFY: {
+ switch (((NMHDR *) lParam)->code) {
+ case EN_LINK:
+ ::SetFocus(m_hRich);
+ switch (((ENLINK *) lParam)->msg) {
+ case WM_LBUTTONUP: {
+ ENLINK* e = reinterpret_cast<ENLINK *>(lParam);
+
+ const TCHAR* tszUrl = Utils::extractURLFromRichEdit(e, m_hRich);
+ if(tszUrl) {
+ char* szUrl = mir_t2a(tszUrl);
+
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM)szUrl);
+ mir_free(szUrl);
+ mir_free(const_cast<TCHAR *>(tszUrl));
+ }
+ ::DestroyWindow(hwnd);
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case WM_COMMAND: {
+ if((HWND)lParam == m_hRich && HIWORD(wParam) == EN_SETFOCUS)
+ ::HideCaret(m_hRich);
+ break;
+ }
+
+ case WM_TIMER:
+ if(wParam == 1000) {
+ POINT pt;
+ RECT rc;
+
+ ::KillTimer(hwnd, 1000);
+ ::GetCursorPos(&pt);
+ ::GetWindowRect(hwnd, &rc);
+ if(!PtInRect(&rc, pt))
+ ::DestroyWindow(hwnd);
+ else
+ break;
+ if(::GetActiveWindow() != hwnd)
+ ::DestroyWindow(hwnd);
+ }
+ break;
+
+ case WM_DESTROY:
+ ::SetWindowLongPtr(m_hRich, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(m_OldMessageEditProc));
+ break;
+
+ case WM_NCDESTROY: {
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ delete this;
+ }
+ }
+ return(::DefWindowProc(hwnd, msg, wParam, lParam));
+}
diff --git a/plugins/TabSRMM/src/mim.cpp b/plugins/TabSRMM/src/mim.cpp
new file mode 100644
index 0000000000..4dc9128a92
--- /dev/null
+++ b/plugins/TabSRMM/src/mim.cpp
@@ -0,0 +1,935 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: mim.cpp 12842 2010-09-28 04:32:57Z borkra $
+ *
+ * wraps some parts of Miranda API
+ * Also, OS dependent stuff (visual styles api etc.)
+ *
+ */
+
+
+#include "commonheaders.h"
+extern PLUGININFOEX pluginInfo;
+
+PITA CMimAPI::m_pfnIsThemeActive = 0;
+POTD CMimAPI::m_pfnOpenThemeData = 0;
+PDTB CMimAPI::m_pfnDrawThemeBackground = 0;
+PCTD CMimAPI::m_pfnCloseThemeData = 0;
+PDTT CMimAPI::m_pfnDrawThemeText = 0;
+PDTTE CMimAPI::m_pfnDrawThemeTextEx = 0;
+PITBPT CMimAPI::m_pfnIsThemeBackgroundPartiallyTransparent = 0;
+PDTPB CMimAPI::m_pfnDrawThemeParentBackground = 0;
+PGTBCR CMimAPI::m_pfnGetThemeBackgroundContentRect = 0;
+ETDT CMimAPI::m_pfnEnableThemeDialogTexture = 0;
+PSLWA CMimAPI::m_pSetLayeredWindowAttributes = 0;
+PFWEX CMimAPI::m_MyFlashWindowEx = 0;
+PAB CMimAPI::m_MyAlphaBlend = 0;
+PGF CMimAPI::m_MyGradientFill = 0;
+DEFICA CMimAPI::m_pfnDwmExtendFrameIntoClientArea = 0;
+DICE CMimAPI::m_pfnDwmIsCompositionEnabled = 0;
+MMFW CMimAPI::m_pfnMonitorFromWindow = 0;
+GMIA CMimAPI::m_pfnGetMonitorInfoA = 0;
+DRT CMimAPI::m_pfnDwmRegisterThumbnail = 0;
+BPI CMimAPI::m_pfnBufferedPaintInit = 0;
+BPU CMimAPI::m_pfnBufferedPaintUninit = 0;
+BBP CMimAPI::m_pfnBeginBufferedPaint = 0;
+EBP CMimAPI::m_pfnEndBufferedPaint = 0;
+BBW CMimAPI::m_pfnDwmBlurBehindWindow = 0;
+DGC CMimAPI::m_pfnDwmGetColorizationColor = 0;
+BPSA CMimAPI::m_pfnBufferedPaintSetAlpha = 0;
+GLIX CMimAPI::m_pfnGetLocaleInfoEx = 0;
+DWMIIB CMimAPI::m_pfnDwmInvalidateIconicBitmaps = 0;
+DWMSWA CMimAPI::m_pfnDwmSetWindowAttribute = 0;
+DWMUT CMimAPI::m_pfnDwmUpdateThumbnailProperties = 0;
+DURT CMimAPI::m_pfnDwmUnregisterThumbnail = 0;
+DSIT CMimAPI::m_pfnDwmSetIconicThumbnail = 0;
+DSILP CMimAPI::m_pfnDwmSetIconicLivePreviewBitmap = 0;
+bool CMimAPI::m_shutDown = 0;
+TCHAR CMimAPI::m_userDir[] = _T("\0");
+
+bool CMimAPI::m_haveBufferedPaint = false;
+DWORD CMimAPI::m_MimVersion = 0;
+
+void CMimAPI::timerMsg(const char *szMsg)
+{
+ mir_snprintf(m_timerMsg, 256, "%s: %d ticks = %f msec", szMsg, (int)(m_tStop - m_tStart), 1000 * ((double)(m_tStop - m_tStart) * m_dFreq));
+ _DebugTraceA(m_timerMsg);
+}
+/*
+ * read a setting for a contact
+ */
+
+DWORD CMimAPI::GetDword(const HANDLE hContact = 0, const char *szModule = 0, const char *szSetting = 0, DWORD uDefault = 0) const
+{
+ return((DWORD)DBGetContactSettingDword(hContact, szModule, szSetting, uDefault));
+}
+
+/*
+ * read a setting from our default module (Tab_SRMSG)
+ */
+
+DWORD CMimAPI::GetDword(const char *szSetting = 0, DWORD uDefault = 0) const
+{
+ return((DWORD)DBGetContactSettingDword(0, SRMSGMOD_T, szSetting, uDefault));
+}
+
+/*
+ * read a contact setting with our default module name (Tab_SRMSG)
+ */
+
+DWORD CMimAPI::GetDword(const HANDLE hContact = 0, const char *szSetting = 0, DWORD uDefault = 0) const
+{
+ return((DWORD)DBGetContactSettingDword(hContact, SRMSGMOD_T, szSetting, uDefault));
+}
+
+/*
+ * read a setting from module only
+ */
+
+DWORD CMimAPI::GetDword(const char *szModule, const char *szSetting, DWORD uDefault) const
+{
+ return((DWORD)DBGetContactSettingDword(0, szModule, szSetting, uDefault));
+}
+
+/*
+ * same for bytes now
+ */
+int CMimAPI::GetByte(const HANDLE hContact = 0, const char *szModule = 0, const char *szSetting = 0, int uDefault = 0) const
+{
+ return(DBGetContactSettingByte(hContact, szModule, szSetting, uDefault));
+}
+
+int CMimAPI::GetByte(const char *szSetting = 0, int uDefault = 0) const
+{
+ return(DBGetContactSettingByte(0, SRMSGMOD_T, szSetting, uDefault));
+}
+
+int CMimAPI::GetByte(const HANDLE hContact = 0, const char *szSetting = 0, int uDefault = 0) const
+{
+ return(DBGetContactSettingByte(hContact, SRMSGMOD_T, szSetting, uDefault));
+}
+
+int CMimAPI::GetByte(const char *szModule, const char *szSetting, int uDefault) const
+{
+ return(DBGetContactSettingByte(0, szModule, szSetting, uDefault));
+}
+
+INT_PTR CMimAPI::GetTString(const HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) const
+{
+ return(DBGetContactSettingTString(hContact, szModule, szSetting, dbv));
+}
+
+INT_PTR CMimAPI::GetString(const HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) const
+{
+ return(DBGetContactSettingString(hContact, szModule, szSetting, dbv));
+}
+
+/*
+ * writer functions
+ */
+
+INT_PTR CMimAPI::WriteDword(const HANDLE hContact = 0, const char *szModule = 0, const char *szSetting = 0, DWORD value = 0) const
+{
+ return(DBWriteContactSettingDword(hContact, szModule, szSetting, value));
+}
+
+/*
+ * write non-contact setting
+*/
+
+INT_PTR CMimAPI::WriteDword(const char *szModule = 0, const char *szSetting = 0, DWORD value = 0) const
+{
+ return(DBWriteContactSettingDword(0, szModule, szSetting, value));
+}
+
+INT_PTR CMimAPI::WriteByte(const HANDLE hContact = 0, const char *szModule = 0, const char *szSetting = 0, BYTE value = 0) const
+{
+ return(DBWriteContactSettingByte(hContact, szModule, szSetting, value));
+}
+
+INT_PTR CMimAPI::WriteByte(const char *szModule = 0, const char *szSetting = 0, BYTE value = 0) const
+{
+ return(DBWriteContactSettingByte(0, szModule, szSetting, value));
+}
+
+INT_PTR CMimAPI::WriteTString(const HANDLE hContact, const char *szModule = 0, const char *szSetting = 0, const TCHAR *str = 0) const
+{
+ return(DBWriteContactSettingTString(hContact, szModule, szSetting, str));
+}
+
+void CMimAPI::GetUTFI()
+{
+ mir_getUTFI(&m_utfi);
+}
+char *CMimAPI::utf8_decode(char* str, wchar_t** ucs2) const
+{
+ return(m_utfi.utf8_decode(str, ucs2));
+}
+char *CMimAPI::utf8_decodecp(char* str, int codepage, wchar_t** ucs2 ) const
+{
+ return(m_utfi.utf8_decodecp(str, codepage, ucs2));
+}
+char *CMimAPI::utf8_encode(const char* src) const
+{
+ return(m_utfi.utf8_encode(src));
+}
+
+char *CMimAPI::utf8_encodecp(const char* src, int codepage) const
+{
+ return(m_utfi.utf8_encodecp(src, codepage));
+}
+
+char *CMimAPI::utf8_encodeW(const wchar_t* src) const
+{
+ return(m_utfi.utf8_encodeW(src));
+}
+
+char *CMimAPI::utf8_encodeT(const TCHAR* src) const
+{
+ return(m_utfi.utf8_encodeW(src));
+}
+
+TCHAR *CMimAPI::utf8_decodeT(const char* src) const
+{
+ return(m_utfi.utf8_decodeW(src));
+}
+
+wchar_t *CMimAPI::utf8_decodeW(const char* str) const
+{
+ return(m_utfi.utf8_decodeW(str));
+}
+
+/**
+ * Case insensitive _tcsstr
+ *
+ * @param szString TCHAR *: String to be searched
+ * @param szSearchFor
+ * TCHAR *: String that should be found in szString
+ *
+ * @return TCHAR *: found position of szSearchFor in szString. 0 if szSearchFor was not found
+ */
+const TCHAR* CMimAPI::StriStr(const TCHAR *szString, const TCHAR *szSearchFor)
+{
+ assert(szString != 0 && szSearchFor != 0);
+
+ if(szString && *szString) {
+ if (0 == szSearchFor || 0 == *szSearchFor)
+ return(szString);
+
+ for(; *szString; ++szString) {
+ if(_totupper(*szString) == _totupper(*szSearchFor)) {
+ const TCHAR *h, *n;
+ for(h = szString, n = szSearchFor; *h && *n; ++h, ++n) {
+ if(_totupper(*h) != _totupper(*n))
+ break;
+ }
+ if(!*n)
+ return(szString);
+ }
+ }
+ return(0);
+ }
+ else
+ return(0);
+}
+
+int CMimAPI::pathIsAbsolute(const TCHAR *path) const
+{
+ if (!path || !(lstrlen(path) > 2))
+ return 0;
+ if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\'))
+ return 1;
+ return 0;
+}
+
+size_t CMimAPI::pathToRelative(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const
+{
+ const TCHAR *tszBase = szBase ? szBase : m_szProfilePath;
+
+ pOut[0] = 0;
+ if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH)
+ return 0;
+ if (!pathIsAbsolute(pSrc)) {
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ return lstrlen(pOut);
+ } else {
+ TCHAR szTmp[MAX_PATH];
+
+ mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc);
+ if (StriStr(szTmp, tszBase)) {
+ if(tszBase[lstrlen(tszBase) - 1] == '\\')
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase));
+ else {
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase) + 1 );
+ //pOut[0]='.';
+ }
+ return(lstrlen(pOut));
+ } else {
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ return(lstrlen(pOut));
+ }
+ }
+}
+
+/**
+ * Translate a relativ path to an absolute, using the current profile
+ * data directory.
+ *
+ * @param pSrc TCHAR *: input path + filename (relative)
+ * @param pOut TCHAR *: the result
+ * @param szBase TCHAR *: (OPTIONAL) base path for the translation. Can be 0 in which case
+ * the function will use m_szProfilePath (usually \tabSRMM below %miranda_userdata%
+ *
+ * @return
+ */
+size_t CMimAPI::pathToAbsolute(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const
+{
+ const TCHAR *tszBase = szBase ? szBase : m_szProfilePath;
+
+ pOut[0] = 0;
+ if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH)
+ return 0;
+ if (pathIsAbsolute(pSrc) && pSrc[0]!='.')
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ else if (pSrc[0]=='.')
+ mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc + 1);
+ else
+ mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc);
+
+ return lstrlen(pOut);
+}
+
+/*
+ * window list functions
+ */
+
+void CMimAPI::BroadcastMessage(UINT msg = 0, WPARAM wParam = 0, LPARAM lParam = 0)
+{
+ WindowList_Broadcast(m_hMessageWindowList, msg, wParam, lParam);
+}
+
+void CMimAPI::BroadcastMessageAsync(UINT msg = 0, WPARAM wParam = 0, LPARAM lParam = 0)
+{
+ WindowList_BroadcastAsync(m_hMessageWindowList, msg, wParam, lParam);
+}
+
+HWND CMimAPI::FindWindow(HANDLE h = 0) const
+{
+ return(WindowList_Find(m_hMessageWindowList, h));
+}
+
+INT_PTR CMimAPI::AddWindow(HWND hWnd = 0, HANDLE h = 0)
+{
+ return(WindowList_Add(m_hMessageWindowList, hWnd, h));
+}
+
+INT_PTR CMimAPI::RemoveWindow(HWND hWnd = 0)
+{
+ return(WindowList_Remove(m_hMessageWindowList, hWnd));
+}
+
+int CMimAPI::FoldersPathChanged(WPARAM wParam, LPARAM lParam)
+{
+ return(M->foldersPathChanged());
+}
+
+void CMimAPI::configureCustomFolders()
+{
+ m_haveFolders = false;
+ if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) {
+ m_hDataPath = (HANDLE)FoldersRegisterCustomPathT("TabSRMM", "Data path", const_cast<TCHAR *>(getDataPath()));
+ m_hSkinsPath = (HANDLE)FoldersRegisterCustomPathT("TabSRMM", "Skins root", const_cast<TCHAR *>(getSkinPath()));
+ m_hAvatarsPath = (HANDLE)FoldersRegisterCustomPathT("TabSRMM", "Saved Avatars", const_cast<TCHAR *>(getSavedAvatarPath()));
+ m_hChatLogsPath = (HANDLE)FoldersRegisterCustomPathT("TabSRMM", "Group chat logs root", const_cast<TCHAR *>(getChatLogPath()));
+ CGlobals::m_event_FoldersChanged = HookEvent(ME_FOLDERS_PATH_CHANGED, CMimAPI::FoldersPathChanged);
+ m_haveFolders = true;
+ }
+ else
+ m_hDataPath = m_hSkinsPath = m_hAvatarsPath = m_hChatLogsPath = 0;
+
+ foldersPathChanged();
+}
+
+INT_PTR CMimAPI::foldersPathChanged()
+{
+ TCHAR szTemp[MAX_PATH + 2] = {'\0'};
+
+ if(m_hDataPath) {
+ FoldersGetCustomPathT(m_hDataPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getDataPath()));
+ mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%s"), szTemp);
+
+ FoldersGetCustomPathT(m_hSkinsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getSkinPath()));
+ mir_sntprintf(m_szSkinsPath, MAX_PATH - 1, _T("%s"), szTemp);
+
+ /*
+ * make sure skins root path always ends with a '\' - this is assumed by the skin
+ * selection code.
+ */
+
+ Utils::ensureTralingBackslash(m_szSkinsPath);
+
+ FoldersGetCustomPathT(m_hAvatarsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getSavedAvatarPath()));
+ mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s"), szTemp);
+
+ FoldersGetCustomPathT(m_hChatLogsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getChatLogPath()));
+ mir_sntprintf(m_szChatLogsPath, MAX_PATH, _T("%s"), szTemp);
+
+ Utils::ensureTralingBackslash(m_szChatLogsPath);
+ }
+ CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)m_szProfilePath);
+ CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)m_szSkinsPath);
+ CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)m_szSavedAvatarsPath);
+ CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)m_szChatLogsPath);
+
+#if defined(_FOLDER_LOCKING)
+ mir_sntprintf(szTemp, MAX_PATH, L"%sfolder.lck", m_szChatLogsPath);
+
+ if(m_hChatLogLock != INVALID_HANDLE_VALUE)
+ CloseHandle(m_hChatLogLock);
+
+ m_hChatLogLock = CreateFile(szTemp, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN, 0);
+#endif
+
+ Skin->extractSkinsAndLogo(true);
+ Skin->setupAeroSkins();
+ return 0;
+}
+
+const TCHAR* CMimAPI::getUserDir()
+{
+ if(m_userDir[0] == 0) {
+ wchar_t* userdata = ::Utils_ReplaceVarsT(L"%miranda_userdata%");
+ mir_sntprintf(m_userDir, MAX_PATH, userdata);
+ Utils::ensureTralingBackslash(m_userDir);
+ mir_free(userdata);
+ }
+ return(m_userDir);
+}
+
+void CMimAPI::InitPaths()
+{
+ m_szProfilePath[0] = 0;
+ m_szSkinsPath[0] = 0;
+ m_szSavedAvatarsPath[0] = 0;
+
+ const TCHAR *szUserdataDir = getUserDir();
+
+ mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%stabSRMM"), szUserdataDir);
+ mir_sntprintf(m_szChatLogsPath, MAX_PATH, _T("%sLogs\\"), szUserdataDir);
+
+ mir_sntprintf(m_szSkinsPath, MAX_PATH, _T("%s\\skins\\"), m_szProfilePath);
+ mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s\\Saved Contact Pictures"), m_szProfilePath);
+}
+
+bool CMimAPI::getAeroState()
+{
+ BOOL result = FALSE;
+ m_isAero = m_DwmActive = false;
+ if(IsWinVerVistaPlus()) {
+ m_DwmActive = (m_pfnDwmIsCompositionEnabled && (m_pfnDwmIsCompositionEnabled(&result) == S_OK) && result) ? true : false;
+ m_isAero = (CSkin::m_skinEnabled == false) && GetByte("useAero", 1) && CSkin::m_fAeroSkinsValid && m_DwmActive;
+
+ }
+ m_isVsThemed = (m_VsAPI && m_pfnIsThemeActive && m_pfnIsThemeActive());
+ return(m_isAero);
+}
+
+/**
+ * Initialize various Win32 API functions which are not common to all versions of Windows.
+ * We have to work with functions pointers here.
+ */
+
+void CMimAPI::InitAPI()
+{
+ m_hUxTheme = 0;
+ m_VsAPI = false;
+
+ HMODULE hDLL = GetModuleHandleA("user32");
+ m_pSetLayeredWindowAttributes = (PSLWA) GetProcAddress(hDLL, "SetLayeredWindowAttributes");
+ m_MyFlashWindowEx = (PFWEX) GetProcAddress(hDLL, "FlashWindowEx");
+
+ m_MyAlphaBlend = (PAB) GetProcAddress(GetModuleHandleA("gdi32"), "GdiAlphaBlend");
+ if (m_MyAlphaBlend == 0)
+ m_MyAlphaBlend = (PAB) GetProcAddress(LoadLibraryA("msimg32.dll"), "AlphaBlend");
+
+ m_MyGradientFill = (PGF) GetProcAddress(GetModuleHandleA("gdi32"), "GdiGradientFill");
+ if (m_MyGradientFill == 0)
+ m_MyGradientFill = (PGF) GetProcAddress(GetModuleHandleA("msimg32"), "GradientFill");
+
+ m_pfnMonitorFromWindow = (MMFW)GetProcAddress(GetModuleHandleA("USER32"), "MonitorFromWindow");
+ m_pfnGetMonitorInfoA = (GMIA)GetProcAddress(GetModuleHandleA("USER32"), "GetMonitorInfoA");
+
+ if (IsWinVerXPPlus()) {
+ if ((m_hUxTheme = Utils::loadSystemLibrary(L"\\uxtheme.dll")) != 0) {
+ m_pfnIsThemeActive = (PITA)GetProcAddress(m_hUxTheme, "IsThemeActive");
+ m_pfnOpenThemeData = (POTD)GetProcAddress(m_hUxTheme, "OpenThemeData");
+ m_pfnDrawThemeBackground = (PDTB)GetProcAddress(m_hUxTheme, "DrawThemeBackground");
+ m_pfnCloseThemeData = (PCTD)GetProcAddress(m_hUxTheme, "CloseThemeData");
+ m_pfnDrawThemeText = (PDTT)GetProcAddress(m_hUxTheme, "DrawThemeText");
+ m_pfnIsThemeBackgroundPartiallyTransparent = (PITBPT)GetProcAddress(m_hUxTheme, "IsThemeBackgroundPartiallyTransparent");
+ m_pfnDrawThemeParentBackground = (PDTPB)GetProcAddress(m_hUxTheme, "DrawThemeParentBackground");
+ m_pfnGetThemeBackgroundContentRect = (PGTBCR)GetProcAddress(m_hUxTheme, "GetThemeBackgroundContentRect");
+ m_pfnEnableThemeDialogTexture = (ETDT)GetProcAddress(m_hUxTheme, "EnableThemeDialogTexture");
+
+ if (m_pfnIsThemeActive != 0 && m_pfnOpenThemeData != 0 && m_pfnDrawThemeBackground != 0 && m_pfnCloseThemeData != 0
+ && m_pfnDrawThemeText != 0 && m_pfnIsThemeBackgroundPartiallyTransparent != 0 && m_pfnDrawThemeParentBackground != 0
+ && m_pfnGetThemeBackgroundContentRect != 0) {
+ m_VsAPI = true;
+ }
+ }
+ }
+
+ /*
+ * vista+ DWM API
+ */
+
+ m_hDwmApi = 0;
+ if (IsWinVerVistaPlus()) {
+ m_hDwmApi = Utils::loadSystemLibrary(L"\\dwmapi.dll");
+ if (m_hDwmApi) {
+ m_pfnDwmExtendFrameIntoClientArea = (DEFICA)GetProcAddress(m_hDwmApi,"DwmExtendFrameIntoClientArea");
+ m_pfnDwmIsCompositionEnabled = (DICE)GetProcAddress(m_hDwmApi,"DwmIsCompositionEnabled");
+ m_pfnDwmRegisterThumbnail = (DRT)GetProcAddress(m_hDwmApi, "DwmRegisterThumbnail");
+ m_pfnDwmBlurBehindWindow = (BBW)GetProcAddress(m_hDwmApi, "DwmEnableBlurBehindWindow");
+ m_pfnDwmGetColorizationColor = (DGC)GetProcAddress(m_hDwmApi, "DwmGetColorizationColor");
+ m_pfnDwmInvalidateIconicBitmaps = (DWMIIB)GetProcAddress(m_hDwmApi, "DwmInvalidateIconicBitmaps");
+ m_pfnDwmSetWindowAttribute = (DWMSWA)GetProcAddress(m_hDwmApi, "DwmSetWindowAttribute");
+ m_pfnDwmUpdateThumbnailProperties = (DWMUT)GetProcAddress(m_hDwmApi, "DwmUpdateThumbnailProperties");
+ m_pfnDwmUnregisterThumbnail = (DURT)GetProcAddress(m_hDwmApi, "DwmUnregisterThumbnail");
+ m_pfnDwmSetIconicThumbnail = (DSIT)GetProcAddress(m_hDwmApi, "DwmSetIconicThumbnail");
+ m_pfnDwmSetIconicLivePreviewBitmap = (DSILP)GetProcAddress(m_hDwmApi, "DwmSetIconicLivePreviewBitmap");
+ }
+ /*
+ * additional uxtheme APIs (Vista+)
+ */
+ if(m_hUxTheme) {
+ m_pfnDrawThemeTextEx = (PDTTE)GetProcAddress(m_hUxTheme, "DrawThemeTextEx");
+ m_pfnBeginBufferedPaint = (BBP)GetProcAddress(m_hUxTheme, "BeginBufferedPaint");
+ m_pfnEndBufferedPaint = (EBP)GetProcAddress(m_hUxTheme, "EndBufferedPaint");
+ m_pfnBufferedPaintInit = (BPI)GetProcAddress(m_hUxTheme, "BufferedPaintInit");
+ m_pfnBufferedPaintUninit = (BPU)GetProcAddress(m_hUxTheme, "BufferedPaintUnInit");
+ m_pfnBufferedPaintSetAlpha = (BPSA)GetProcAddress(m_hUxTheme, "BufferedPaintSetAlpha");
+ m_haveBufferedPaint = (m_pfnBeginBufferedPaint != 0 && m_pfnEndBufferedPaint != 0) ? true : false;
+ if(m_haveBufferedPaint)
+ m_pfnBufferedPaintInit();
+ }
+ m_pfnGetLocaleInfoEx = (GLIX)GetProcAddress(GetModuleHandleA("kernel32"), "GetLocaleInfoEx");
+ }
+ else
+ m_haveBufferedPaint = false;
+}
+
+/**
+ * hook subscriber function for incoming message typing events
+ */
+
+int CMimAPI::TypingMessage(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwnd = 0;
+ int issplit = 1, foundWin = 0, preTyping = 0;
+ struct TContainerData *pContainer = NULL;
+ BOOL fShowOnClist = TRUE;
+
+ if(wParam) {
+
+ if ((hwnd = M->FindWindow((HANDLE) wParam)) && M->GetByte(SRMSGMOD, SRMSGSET_SHOWTYPING, SRMSGDEFSET_SHOWTYPING))
+ preTyping = SendMessage(hwnd, DM_TYPING, 0, lParam);
+
+ if (hwnd && IsWindowVisible(hwnd))
+ foundWin = MessageWindowOpened(0, (LPARAM)hwnd);
+ else
+ foundWin = 0;
+
+
+ if(hwnd) {
+ SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
+ if(pContainer == NULL)
+ return 0; // should never happen
+ }
+
+ if(M->GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST)) {
+ if(!hwnd && !M->GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGNOWINOPEN, 1))
+ fShowOnClist = FALSE;
+ if(hwnd && !M->GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINOPEN, 1))
+ fShowOnClist = FALSE;
+ }
+ else
+ fShowOnClist = FALSE;
+
+ if((!foundWin || !(pContainer->dwFlags&CNT_NOSOUND)) && preTyping != (lParam != 0)){
+ if (lParam)
+ SkinPlaySound("TNStart");
+ else
+ SkinPlaySound("TNStop");
+ }
+
+ if(M->GetByte(SRMSGMOD, "ShowTypingPopup", 0)) {
+ BOOL fShow = FALSE;
+ int iMode = M->GetByte("MTN_PopupMode", 0);
+
+ switch(iMode) {
+ case 0:
+ fShow = TRUE;
+ break;
+ case 1:
+ if(!foundWin || !(pContainer && pContainer->hwndActive == hwnd && GetForegroundWindow() == pContainer->hwnd))
+ fShow = TRUE;
+ break;
+ case 2:
+ if(hwnd == 0)
+ fShow = TRUE;
+ else {
+ if(PluginConfig.m_HideOnClose) {
+ struct TContainerData *pContainer = 0;
+ SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
+ if(pContainer && pContainer->fHidden)
+ fShow = TRUE;
+ }
+ }
+ break;
+ }
+ if(fShow)
+ TN_TypingMessage(wParam, lParam);
+ }
+
+ if ((int) lParam) {
+ TCHAR szTip[256];
+
+ _sntprintf(szTip, SIZEOF(szTip), CTranslator::get(CTranslator::GEN_MTN_STARTWITHNICK), (TCHAR *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, wParam, GCDNF_TCHAR));
+ if (fShowOnClist && ServiceExists(MS_CLIST_SYSTRAY_NOTIFY) && M->GetByte(SRMSGMOD, "ShowTypingBalloon", 0)) {
+ MIRANDASYSTRAYNOTIFY tn;
+ tn.szProto = NULL;
+ tn.cbSize = sizeof(tn);
+ tn.tszInfoTitle = const_cast<TCHAR *>(CTranslator::get(CTranslator::GEN_MTN_TTITLE));
+ tn.tszInfo = szTip;
+ tn.dwInfoFlags = NIIF_INFO | NIIF_INTERN_UNICODE;
+ tn.uTimeout = 1000 * 4;
+ CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM) & tn);
+ }
+ if(fShowOnClist) {
+ CLISTEVENT cle;
+
+ ZeroMemory(&cle, sizeof(cle));
+ cle.cbSize = sizeof(cle);
+ cle.hContact = (HANDLE) wParam;
+ cle.hDbEvent = (HANDLE) 1;
+ cle.flags = CLEF_ONLYAFEW | CLEF_TCHAR;
+ cle.hIcon = PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING];
+ cle.pszService = "SRMsg/TypingMessage";
+ cle.ptszTooltip = szTip;
+ CallServiceSync(MS_CLIST_REMOVEEVENT, wParam, (LPARAM) 1);
+ CallServiceSync(MS_CLIST_ADDEVENT, wParam, (LPARAM) & cle);
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * this is the global ack dispatcher. It handles both ACKTYPE_MESSAGE and ACKTYPE_AVATAR events
+ * for ACKTYPE_MESSAGE it searches the corresponding send job in the queue and, if found, dispatches
+ * it to the owners window
+ *
+ * ACKTYPE_AVATAR no longer handled here, because we have avs services now.
+ */
+
+int CMimAPI::ProtoAck(WPARAM wParam, LPARAM lParam)
+{
+ ACKDATA *pAck = (ACKDATA *) lParam;
+ HWND hwndDlg = 0;
+ int i = 0, j, iFound = SendQueue::NR_SENDJOBS;
+
+ if (lParam == 0)
+ return 0;
+
+ SendJob *jobs = sendQueue->getJobByIndex(0);
+
+ if (pAck->type == ACKTYPE_MESSAGE) {
+ for (j = 0; j < SendQueue::NR_SENDJOBS; j++) {
+ if (pAck->hProcess == jobs[j].hSendId && pAck->hContact == jobs[j].hOwner) {
+ TWindowData *dat = jobs[j].hwndOwner ? (TWindowData *)GetWindowLongPtr(jobs[j].hwndOwner, GWLP_USERDATA) : NULL;
+ if (dat) {
+ if (dat->hContact == jobs[j].hOwner) {
+ iFound = j;
+ break;
+ }
+ } else { // ack message w/o an open window...
+ sendQueue->ackMessage(NULL, (WPARAM)MAKELONG(j, i), lParam);
+ return 0;
+ }
+ }
+ if (iFound == SendQueue::NR_SENDJOBS) // no mathing entry found in this queue entry.. continue
+ continue;
+ else
+ break;
+ }
+ if (iFound == SendQueue::NR_SENDJOBS) { // no matching send info found in the queue
+ sendLater->processAck(pAck); //
+ return 0; // try to find the process handle in the list of open send later jobs
+ } else { // the job was found
+ SendMessage(jobs[iFound].hwndOwner, HM_EVENTSENT, (WPARAM)MAKELONG(iFound, i), lParam);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+int CMimAPI::PrebuildContactMenu(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)wParam;
+ if ( hContact ) {
+ char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+
+ CLISTMENUITEM clmi = {0};
+ clmi.cbSize = sizeof( CLISTMENUITEM );
+ clmi.flags = CMIM_FLAGS | CMIF_DEFAULT | CMIF_HIDDEN;
+
+ if ( szProto ) {
+ // leave this menu item hidden for chats
+ if ( !M->GetByte(hContact, szProto, "ChatRoom", 0 ))
+ if ( CallProtoService( szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND )
+ clmi.flags &= ~CMIF_HIDDEN;
+ }
+
+ CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )PluginConfig.m_hMenuItem, ( LPARAM )&clmi );
+ }
+ return 0;
+}
+
+/**
+ * this handler is called first in the message window chain - it will handle events for which a message window
+ * is already open. if not, it will do nothing and the 2nd handler (MessageEventAdded) will perform all
+ * the needed actions.
+ *
+ * this handler POSTs the event to the message window procedure - so it is fast and can exit quickly which will
+ * improve the overall responsiveness when receiving messages.
+ */
+
+int CMimAPI::DispatchNewEvent(WPARAM wParam, LPARAM lParam)
+{
+ if (wParam) {
+ HWND h = M->FindWindow((HANDLE)wParam);
+ if (h)
+ PostMessage(h, HM_DBEVENTADDED, wParam, lParam); // was SENDMESSAGE !!! XXX
+ }
+ return 0;
+}
+
+/**
+ * Message event added is called when a new message is added to the database
+ * if no session is open for the contact, this function will determine if and how a new message
+ * session (tab) must be created.
+ *
+ * if a session is already created, it just does nothing and DispatchNewEvent() will take care.
+ */
+
+int CMimAPI::MessageEventAdded(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwnd;
+ CLISTEVENT cle;
+ DBEVENTINFO dbei;
+ BYTE bAutoPopup = FALSE, bAutoCreate = FALSE, bAutoContainer = FALSE, bAllowAutoCreate = 0;
+ struct TContainerData *pContainer = 0;
+ TCHAR szName[CONTAINER_NAMELEN + 1];
+ DWORD dwStatusMask = 0;
+ struct TWindowData *mwdat=NULL;
+
+ ZeroMemory(&dbei, sizeof(dbei));
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = 0;
+ CallService(MS_DB_EVENT_GET, lParam, (LPARAM) & dbei);
+
+ hwnd = M->FindWindow((HANDLE) wParam);
+
+ if (dbei.flags & DBEF_SENT || !(dbei.eventType == EVENTTYPE_MESSAGE || dbei.eventType == EVENTTYPE_FILE) || dbei.flags & DBEF_READ)
+ return 0;
+
+ CallServiceSync(MS_CLIST_REMOVEEVENT, wParam, (LPARAM) 1);
+ //MaD: hide on close mod, simulating standard behavior for hidden container
+ if (hwnd) {
+ struct TContainerData *pTargetContainer = 0;
+ WINDOWPLACEMENT wp={0};
+ wp.length = sizeof(wp);
+ SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pTargetContainer);
+
+ if(pTargetContainer && PluginConfig.m_HideOnClose && !IsWindowVisible(pTargetContainer->hwnd)) {
+ GetWindowPlacement(pTargetContainer->hwnd, &wp);
+ GetContainerNameForContact((HANDLE) wParam, szName, CONTAINER_NAMELEN);
+
+ bAutoPopup = M->GetByte(SRMSGSET_AUTOPOPUP, SRMSGDEFSET_AUTOPOPUP);
+ bAutoCreate = M->GetByte("autotabs", 1);
+ bAutoContainer = M->GetByte("autocontainer", 1);
+ dwStatusMask = M->GetDword("autopopupmask", -1);
+
+ bAllowAutoCreate = FALSE;
+
+ if (bAutoPopup || bAutoCreate) {
+ BOOL bActivate = TRUE, bPopup = TRUE;
+ if(bAutoPopup) {
+ if(wp.showCmd == SW_SHOWMAXIMIZED)
+ ShowWindow(pTargetContainer->hwnd, SW_SHOWMAXIMIZED);
+ else
+ ShowWindow(pTargetContainer->hwnd, SW_SHOWNOACTIVATE);
+ return 0;
+ }
+ else {
+ bActivate = FALSE;
+ bPopup = (BOOL) M->GetByte("cpopup", 0);
+ pContainer = FindContainerByName(szName);
+ if (pContainer != NULL) {
+ if(bAutoContainer) {
+ ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE);
+ return 0;
+ }
+ else goto nowindowcreate;
+ }
+ else {
+ if(bAutoContainer) {
+ ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE);
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ else
+ return 0;
+ } else {
+ if(dbei.eventType == EVENTTYPE_FILE) {
+ tabSRMM_ShowPopup(wParam, lParam, dbei.eventType, 0, 0, 0, dbei.szModule, 0);
+ return(0);
+ }
+ }
+
+ /*
+ * if no window is open, we are not interested in anything else but unread message events
+ */
+
+ /* new message */
+ if (!nen_options.iNoSounds)
+ SkinPlaySound("AlertMsg");
+
+ if (nen_options.iNoAutoPopup)
+ goto nowindowcreate;
+
+ GetContainerNameForContact((HANDLE) wParam, szName, CONTAINER_NAMELEN);
+
+ bAutoPopup = M->GetByte(SRMSGSET_AUTOPOPUP, SRMSGDEFSET_AUTOPOPUP);
+ bAutoCreate = M->GetByte("autotabs", 1);
+ bAutoContainer = M->GetByte("autocontainer", 1);
+ dwStatusMask = M->GetDword("autopopupmask", -1);
+
+ bAllowAutoCreate = FALSE;
+
+ if (dwStatusMask == -1)
+ bAllowAutoCreate = TRUE;
+ else {
+ char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)wParam, 0);
+ DWORD dwStatus = 0;
+
+ if (PluginConfig.g_MetaContactsAvail && szProto && !strcmp(szProto, (char *)CallService(MS_MC_GETPROTOCOLNAME, 0, 0))) {
+ HANDLE hSubconttact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, wParam, 0);
+
+ szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hSubconttact, 0);
+ }
+ if (szProto) {
+ dwStatus = (DWORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ if (dwStatus == 0 || dwStatus <= ID_STATUS_OFFLINE || ((1 << (dwStatus - ID_STATUS_ONLINE)) & dwStatusMask)) // should never happen, but...
+ bAllowAutoCreate = TRUE;
+ }
+ }
+ if (bAllowAutoCreate && (bAutoPopup || bAutoCreate)) {
+ BOOL bActivate = TRUE, bPopup = TRUE;
+ if (bAutoPopup) {
+ bActivate = bPopup = TRUE;
+ if ((pContainer = FindContainerByName(szName)) == NULL)
+ pContainer = CreateContainer(szName, FALSE, (HANDLE)wParam);
+ CreateNewTabForContact(pContainer, (HANDLE) wParam, 0, NULL, bActivate, bPopup, FALSE, 0);
+ return 0;
+ } else {
+ bActivate = FALSE;
+ bPopup = (BOOL) M->GetByte("cpopup", 0);
+ pContainer = FindContainerByName(szName);
+ if (pContainer != NULL) {
+ //if ((IsIconic(pContainer->hwnd)) && PluginConfig.haveAutoSwitch())
+ // pContainer->dwFlags |= CNT_DEFERREDTABSELECT;
+ if (M->GetByte("limittabs", 0) && !wcsncmp(pContainer->szName, L"default", 6)) {
+ if ((pContainer = FindMatchingContainer(L"default", (HANDLE)wParam)) != NULL) {
+ CreateNewTabForContact(pContainer, (HANDLE) wParam, 0, NULL, bActivate, bPopup, TRUE, (HANDLE)lParam);
+ return 0;
+ } else if (bAutoContainer) {
+ pContainer = CreateContainer(szName, CNT_CREATEFLAG_MINIMIZED, (HANDLE)wParam); // 2 means create minimized, don't popup...
+ CreateNewTabForContact(pContainer, (HANDLE) wParam, 0, NULL, bActivate, bPopup, TRUE, (HANDLE)lParam);
+ SendMessageW(pContainer->hwnd, WM_SIZE, 0, 0);
+ return 0;
+ }
+ } else {
+ CreateNewTabForContact(pContainer, (HANDLE) wParam, 0, NULL, bActivate, bPopup, TRUE, (HANDLE)lParam);
+ return 0;
+ }
+
+ } else {
+ if (bAutoContainer) {
+ pContainer = CreateContainer(szName, CNT_CREATEFLAG_MINIMIZED, (HANDLE)wParam); // 2 means create minimized, don't popup...
+ CreateNewTabForContact(pContainer, (HANDLE) wParam, 0, NULL, bActivate, bPopup, TRUE, (HANDLE)lParam);
+ SendMessageW(pContainer->hwnd, WM_SIZE, 0, 0);
+ return 0;
+ }
+ }
+ }
+ }
+
+ /*
+ * for tray support, we add the event to the tray menu. otherwise we send it back to
+ * the contact list for flashing
+ */
+nowindowcreate:
+ if (!(dbei.flags & DBEF_READ)) {
+ UpdateTrayMenu(0, 0, dbei.szModule, NULL, (HANDLE)wParam, 1);
+ if (!nen_options.bTraySupport) {
+ TCHAR toolTip[256], *contactName;
+ ZeroMemory(&cle, sizeof(cle));
+ cle.cbSize = sizeof(cle);
+ cle.hContact = (HANDLE) wParam;
+ cle.hDbEvent = (HANDLE) lParam;
+ cle.flags = CLEF_TCHAR;
+ cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ cle.pszService = "SRMsg/ReadMessage";
+ contactName = (TCHAR*) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, wParam, GCDNF_TCHAR);
+ mir_sntprintf(toolTip, SIZEOF(toolTip), CTranslator::get(CTranslator::GEN_MSG_TTITLE), contactName);
+ cle.ptszTooltip = toolTip;
+ CallService(MS_CLIST_ADDEVENT, 0, (LPARAM) & cle);
+ }
+ tabSRMM_ShowPopup(wParam, lParam, dbei.eventType, 0, 0, 0, dbei.szModule, 0);
+ }
+ return 0;
+}
+
+CMimAPI *M = 0;
+FI_INTERFACE *FIF = 0;
diff --git a/plugins/TabSRMM/src/msgdialog.cpp b/plugins/TabSRMM/src/msgdialog.cpp
new file mode 100644
index 0000000000..33b8234ae7
--- /dev/null
+++ b/plugins/TabSRMM/src/msgdialog.cpp
@@ -0,0 +1,3895 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: msgdialog.cpp 13447 2011-03-14 19:55:07Z george.hazan $
+ *
+ * This implements the message dialog window.
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+#define MS_HTTPSERVER_ADDFILENAME "HTTPServer/AddFileName"
+
+extern TTemplateSet RTL_Active, LTR_Active;
+const TCHAR* pszIDCSAVE_close = 0, *pszIDCSAVE_save = 0;
+
+static WNDPROC OldMessageEditProc=0, OldAvatarWndProc=0, OldMessageLogProc=0, oldAvatarParentWndProc=0;
+ WNDPROC OldIEViewProc = 0;
+
+WNDPROC OldSplitterProc = 0;
+
+static const UINT sendControls[] = { IDC_MESSAGE, IDC_LOG };
+static const UINT formatControls[] = { IDC_SMILEYBTN, IDC_FONTBOLD, IDC_FONTITALIC, IDC_FONTUNDERLINE, IDC_FONTFACE,IDC_FONTSTRIKEOUT };
+static const UINT addControls[] = { IDC_ADD, IDC_CANCELADD };
+
+static const UINT errorControls[] = { IDC_STATICERRORICON, IDC_STATICTEXT, IDC_RETRY, IDC_CANCELSEND, IDC_MSGSENDLATER};
+
+static struct _tooltips {
+ int id;
+ int translate_id;
+} tooltips[] = {
+ IDC_ADD, CTranslator::GEN_TOOLTIP_ADDCONTACT,
+ IDC_CANCELADD, CTranslator::GEN_TOOLTIP_DONTADD,
+ IDC_TOGGLESIDEBAR, CTranslator::GEN_TOOLTIP_EXPANDSIDEBAR,
+ -1, NULL
+};
+
+static struct _buttonicons {
+ int id;
+ HICON *pIcon;
+} buttonicons[] = {
+ IDC_ADD, &PluginConfig.g_buttonBarIcons[ICON_BUTTON_ADD],
+ IDC_CANCELADD, &PluginConfig.g_buttonBarIcons[ICON_BUTTON_CANCEL],
+ -1, NULL
+};
+
+static void _clrMsgFilter(LPARAM lParam)
+{
+ MSGFILTER *m = reinterpret_cast<MSGFILTER *>(lParam);
+
+ m->msg = 0;
+ m->lParam = 0;
+ m->wParam = 0;
+}
+
+static BOOL IsStringValidLinkA(char* pszText)
+{
+ char *p = pszText;
+
+ if (pszText == NULL)
+ return FALSE;
+ if (lstrlenA(pszText) < 5)
+ return FALSE;
+
+ while (*p) {
+ if (*p == '"')
+ return FALSE;
+ p++;
+ }
+ if (tolower(pszText[0]) == 'w' && tolower(pszText[1]) == 'w' && tolower(pszText[2]) == 'w' && pszText[3] == '.' && isalnum(pszText[4]))
+ return TRUE;
+
+ return(strstr(pszText, "://") == NULL ? FALSE : TRUE);
+}
+
+BOOL TSAPI IsUtfSendAvailable(HANDLE hContact)
+{
+ char* szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto == NULL)
+ return FALSE;
+
+ return (CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_IMSENDUTF) ? TRUE : FALSE;
+}
+
+/**
+ * show a modified context menu for the richedit control(s)
+ * @param dat message window data
+ * @param idFrom dlg ctrl id
+ * @param hwndFrom src window handle
+ * @param pt mouse pointer position
+ */
+static void ShowPopupMenu(TWindowData *dat, int idFrom, HWND hwndFrom, POINT pt)
+{
+ HMENU hMenu, hSubMenu;
+ CHARRANGE sel, all = { 0, -1};
+ int iSelection;
+ unsigned oldCodepage = dat->codePage;
+ int iPrivateBG = M->GetByte(dat->hContact, "private_bg", 0);
+ MessageWindowPopupData mwpd;
+ HWND hwndDlg = dat->hwnd;
+
+ hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT));
+ if (idFrom == IDC_LOG)
+ hSubMenu = GetSubMenu(hMenu, 0);
+ else {
+ hSubMenu = GetSubMenu(hMenu, 2);
+ EnableMenuItem(hSubMenu, IDM_PASTEFORMATTED, MF_BYCOMMAND | (dat->SendFormat != 0 ? MF_ENABLED : MF_GRAYED));
+ EnableMenuItem(hSubMenu, ID_EDITOR_PASTEANDSENDIMMEDIATELY, MF_BYCOMMAND | (PluginConfig.m_PasteAndSend ? MF_ENABLED : MF_GRAYED));
+ CheckMenuItem(hSubMenu, ID_EDITOR_SHOWMESSAGELENGTHINDICATOR, MF_BYCOMMAND | (PluginConfig.m_visualMessageSizeIndicator ? MF_CHECKED : MF_UNCHECKED));
+ EnableMenuItem(hSubMenu, ID_EDITOR_SHOWMESSAGELENGTHINDICATOR, MF_BYCOMMAND | (dat->pContainer->hwndStatus ? MF_ENABLED : MF_GRAYED));
+ }
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hSubMenu, 0);
+ SendMessage(hwndFrom, EM_EXGETSEL, 0, (LPARAM) & sel);
+ if (sel.cpMin == sel.cpMax) {
+ EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED);
+ //MAD
+ EnableMenuItem(hSubMenu, IDM_QUOTE, MF_BYCOMMAND | MF_GRAYED);
+ //MAD_
+ if (idFrom == IDC_MESSAGE)
+ EnableMenuItem(hSubMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED);
+ }
+
+ if (idFrom == IDC_LOG) {
+ int i;
+ //MAD: quote mod
+ InsertMenuA(hSubMenu, 6/*5*/, MF_BYPOSITION | MF_SEPARATOR, 0, 0);
+ InsertMenu(hSubMenu, 7/*6*/, MF_BYPOSITION | MF_POPUP, (UINT_PTR) PluginConfig.g_hMenuEncoding, CTranslator::get(CTranslator::GEN_MSG_ENCODING));
+ for (i = 0; i < GetMenuItemCount(PluginConfig.g_hMenuEncoding); i++)
+ CheckMenuItem(PluginConfig.g_hMenuEncoding, i, MF_BYPOSITION | MF_UNCHECKED);
+ if (dat->codePage == CP_ACP)
+ CheckMenuItem(PluginConfig.g_hMenuEncoding, 0, MF_BYPOSITION | MF_CHECKED);
+ else
+ CheckMenuItem(PluginConfig.g_hMenuEncoding, dat->codePage, MF_BYCOMMAND | MF_CHECKED);
+ CheckMenuItem(hSubMenu, ID_LOG_FREEZELOG, MF_BYCOMMAND | (dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED ? MF_CHECKED : MF_UNCHECKED));
+ }
+
+ if (idFrom == IDC_LOG || idFrom == IDC_MESSAGE) {
+ // First notification
+ mwpd.cbSize = sizeof(mwpd);
+ mwpd.uType = MSG_WINDOWPOPUP_SHOWING;
+ mwpd.uFlags = (idFrom == IDC_LOG ? MSG_WINDOWPOPUP_LOG : MSG_WINDOWPOPUP_INPUT);
+ mwpd.hContact = dat->hContact;
+ mwpd.hwnd = hwndFrom;
+ mwpd.hMenu = hSubMenu;
+ mwpd.selection = 0;
+ mwpd.pt = pt;
+ NotifyEventHooks(PluginConfig.m_event_MsgPopup, 0, (LPARAM)&mwpd);
+ }
+
+ iSelection = TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL);
+
+ if (idFrom == IDC_LOG || idFrom == IDC_MESSAGE) {
+ // Second notification
+ mwpd.selection = iSelection;
+ mwpd.uType = MSG_WINDOWPOPUP_SELECTED;
+ NotifyEventHooks(PluginConfig.m_event_MsgPopup, 0, (LPARAM)&mwpd);
+ }
+
+ if (((iSelection > 800 && iSelection < 1400) || iSelection == 20866) && idFrom == IDC_LOG) {
+ dat->codePage = iSelection;
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "ANSIcodepage", dat->codePage);
+ } else if (iSelection == 500 && idFrom == IDC_LOG) {
+ dat->codePage = CP_ACP;
+ DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "ANSIcodepage");
+ } else {
+ switch (iSelection) {
+ case IDM_COPY:
+ SendMessage(hwndFrom, WM_COPY, 0, 0);
+ break;
+ case IDM_CUT:
+ SendMessage(hwndFrom, WM_CUT, 0, 0);
+ break;
+ case IDM_PASTE:
+ case IDM_PASTEFORMATTED:
+ if (idFrom == IDC_MESSAGE)
+ SendMessage(hwndFrom, EM_PASTESPECIAL, (iSelection == IDM_PASTE) ? CF_TEXTT : 0, 0);
+ break;
+ case IDM_COPYALL:
+ SendMessage(hwndFrom, EM_EXSETSEL, 0, (LPARAM) & all);
+ SendMessage(hwndFrom, WM_COPY, 0, 0);
+ SendMessage(hwndFrom, EM_EXSETSEL, 0, (LPARAM) & sel);
+ break;
+ //MAD
+ case IDM_QUOTE:
+ SendMessage(hwndDlg,WM_COMMAND, IDC_QUOTE, 0);
+ break;
+ //MAD_
+ case IDM_SELECTALL:
+ SendMessage(hwndFrom, EM_EXSETSEL, 0, (LPARAM) & all);
+ break;
+ case IDM_CLEAR:
+ ClearLog(dat);
+ break;
+ case ID_LOG_FREEZELOG:
+ SendMessage(GetDlgItem(hwndDlg, IDC_LOG), WM_KEYDOWN, VK_F12, 0);
+ break;
+ case ID_EDITOR_SHOWMESSAGELENGTHINDICATOR:
+ PluginConfig.m_visualMessageSizeIndicator = !PluginConfig.m_visualMessageSizeIndicator;
+ M->WriteByte(SRMSGMOD_T, "msgsizebar", (BYTE)PluginConfig.m_visualMessageSizeIndicator);
+ M->BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 0);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ if(dat->pContainer->hwndStatus)
+ RedrawWindow(dat->pContainer->hwndStatus, 0, 0, RDW_INVALIDATE | RDW_UPDATENOW);
+ break;
+ case ID_EDITOR_PASTEANDSENDIMMEDIATELY:
+ HandlePasteAndSend(dat);
+ break;
+ }
+ }
+ if (idFrom == IDC_LOG)
+ RemoveMenu(hSubMenu, 7, MF_BYPOSITION);
+ DestroyMenu(hMenu);
+ if (dat->codePage != oldCodepage) {
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ SendMessage(hwndDlg, DM_UPDATETITLE, 0, 1);
+ }
+}
+
+static void ResizeIeView(const TWindowData *dat, DWORD px, DWORD py, DWORD cx, DWORD cy)
+{
+ RECT rcRichEdit;
+ POINT pt;
+ IEVIEWWINDOW ieWindow;
+ int iMode = dat->hwndIEView ? 1 : 2;
+ HWND hwndDlg = dat->hwnd;
+
+ ZeroMemory(&ieWindow, sizeof(ieWindow));
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_LOG), &rcRichEdit);
+ pt.x = rcRichEdit.left;
+ pt.y = rcRichEdit.top;
+ ScreenToClient(hwndDlg, &pt);
+ ieWindow.cbSize = sizeof(IEVIEWWINDOW);
+ ieWindow.iType = IEW_SETPOS;
+ ieWindow.parent = hwndDlg;
+ ieWindow.hwnd = iMode == 1 ? dat->hwndIEView : dat->hwndHPP;
+ ieWindow.x = pt.x;
+ ieWindow.y = pt.y;
+ ieWindow.cx = rcRichEdit.right - rcRichEdit.left;
+ ieWindow.cy = rcRichEdit.bottom - rcRichEdit.top;
+ if (ieWindow.cx != 0 && ieWindow.cy != 0) {
+ CallService(iMode == 1 ? MS_IEVIEW_WINDOW : MS_HPP_EG_WINDOW, 0, (LPARAM)&ieWindow);
+ }
+}
+
+LRESULT CALLBACK IEViewSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct TWindowData *mwdat = (struct TWindowData *)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
+
+ switch (msg) {
+ case WM_NCCALCSIZE:
+ return(CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, OldIEViewProc));
+ case WM_NCPAINT:
+ return(CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, OldIEViewProc));
+ }
+ return CallWindowProc(OldIEViewProc, hwnd, msg, wParam, lParam);
+}
+
+/*
+ * sublassing procedure for the h++ based message log viewer
+ */
+
+LRESULT CALLBACK HPPKFSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+
+ struct TWindowData *mwdat = (struct TWindowData *)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
+ if(mwdat) {
+ BOOL isCtrl, isShift, isAlt;
+ KbdState(mwdat, isShift, isCtrl, isAlt);
+
+ switch(msg) {
+ case WM_NCCALCSIZE:
+ return(CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, mwdat->oldIEViewProc));
+ case WM_NCPAINT:
+ return(CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, mwdat->oldIEViewProc));
+
+ case WM_KEYDOWN:
+ if(!isCtrl && !isAlt&&!isShift) {
+ {
+ if (wParam != VK_PRIOR&&wParam != VK_NEXT&&
+ wParam != VK_DELETE&&wParam != VK_MENU&&wParam != VK_END&&
+ wParam != VK_HOME&&wParam != VK_UP&&wParam != VK_DOWN&&
+ wParam != VK_LEFT&&wParam != VK_RIGHT&&wParam != VK_TAB&&
+ wParam != VK_SPACE) {
+ SetFocus(GetDlgItem(mwdat->hwnd,IDC_MESSAGE));
+ keybd_event((BYTE)wParam, (BYTE)MapVirtualKey(wParam,0), KEYEVENTF_EXTENDEDKEY | 0, 0);
+ return 0;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return CallWindowProc(mwdat->oldIEViewProc, hwnd, msg, wParam, lParam);
+}
+
+/*
+ * update state of the container - this is called whenever a tab becomes active, no matter how and
+ * deals with various things like updating the title bar, removing flashing icons, updating the
+ * session list, switching the keyboard layout (autolocale active) and the general container status.
+ *
+ * it protects itself from being called more than once per session activation and is valid for
+ * normal IM sessions *only*. Group chat sessions have their own activation handler (see chat/window.c)
+*/
+
+static void MsgWindowUpdateState(TWindowData *dat, UINT msg)
+{
+ if (dat && dat->iTabID >= 0) {
+ HWND hwndDlg = dat->hwnd;
+ HWND hwndTab = GetParent(hwndDlg);
+
+ if (msg == WM_ACTIVATE) {
+ if (dat->pContainer->dwFlags & CNT_TRANSPARENCY && CMimAPI::m_pSetLayeredWindowAttributes != NULL) {
+ DWORD trans = LOWORD(dat->pContainer->settings->dwTransparency);
+ CMimAPI::m_pSetLayeredWindowAttributes(dat->pContainer->hwnd, 0, (BYTE)trans, (dat->pContainer->dwFlags & CNT_TRANSPARENCY ? LWA_ALPHA : 0));
+ }
+ }
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ if(dat->fIsAutosizingInput && dat->iInputAreaHeight == -1) {
+ dat->iInputAreaHeight = 0;
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_REQUESTRESIZE, 0, 0);
+ }
+#endif
+ if(dat->pWnd)
+ dat->pWnd->activateTab();
+ dat->Panel->dismissConfig();
+ dat->dwUnread = 0;
+ if (dat->pContainer->hwndSaved == hwndDlg)
+ return;
+
+ dat->pContainer->hwndSaved = hwndDlg;
+
+ dat->dwTickLastEvent = 0;
+ dat->dwFlags &= ~MWF_DIVIDERSET;
+ if (KillTimer(hwndDlg, TIMERID_FLASHWND)) {
+ FlashTab(dat, hwndTab, dat->iTabID, &dat->bTabFlash, FALSE, dat->hTabIcon);
+ dat->mayFlashTab = FALSE;
+ }
+ if (dat->pContainer->dwFlashingStarted != 0) {
+ FlashContainer(dat->pContainer, 0, 0);
+ dat->pContainer->dwFlashingStarted = 0;
+ }
+ if (dat->dwFlagsEx & MWF_SHOW_FLASHCLIST) {
+ dat->dwFlagsEx &= ~MWF_SHOW_FLASHCLIST;
+ if (dat->hFlashingEvent != 0)
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM)dat->hContact, (LPARAM)dat->hFlashingEvent);
+ dat->hFlashingEvent = 0;
+ }
+ dat->pContainer->dwFlags &= ~CNT_NEED_UPDATETITLE;
+
+ if (dat->dwFlags & MWF_DEFERREDREMAKELOG) {
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ dat->dwFlags &= ~MWF_DEFERREDREMAKELOG;
+ }
+
+ if (dat->dwFlags & MWF_NEEDCHECKSIZE)
+ PostMessage(hwndDlg, DM_SAVESIZE, 0, 0);
+
+ if (PluginConfig.m_AutoLocaleSupport) {
+ if (dat->hkl == 0)
+ DM_LoadLocale(dat);
+ else
+ SendMessage(hwndDlg, DM_SETLOCALE, 0, 0);
+ }
+
+ dat->pContainer->hIconTaskbarOverlay = 0;
+ SendMessage(dat->pContainer->hwnd, DM_UPDATETITLE, (WPARAM)dat->hContact, 0);
+
+ UpdateStatusBar(dat);
+ dat->dwLastActivity = GetTickCount();
+ dat->pContainer->dwLastActivity = dat->dwLastActivity;
+
+ dat->pContainer->MenuBar->configureMenu();
+ UpdateTrayMenuState(dat, FALSE);
+
+ if (PluginConfig.m_MathModAvail) {
+ CallService(MTH_Set_ToolboxEditHwnd, 0, (LPARAM)GetDlgItem(hwndDlg, IDC_MESSAGE));
+ MTH_updateMathWindow(dat);
+ }
+ if(dat->pContainer->hwndActive == hwndDlg)
+ PostMessage(hwndDlg, DM_REMOVEPOPUPS, PU_REMOVE_ON_FOCUS, 0);
+
+ dat->Panel->Invalidate();
+
+ if (dat->dwFlags & MWF_DEFERREDSCROLL && dat->hwndIEView == 0 && dat->hwndHPP == 0) {
+ HWND hwnd = GetDlgItem(hwndDlg, IDC_LOG);
+
+ SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+ dat->dwFlags &= ~MWF_DEFERREDSCROLL;
+ SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_TOP, 0), 0);
+ SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+ DM_ScrollToBottom(dat, 0, 1);
+ PostMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), 0); // XXX was post()
+ }
+ DM_SetDBButtonStates(hwndDlg, dat);
+
+ if (dat->hwndIEView) {
+ RECT rcRTF;
+ POINT pt;
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_LOG), &rcRTF);
+ rcRTF.left += 20;
+ rcRTF.top += 20;
+ pt.x = rcRTF.left;
+ pt.y = rcRTF.top;
+ if (dat->hwndIEView) {
+ if (M->GetByte("subclassIEView", 0) && dat->oldIEViewProc == 0) {
+ WNDPROC wndProc = (WNDPROC)SetWindowLongPtr(dat->hwndIEView, GWLP_WNDPROC, (LONG_PTR)IEViewSubclassProc);
+ if (OldIEViewProc == 0)
+ OldIEViewProc = wndProc;
+ dat->oldIEViewProc = wndProc;
+ SetWindowPos(dat->hwndIEView, 0, 0, 0, 0, 0, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_DRAWFRAME);
+ RedrawWindow(dat->hwndIEView, 0, 0, RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW);
+ }
+ }
+ dat->hwndIWebBrowserControl = WindowFromPoint(pt);
+ }
+
+ if (dat->dwFlagsEx & MWF_EX_DELAYEDSPLITTER) {
+ dat->dwFlagsEx &= ~MWF_EX_DELAYEDSPLITTER;
+ ShowWindow(dat->pContainer->hwnd, SW_RESTORE);
+ PostMessage(hwndDlg, DM_SPLITTERGLOBALEVENT, dat->wParam, dat->lParam);
+ dat->wParam = dat->lParam = 0;
+ }
+ if (dat->dwFlagsEx & MWF_EX_AVATARCHANGED) {
+ dat->dwFlagsEx &= ~MWF_EX_AVATARCHANGED;
+ PostMessage(hwndDlg, DM_UPDATEPICLAYOUT, 0, 0);
+ }
+ BB_SetButtonsPos(dat);
+ if(M->isAero())
+ InvalidateRect(hwndTab, NULL, FALSE);
+ if(dat->pContainer->dwFlags & CNT_SIDEBAR)
+ dat->pContainer->SideBar->setActiveItem(dat);
+
+ if(dat->pWnd)
+ dat->pWnd->Invalidate();
+ }
+}
+
+void TSAPI ShowMultipleControls(HWND hwndDlg, const UINT *controls, int cControls, int state)
+{
+ int i;
+ for (i = 0; i < cControls; i++)
+ Utils::showDlgControl(hwndDlg, controls[i], state);
+}
+
+void TSAPI SetDialogToType(HWND hwndDlg)
+{
+ struct TWindowData *dat;
+ int showToolbar = 0;
+
+ dat = (struct TWindowData *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ showToolbar = dat->pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1;
+
+ if (dat->hContact) {
+ if (M->GetByte(dat->hContact, "CList", "NotOnList", 0)) {
+ dat->bNotOnList = TRUE;
+ ShowMultipleControls(hwndDlg, addControls, 2, SW_SHOW);
+ Utils::showDlgControl(hwndDlg, IDC_LOGFROZENTEXT, SW_SHOW);
+ SetWindowText(GetDlgItem(hwndDlg, IDC_LOGFROZENTEXT), CTranslator::get(CTranslator::GEN_MSG_CONTACT_NOT_ON_LIST));
+ } else {
+ ShowMultipleControls(hwndDlg, addControls, 2, SW_HIDE);
+ dat->bNotOnList = FALSE;
+ Utils::showDlgControl(hwndDlg, IDC_LOGFROZENTEXT, SW_HIDE);
+ }
+ }
+
+ Utils::enableDlgControl(hwndDlg, IDC_TIME, TRUE);
+
+ if (dat->hwndIEView || dat->hwndHPP) {
+ Utils::showDlgControl(hwndDlg, IDC_LOG, SW_HIDE);
+ Utils::enableDlgControl(hwndDlg, IDC_LOG, FALSE);
+ Utils::showDlgControl(hwndDlg, IDC_MESSAGE, SW_SHOW);
+ } else
+ ShowMultipleControls(hwndDlg, sendControls, sizeof(sendControls) / sizeof(sendControls[0]), SW_SHOW);
+
+ ShowMultipleControls(hwndDlg, errorControls, sizeof(errorControls) / sizeof(errorControls[0]), dat->dwFlags & MWF_ERRORSTATE ? SW_SHOW : SW_HIDE);
+
+ if (!dat->SendFormat)
+ ShowMultipleControls(hwndDlg, &formatControls[1], 5, SW_HIDE);
+
+ ConfigureSmileyButton(dat);
+
+ if (dat->pContainer->hwndActive == hwndDlg)
+ UpdateReadChars(dat);
+
+ SetDlgItemText(hwndDlg, IDC_STATICTEXT, CTranslator::get(CTranslator::GEN_MSG_FAILEDSEND));
+
+ DM_RecalcPictureSize(dat);
+ GetAvatarVisibility(hwndDlg, dat);
+
+ Utils::showDlgControl(hwndDlg, IDC_CONTACTPIC, dat->showPic ? SW_SHOW : SW_HIDE);
+ Utils::showDlgControl(hwndDlg, IDC_SPLITTER, dat->fIsAutosizingInput ? SW_HIDE : SW_SHOW);
+ Utils::showDlgControl(hwndDlg, IDC_MULTISPLITTER, (dat->sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE);
+
+ EnableSendButton(dat, GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)) != 0);
+ SendMessage(hwndDlg, DM_UPDATETITLE, 0, 1);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+
+ if (!PluginConfig.g_FlashAvatarAvail)
+ Utils::enableDlgControl(hwndDlg, IDC_CONTACTPIC, FALSE);
+
+ dat->Panel->Configure();
+}
+
+static LRESULT CALLBACK MessageLogSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndParent = GetParent(hwnd);
+ TWindowData *mwdat = (TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA);
+ BOOL isCtrl, isShift, isAlt;
+ KbdState(mwdat, isShift, isCtrl, isAlt);
+
+ switch (msg) {
+ case WM_KILLFOCUS: {
+ if(wParam != (WPARAM)hwnd && 0 != wParam) {
+ CHARRANGE cr;
+ SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&cr);
+ if (cr.cpMax != cr.cpMin) {
+ cr.cpMin = cr.cpMax;
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr);
+ }
+ }
+ break;
+ }
+ //MAD
+ case WM_CHAR:
+ if (wParam == 0x03 &&isCtrl)
+ return SendMessage(hwnd, WM_COPY, 0, 0);
+ if(wParam == 0x11 && isCtrl)
+ SendMessage(mwdat->hwnd,WM_COMMAND, IDC_QUOTE, 0);
+ break;
+
+
+ case WM_SYSKEYUP:
+ if(wParam == VK_MENU) {
+ ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_LOG);
+ return(0);
+ }
+ break;
+
+ case WM_SYSKEYDOWN:
+ mwdat->fkeyProcessed = false;
+ if(ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_LOG)) {
+ mwdat->fkeyProcessed = true;
+ return(0);
+ }
+ break;
+
+ case WM_SYSCHAR: {
+ if(mwdat->fkeyProcessed) {
+ mwdat->fkeyProcessed = false;
+ return(0);
+ }
+ break;
+ }
+ case WM_KEYDOWN:
+ if(!isCtrl && !isAlt&&!isShift)
+ {
+ if (/*wParam != VK_ESCAPE&&*/wParam != VK_PRIOR&&wParam != VK_NEXT&&
+ wParam != VK_DELETE&&wParam != VK_MENU&&wParam != VK_END&&
+ wParam != VK_HOME&&wParam != VK_UP&&wParam != VK_DOWN&&
+ wParam != VK_LEFT&&wParam != VK_RIGHT &&
+ wParam != VK_SPACE)
+ {
+ // TODO causes issues when pressing keys in the log
+ //SetFocus(GetDlgItem(mwdat->hwnd,IDC_MESSAGE));
+ //keybd_event((BYTE)wParam, (BYTE)MapVirtualKey(wParam,0), KEYEVENTF_EXTENDEDKEY | 0, 0);
+
+ //return 0;
+ }
+ }
+ break;
+ //MAD_
+ case WM_COPY: {
+ return(DM_WMCopyHandler(hwnd, OldMessageLogProc, wParam, lParam));
+ }
+ case WM_NCCALCSIZE:
+ return(CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, OldMessageLogProc));
+ case WM_NCPAINT:
+ return(CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, OldMessageLogProc));
+ case WM_CONTEXTMENU: {
+ POINT pt;
+
+ if (lParam == 0xFFFFFFFF) {
+ CHARRANGE sel;
+ SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) & sel);
+ SendMessage(hwnd, EM_POSFROMCHAR, (WPARAM) & pt, (LPARAM) sel.cpMax);
+ ClientToScreen(hwnd, &pt);
+ } else {
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ }
+
+ ShowPopupMenu(mwdat, IDC_LOG, hwnd, pt);
+ return TRUE;
+ }
+ case WM_NCDESTROY:
+ if(OldMessageLogProc)
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) OldMessageLogProc);
+ break;
+
+ }
+ return CallWindowProc(OldMessageLogProc, hwnd, msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ LONG lastEnterTime = GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ HWND hwndParent = GetParent(hwnd);
+ struct TWindowData *mwdat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA);
+
+ /*
+ * prevent the rich edit from switching text direction or keyboard layout when
+ * using hotkeys with ctrl-shift or alt-shift modifiers
+ */
+ if(mwdat->fkeyProcessed && (msg == WM_KEYUP)) {
+ GetKeyboardState(mwdat->kstate);
+ if(mwdat->kstate[VK_CONTROL] & 0x80 || mwdat->kstate[VK_SHIFT] & 0x80)
+ return(0);
+ else {
+ mwdat->fkeyProcessed = false;
+ return(0);
+ }
+ }
+ switch (msg) {
+ case WM_NCCALCSIZE:
+ return(CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKINPUTAREA, msg, wParam, lParam, OldMessageEditProc));
+ case WM_NCPAINT:
+ return(CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKINPUTAREA, msg, wParam, lParam, OldMessageEditProc));
+ case WM_DROPFILES:
+ SendMessage(hwndParent, WM_DROPFILES, (WPARAM)wParam, (LPARAM)lParam);
+ break;
+ case WM_CHAR: {
+ BOOL isCtrl, isShift, isAlt;
+ KbdState(mwdat, isShift, isCtrl, isAlt);
+ //MAD: sound on typing..
+ if(PluginConfig.g_bSoundOnTyping&&!isAlt&&!isCtrl&&!(mwdat->pContainer->dwFlags&CNT_NOSOUND)&&wParam!=VK_ESCAPE&&!(wParam==VK_TAB&&PluginConfig.m_AllowTab))
+ SkinPlaySound("SoundOnTyping");
+ //MAD
+ if (wParam == 0x0d && isCtrl && PluginConfig.m_MathModAvail) {
+ TCHAR toInsert[100];
+ BYTE keyState[256];
+ size_t i;
+ size_t iLen = lstrlen(PluginConfig.m_MathModStartDelimiter);
+ ZeroMemory(keyState, 256);
+ _tcsncpy(toInsert, PluginConfig.m_MathModStartDelimiter, 30);
+ _tcsncat(toInsert, PluginConfig.m_MathModStartDelimiter, 30);
+ SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM)toInsert);
+ SetKeyboardState(keyState);
+ for (i = 0; i < iLen; i++)
+ SendMessage(hwnd, WM_KEYDOWN, mwdat->dwFlags & MWF_LOG_RTL ? VK_RIGHT : VK_LEFT, 0);
+ return 0;
+ }
+ if (isCtrl && !isAlt) {
+ switch (wParam) {
+ case 0x02: // bold
+ if (mwdat->SendFormat) {
+ SendMessage(hwndParent, WM_COMMAND, MAKELONG(IDC_FONTBOLD, IDC_MESSAGE), 0);
+ }
+ return 0;
+ case 0x09:
+ if (mwdat->SendFormat) {
+ SendMessage(hwndParent, WM_COMMAND, MAKELONG(IDC_FONTITALIC, IDC_MESSAGE), 0);
+ }
+ return 0;
+ case 21:
+ if (mwdat->SendFormat) {
+ SendMessage(hwndParent, WM_COMMAND, MAKELONG(IDC_FONTUNDERLINE, IDC_MESSAGE), 0);
+ }
+ return 0;
+ case 0x0b:
+ SetWindowText(hwnd, _T(""));
+ return 0;
+ }
+ break;
+ }
+ break;
+ }
+ case WM_MOUSEWHEEL: {
+ LRESULT result = DM_MouseWheelHandler(hwnd, hwndParent, mwdat, wParam, lParam);
+
+ if (result == 0)
+ return 0;
+ break;
+ }
+ case WM_PASTE:
+ case EM_PASTESPECIAL: {
+ if (OpenClipboard(hwnd)) {
+ HANDLE hClip;
+ if(hClip = GetClipboardData(CF_TEXT)) {
+ if (lstrlenA((char *)hClip) > mwdat->nMax) {
+ TCHAR szBuffer[512];
+ if (M->GetByte("autosplit", 0))
+ _sntprintf(szBuffer, 512, CTranslator::get(CTranslator::GEN_MSG_TOO_LONG_SPLIT), mwdat->nMax - 10);
+ else
+ _sntprintf(szBuffer, 512, CTranslator::get(CTranslator::GEN_MSG_TOO_LONG_NOSPLIT), mwdat->nMax);
+ SendMessage(hwndParent, DM_ACTIVATETOOLTIP, IDC_MESSAGE, (LPARAM)szBuffer);
+ }
+ }
+ else if(hClip = GetClipboardData(CF_BITMAP))
+ SendHBitmapAsFile(mwdat, (HBITMAP)hClip);
+
+ CloseClipboard();
+ }
+ return CallWindowProc(OldMessageEditProc, hwnd, msg, wParam, lParam);
+ }
+ case WM_KEYDOWN: {
+ BOOL isCtrl, isShift, isAlt;
+ KbdState(mwdat, isShift, isCtrl, isAlt);
+
+ //MAD: sound on typing..
+ if(PluginConfig.g_bSoundOnTyping&&!isAlt&&!(mwdat->pContainer->dwFlags&CNT_NOSOUND)&&wParam == VK_DELETE)
+ SkinPlaySound("SoundOnTyping");
+ //
+
+ if (wParam == VK_INSERT && !isShift && !isCtrl && !isAlt) {
+ mwdat->fInsertMode = !mwdat->fInsertMode;
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd);
+ }
+ if (wParam == VK_CAPITAL || wParam == VK_NUMLOCK)
+ SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd);
+
+ if (wParam == VK_RETURN) {
+ if(mwdat->fEditNotesActive)
+ break;
+
+ if (isShift) {
+ if (PluginConfig.m_SendOnShiftEnter) {
+ PostMessage(hwndParent, WM_COMMAND, IDOK, 0);
+ return 0;
+ } else
+ break;
+ }
+ if ((isCtrl && !isShift) ^(0 != PluginConfig.m_SendOnEnter)) {
+ PostMessage(hwndParent, WM_COMMAND, IDOK, 0);
+ return 0;
+ }
+ if (PluginConfig.m_SendOnEnter || PluginConfig.m_SendOnDblEnter) {
+ if (isCtrl)
+ break;
+ else {
+ if (PluginConfig.m_SendOnDblEnter) {
+ if (lastEnterTime + 2 < time(NULL)) {
+ lastEnterTime = time(NULL);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, lastEnterTime);
+ break;
+ } else {
+ SendMessage(hwnd, WM_KEYDOWN, VK_BACK, 0);
+ SendMessage(hwnd, WM_KEYUP, VK_BACK, 0);
+ PostMessage(hwndParent, WM_COMMAND, IDOK, 0);
+ return 0;
+ }
+ }
+ PostMessage(hwndParent, WM_COMMAND, IDOK, 0);
+ return 0;
+ }
+ } else
+ break;
+ } else
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+
+ if (isCtrl && !isAlt && !isShift) {
+ if (!isShift && (wParam == VK_UP || wParam == VK_DOWN)) { // input history scrolling (ctrl-up / down)
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ if (mwdat)
+ mwdat->cache->inputHistoryEvent(wParam);
+ return 0;
+ }
+ }
+ if (isCtrl && isAlt && !isShift) {
+ switch (wParam) {
+ case VK_UP:
+ case VK_DOWN:
+ case VK_PRIOR:
+ case VK_NEXT:
+ case VK_HOME:
+ case VK_END: {
+ WPARAM wp = 0;
+
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ if (wParam == VK_UP)
+ wp = MAKEWPARAM(SB_LINEUP, 0);
+ else if (wParam == VK_PRIOR)
+ wp = MAKEWPARAM(SB_PAGEUP, 0);
+ else if (wParam == VK_NEXT)
+ wp = MAKEWPARAM(SB_PAGEDOWN, 0);
+ else if (wParam == VK_HOME)
+ wp = MAKEWPARAM(SB_TOP, 0);
+ else if (wParam == VK_END) {
+ DM_ScrollToBottom(mwdat, 0, 0);
+ return 0;
+ } else if (wParam == VK_DOWN)
+ wp = MAKEWPARAM(SB_LINEDOWN, 0);
+
+ if (mwdat->hwndIEView == 0 && mwdat->hwndHPP == 0)
+ SendMessage(GetDlgItem(hwndParent, IDC_LOG), WM_VSCROLL, wp, 0);
+ else
+ SendMessage(mwdat->hwndIWebBrowserControl, WM_VSCROLL, wp, 0);
+ return 0;
+ }
+ }
+ }
+ if (wParam == VK_RETURN)
+ break;
+ }
+ case WM_SYSKEYDOWN:
+ mwdat->fkeyProcessed = false;
+ if(ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_MESSAGE)) {
+ mwdat->fkeyProcessed = true;
+ return(0);
+ }
+ break;
+
+ case WM_SYSKEYUP:
+ if(wParam == VK_MENU) {
+ ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_MESSAGE);
+ return(0);
+ }
+ break;
+
+ case WM_SYSCHAR: {
+ if(mwdat->fkeyProcessed) {
+ mwdat->fkeyProcessed = false;
+ return(0);
+ }
+ HWND hwndDlg = hwndParent;
+ BOOL isCtrl, isShift, isAlt;
+
+ KbdState(mwdat, isShift, isCtrl, isAlt);
+ if ((wParam >= '0' && wParam <= '9') && isAlt) { // ALT-1 -> ALT-0 direct tab selection
+ BYTE bChar = (BYTE)wParam;
+ int iIndex;
+
+ if (bChar == '0')
+ iIndex = 10;
+ else
+ iIndex = bChar - (BYTE)'0';
+ SendMessage(mwdat->pContainer->hwnd, DM_SELECTTAB, DM_SELECT_BY_INDEX, (LPARAM)iIndex);
+ return 0;
+ }
+ break;
+ }
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ break;
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ break;
+ case WM_INPUTLANGCHANGEREQUEST:
+ return CallWindowProc(OldMessageEditProc, hwnd, WM_INPUTLANGCHANGEREQUEST, wParam, lParam);
+ case WM_INPUTLANGCHANGE:
+ if (PluginConfig.m_AutoLocaleSupport && GetFocus() == hwnd && mwdat->pContainer->hwndActive == hwndParent && GetForegroundWindow() == mwdat->pContainer->hwnd && GetActiveWindow() == mwdat->pContainer->hwnd) {
+ DM_SaveLocale(mwdat, wParam, lParam);
+ SendMessage(hwnd, EM_SETLANGOPTIONS, 0, (LPARAM) SendMessage(hwnd, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
+ return(1);
+ }
+ break;
+
+ case WM_ERASEBKGND:
+ return(CSkin::m_skinEnabled ? 0 : 1);
+
+ /*
+ * sent by smileyadd when the smiley selection window dies
+ * just grab the focus :)
+ */
+ case WM_USER + 100:
+ SetFocus(hwnd);
+ break;
+ case WM_CONTEXTMENU: {
+ POINT pt;
+
+ if (lParam == 0xFFFFFFFF) {
+ CHARRANGE sel;
+ SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) & sel);
+ SendMessage(hwnd, EM_POSFROMCHAR, (WPARAM) & pt, (LPARAM) sel.cpMax);
+ ClientToScreen(hwnd, &pt);
+ } else {
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ }
+
+ ShowPopupMenu(mwdat, IDC_MESSAGE, hwnd, pt);
+ return TRUE;
+ }
+ case WM_NCDESTROY:
+ if(OldMessageEditProc)
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) OldMessageEditProc);
+ break;
+
+
+ }
+ return CallWindowProc(OldMessageEditProc, hwnd, msg, wParam, lParam);
+}
+
+/*
+ * subclasses the avatar display controls, needed for skinning and to prevent
+ * it from flickering during resize/move operations.
+ */
+
+static LRESULT CALLBACK AvatarSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+
+ case WM_ERASEBKGND:
+ return TRUE;
+ case WM_UPDATEUISTATE:
+ return TRUE;
+ }
+ return CallWindowProc(OldAvatarWndProc, hwnd, msg, wParam, lParam);
+}
+
+LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndParent = GetParent(hwnd);
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA);
+
+ switch (msg) {
+ case WM_NCHITTEST:
+ return HTCLIENT;
+ case WM_SETCURSOR: {
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ SetCursor(rc.right > rc.bottom ? PluginConfig.hCurSplitNS : PluginConfig.hCurSplitWE);
+ return TRUE;
+ }
+ case WM_LBUTTONDOWN: {
+ if (hwnd == GetDlgItem(hwndParent, IDC_SPLITTER) || hwnd == GetDlgItem(hwndParent, IDC_SPLITTERY)) {
+ RECT rc;
+
+ if (dat) {
+ GetClientRect(hwnd, &rc);
+ dat->savedSplitter = rc.right > rc.bottom ? (short) HIWORD(GetMessagePos()) + rc.bottom / 2 : (short) LOWORD(GetMessagePos()) + rc.right / 2;
+ if (dat->bType == SESSIONTYPE_IM)
+ dat->savedSplitY = dat->splitterY;
+ else {
+ SESSION_INFO *si = (SESSION_INFO *)dat->si;
+ dat->savedSplitY = si->iSplitterY;
+ }
+ dat->savedDynaSplit = dat->dynaSplitter;
+ }
+ }
+ SetCapture(hwnd);
+ return 0;
+ }
+ case WM_MOUSEMOVE:
+ if (GetCapture() == hwnd) {
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ SendMessage(hwndParent, DM_SPLITTERMOVED, rc.right > rc.bottom ? (short) HIWORD(GetMessagePos()) + rc.bottom / 2 : (short) LOWORD(GetMessagePos()) + rc.right / 2, (LPARAM) hwnd);
+ }
+ return 0;
+ case WM_ERASEBKGND:
+ return(1);
+ case WM_PAINT: {
+ RECT rc;
+ PAINTSTRUCT ps;
+ HDC dc = BeginPaint(hwnd, &ps);
+ int ctrlId = GetDlgCtrlID(hwnd);
+
+ GetClientRect(hwnd, &rc);
+
+ if (dat && CSkin::m_skinEnabled)
+ CSkin::SkinDrawBG(hwnd, dat->pContainer->hwnd, dat->pContainer, &rc, dc);
+ else if(M->isAero() || M->isVSThemed()) {
+ if(ctrlId == IDC_PANELSPLITTER) {
+ EndPaint(hwnd, &ps);
+ return(0);
+ }
+ CSkin::FillBack(dc, &rc);
+ }
+ else
+ CSkin::FillBack(dc, &rc);
+ EndPaint(hwnd, &ps);
+ return 0;
+ }
+
+ case WM_LBUTTONUP: {
+ HWND hwndCapture = GetCapture();
+
+ ReleaseCapture();
+ DM_ScrollToBottom(dat, 0, 1);
+ if (dat && dat->bType == SESSIONTYPE_IM && hwnd == GetDlgItem(hwndParent, IDC_PANELSPLITTER)) {
+ SendMessage(hwndParent, WM_SIZE, 0, 0);
+ dat->panelWidth = -1;
+ RedrawWindow(hwndParent, NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW);
+ } else if ((dat && dat->bType == SESSIONTYPE_IM && hwnd == GetDlgItem(hwndParent, IDC_SPLITTER)) ||
+ (dat && dat->bType == SESSIONTYPE_CHAT && hwnd == GetDlgItem(hwndParent, IDC_SPLITTERY))) {
+ RECT rc;
+ POINT pt;
+ int selection;
+ HMENU hMenu = GetSubMenu(dat->pContainer->hMenuContext, 12);
+ LONG messagePos = GetMessagePos();
+
+ GetClientRect(hwnd, &rc);
+ if (hwndCapture != hwnd || dat->savedSplitter == (rc.right > rc.bottom ? (short) HIWORD(messagePos) + rc.bottom / 2 : (short) LOWORD(messagePos) + rc.right / 2))
+ break;
+ GetCursorPos(&pt);
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ if(dat->fIsAutosizingInput)
+ selection = ID_SPLITTERCONTEXT_SETPOSITIONFORTHISSESSION;
+ else
+ selection = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndParent, NULL);
+#else
+ selection = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndParent, NULL);
+#endif
+ switch (selection) {
+ case ID_SPLITTERCONTEXT_SAVEFORTHISCONTACTONLY: {
+ HWND hwndParent = GetParent(hwnd);
+
+ dat->dwFlagsEx |= MWF_SHOW_SPLITTEROVERRIDE;
+ M->WriteByte(dat->hContact, SRMSGMOD_T, "splitoverride", 1);
+ if (dat->bType == SESSIONTYPE_IM)
+ SaveSplitter(dat);
+ break;
+ }
+ case ID_SPLITTERCONTEXT_SETPOSITIONFORTHISSESSION:
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ if(dat->fIsAutosizingInput) {
+ RECT rc;
+ GetWindowRect(GetDlgItem(dat->hwnd, IDC_MESSAGE), &rc);
+ dat->iInputAreaHeight = 0;
+ }
+#endif
+ break;
+ case ID_SPLITTERCONTEXT_SAVEGLOBALFORALLSESSIONS: {
+
+ RECT rcWin;
+ BYTE bSync = M->GetByte("Chat", "SyncSplitter", 0);
+ DWORD dwOff_IM = 0, dwOff_CHAT = 0;
+
+ dwOff_CHAT = -(2 + (PluginConfig.g_DPIscaleY > 1.0 ? 1 : 0));
+ dwOff_IM = 2 + (PluginConfig.g_DPIscaleY > 1.0 ? 1 : 0);
+
+ GetWindowRect(hwndParent, &rcWin);
+ PluginConfig.lastSPlitterPos.pSrcDat = dat;
+ PluginConfig.lastSPlitterPos.pSrcContainer = dat->pContainer;
+ PluginConfig.lastSPlitterPos.lParam = rc.bottom;
+ PluginConfig.lastSPlitterPos.pos = rcWin.bottom - HIWORD(messagePos);
+ PluginConfig.lastSPlitterPos.pos_chat = rcWin.bottom - (short)HIWORD(messagePos) + rc.bottom / 2;
+ PluginConfig.lastSPlitterPos.off_chat = dwOff_CHAT;
+ PluginConfig.lastSPlitterPos.off_im = dwOff_IM;
+ PluginConfig.lastSPlitterPos.bSync = bSync;
+ SendMessage(dat->hwnd, DM_SPLITTERGLOBALEVENT, 0, 0);
+ M->BroadcastMessage(DM_SPLITTERGLOBALEVENT, 0, 0);
+ break;
+ }
+ default:
+ dat->splitterY = dat->savedSplitY;
+ dat->dynaSplitter = dat->savedDynaSplit;
+ DM_RecalcPictureSize(dat);
+ if (dat->bType == SESSIONTYPE_CHAT) {
+ SESSION_INFO *si = (SESSION_INFO *)dat->si;
+ si->iSplitterY = dat->savedSplitY;
+ dat->splitterY =si->iSplitterY + DPISCALEY_S(22);
+ }
+ CSkin::UpdateToolbarBG(dat);
+ SendMessage(hwndParent, WM_SIZE, 0, 0);
+ DM_ScrollToBottom(dat, 0, 1);
+ break;
+ }
+ }
+ return 0;
+ }
+ }
+ return CallWindowProc(OldSplitterProc, hwnd, msg, wParam, lParam);
+}
+
+/*
+ * resizer proc for the "new" layout.
+ */
+
+static int MessageDialogResize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL * urc)
+{
+ TWindowData* dat = (TWindowData *) lParam;
+ RECT rc, rcButton;
+ static int uinWidth, msgTop = 0, msgBottom = 0;
+
+ int showToolbar = dat->pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1;
+ BOOL bBottomToolbar = dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR ? 1 : 0;
+ static LONG rcLogBottom;
+
+ int panelHeight = dat->Panel->getHeight() + 1;
+ int s_offset = 0;
+ bool fInfoPanel = dat->Panel->isActive();
+ bool fErrorState = (dat->dwFlags & MWF_ERRORSTATE) ? true : false;
+
+ GetClientRect(GetDlgItem(hwndDlg, IDC_LOG), &rc);
+ GetClientRect(GetDlgItem(hwndDlg, IDC_PROTOCOL), &rcButton);
+
+ if (dat->panelStatusCX == 0)
+ dat->panelStatusCX = 80;
+
+ s_offset = 1;
+
+ switch (urc->wId) {
+ case IDC_PANELSPLITTER:
+ urc->rcItem.bottom = panelHeight;
+ urc->rcItem.top = panelHeight - 2;
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP;
+ case IDC_LOG:
+ if (dat->dwFlags & MWF_ERRORSTATE)
+ urc->rcItem.bottom -= ERRORPANEL_HEIGHT;
+ if (dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED || dat->bNotOnList)
+ urc->rcItem.bottom -= 20;
+ if (dat->sendMode & SMODE_MULTIPLE)
+ urc->rcItem.right -= (dat->multiSplitterX + 3);
+ urc->rcItem.bottom -= dat->splitterY - dat->originalSplitterY;
+ if (!showToolbar||bBottomToolbar)
+ urc->rcItem.bottom += 21;
+ if (fInfoPanel)
+ urc->rcItem.top += panelHeight;
+ urc->rcItem.bottom += 3;
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item = &SkinItems[ID_EXTBKHISTORY];
+ if (!item->IGNORED) {
+ urc->rcItem.left += item->MARGIN_LEFT;
+ urc->rcItem.right -= item->MARGIN_RIGHT;
+ urc->rcItem.top += item->MARGIN_TOP;
+ urc->rcItem.bottom -= item->MARGIN_BOTTOM;
+ }
+ }
+ rcLogBottom = urc->rcItem.bottom;
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+ case IDC_CONTACTPIC:{
+ RECT rc;
+ GetClientRect(GetDlgItem(hwndDlg, IDC_MESSAGE), &rc);
+ urc->rcItem.top -= dat->splitterY - dat->originalSplitterY;
+ urc->rcItem.left = urc->rcItem.right - (dat->pic.cx + 2);
+ if ((urc->rcItem.bottom - urc->rcItem.top) < (dat->pic.cy/* + 2*/) && dat->showPic) {
+ urc->rcItem.top = urc->rcItem.bottom - dat->pic.cy;
+ dat->fMustOffset = TRUE;
+ } else
+ dat->fMustOffset = FALSE;
+
+ if(showToolbar && bBottomToolbar && (PluginConfig.m_AlwaysFullToolbarWidth || ((dat->pic.cy - DPISCALEY_S(6)) < rc.bottom))) {
+ urc->rcItem.bottom -= DPISCALEY_S(22);
+ if(dat->fIsAutosizingInput) {
+ urc->rcItem.left--;
+ urc->rcItem.top--;
+ }
+ }
+
+ //Bolshevik: resizes avatar control _FIXED
+ if( dat->hwndContactPic ) //if Panel control was created?
+ SetWindowPos(dat->hwndContactPic, HWND_TOP, 1, ((urc->rcItem.bottom-urc->rcItem.top)-(dat->pic.cy))/2+1, //resizes it
+ dat->pic.cx-2,
+ dat->pic.cy-2, SWP_SHOWWINDOW);
+ //Bolshevik_
+ if (PluginConfig.g_FlashAvatarAvail) {
+ RECT rc = { urc->rcItem.left, urc->rcItem.top, urc->rcItem.right, urc->rcItem.bottom };
+ FLASHAVATAR fa = {0};
+
+ fa.hContact = !fInfoPanel ? dat->hContact : NULL;
+ fa.id = 25367;
+ fa.cProto = dat->szProto;
+ CallService(MS_FAVATAR_RESIZE, (WPARAM)&fa, (LPARAM)&rc);
+ }
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM;
+ }
+ case IDC_SPLITTER:
+ urc->rcItem.right = urc->dlgNewSize.cx;
+ urc->rcItem.top -= dat->splitterY - dat->originalSplitterY;
+ urc->rcItem.bottom = urc->rcItem.top + 2;
+ OffsetRect(&urc->rcItem, 0, 1);
+ urc->rcItem.left = 0;
+
+ if (dat->fMustOffset)
+ urc->rcItem.right -= (dat->pic.cx); // + DPISCALEX(2));
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_BOTTOM;
+ case IDC_MESSAGE:
+ urc->rcItem.right = urc->dlgNewSize.cx;
+ if (dat->showPic)
+ urc->rcItem.right -= dat->pic.cx + 2;
+ urc->rcItem.top -= dat->splitterY - dat->originalSplitterY;
+ if (bBottomToolbar&&showToolbar)
+ urc->rcItem.bottom -= DPISCALEY_S(22);
+
+ if(dat->fIsAutosizingInput)
+ urc->rcItem.top -= DPISCALEY_S(1);
+
+ msgTop = urc->rcItem.top;
+ msgBottom = urc->rcItem.bottom;
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item = &SkinItems[ID_EXTBKINPUTAREA];
+ if (!item->IGNORED) {
+ urc->rcItem.left += item->MARGIN_LEFT;
+ urc->rcItem.right -= item->MARGIN_RIGHT;
+ urc->rcItem.top += item->MARGIN_TOP;
+ urc->rcItem.bottom -= item->MARGIN_BOTTOM;
+ }
+ }
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_BOTTOM;
+ case IDC_MULTISPLITTER:
+ if (fInfoPanel)
+ urc->rcItem.top += panelHeight;
+ urc->rcItem.left -= dat->multiSplitterX;
+ urc->rcItem.right -= dat->multiSplitterX;
+ urc->rcItem.bottom = rcLogBottom;
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_HEIGHT;
+ case IDC_LOGFROZENTEXT:
+ urc->rcItem.right = urc->dlgNewSize.cx - 50;
+ urc->rcItem.bottom = msgTop - (bBottomToolbar ? 0 : 28);
+ urc->rcItem.top = msgTop - 16 - (bBottomToolbar ? 0 : 28);
+ if (!showToolbar && !bBottomToolbar) {
+ urc->rcItem.bottom += 21;
+ urc->rcItem.top += 21;
+ }
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_BOTTOM;
+ case IDC_ADD:
+ urc->rcItem.bottom = msgTop - (bBottomToolbar ? 0 : 28);
+ urc->rcItem.top = msgTop - 18 - (bBottomToolbar ? 0 : 28);
+ urc->rcItem.right = urc->dlgNewSize.cx - 28;
+ urc->rcItem.left = urc->rcItem.right - 20;
+ if (!showToolbar && !bBottomToolbar) {
+ urc->rcItem.bottom += 21;
+ urc->rcItem.top += 21;
+ }
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_BOTTOM;
+ case IDC_CANCELADD:
+ urc->rcItem.bottom = msgTop - (bBottomToolbar ? 0 : 28);
+ urc->rcItem.top = msgTop - 18 - (bBottomToolbar ? 0 : 28);
+ urc->rcItem.right = urc->dlgNewSize.cx - 4;
+ urc->rcItem.left = urc->rcItem.right - 20;
+ if (!showToolbar && !bBottomToolbar) {
+ urc->rcItem.bottom += 21;
+ urc->rcItem.top += 21;
+ }
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_BOTTOM;
+ case IDC_TOGGLESIDEBAR:
+ return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM;
+ case IDC_RETRY:
+ case IDC_CANCELSEND:
+ case IDC_MSGSENDLATER:
+ if(fErrorState) {
+ urc->rcItem.bottom = msgTop - 5 - (bBottomToolbar ? 0 : 28) - ((dat->bNotOnList || dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED) ? 20 : 0);
+ urc->rcItem.top = msgTop - 25 - (bBottomToolbar ? 0 : 28) - ((dat->bNotOnList || dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED) ? 20 : 0);
+ }
+ if (!showToolbar && !bBottomToolbar) {
+ urc->rcItem.bottom += 21;
+ urc->rcItem.top += 21;
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM;
+ case IDC_STATICTEXT:
+ case IDC_STATICERRORICON:
+ if(fErrorState) {
+ urc->rcItem.bottom = msgTop - 28 - (bBottomToolbar ? 0 : 28) - ((dat->bNotOnList || dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED) ? 20 : 0);
+ urc->rcItem.top = msgTop - 45 - (bBottomToolbar ? 0 : 28) - ((dat->bNotOnList || dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED) ? 20 : 0);
+ }
+ if (!showToolbar && !bBottomToolbar) {
+ urc->rcItem.bottom += 21;
+ urc->rcItem.top += 21;
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM;
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM;
+}
+
+INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct TWindowData *dat = 0;
+ HWND hwndTab, hwndContainer;
+ struct TContainerData *m_pContainer = 0;
+
+ dat = (struct TWindowData *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ hwndTab = GetParent(hwndDlg);
+
+ if (dat == 0) {
+ if (msg == WM_ACTIVATE || msg == WM_SETFOCUS)
+ return 0;
+ } else {
+ m_pContainer = dat->pContainer;
+ hwndContainer = m_pContainer->hwnd;
+ }
+
+ switch (msg) {
+ case WM_INITDIALOG: {
+ RECT rc;
+ POINT pt;
+ int i;
+ BOOL isThemed = PluginConfig.m_bIsXP;
+ int dwLocalSmAdd = 0;
+ DBVARIANT dbv = {0};
+
+ struct TNewWindowData *newData = (struct TNewWindowData *) lParam;
+
+ dat = (struct TWindowData *) malloc(sizeof(struct TWindowData));
+ ZeroMemory((void *) dat, sizeof(struct TWindowData));
+ if (newData->iTabID >= 0) {
+ dat->pContainer = newData->pContainer;
+ m_pContainer = dat->pContainer;
+ hwndContainer = m_pContainer->hwnd;
+ }
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) dat);
+
+ if (Utils::rtf_ctable == 0)
+ Utils::RTF_CTableInit();
+
+ dat->dwFlags |= MWF_INITMODE;
+
+ dat->bType = SESSIONTYPE_IM;
+ dat->fInsertMode = FALSE;
+ dat->fLimitedUpdate = false;
+ dat->Panel = new CInfoPanel(dat);
+
+ newData->item.lParam = (LPARAM) hwndDlg;
+ TabCtrl_SetItem(hwndTab, newData->iTabID, &newData->item);
+ dat->iTabID = newData->iTabID;
+ dat->hwnd = hwndDlg;
+
+ DM_ThemeChanged(dat);
+
+ pszIDCSAVE_close = CTranslator::get(CTranslator::GEN_MSG_CLOSE);
+ pszIDCSAVE_save = CTranslator::get(CTranslator::GEN_MSG_SAVEANDCLOSE);
+
+ dat->hContact = newData->hContact;
+
+ dat->cache = CContactCache::getContactCache(dat->hContact);
+ dat->cache->updateState();
+ dat->cache->setWindowData(hwndDlg, dat);
+ M->AddWindow(hwndDlg, dat->hContact);
+ BroadCastContainer(m_pContainer, DM_REFRESHTABINDEX, 0, 0);
+ dat->pWnd = 0;
+ CProxyWindow::add(dat);
+ dat->szProto = const_cast<char *>(dat->cache->getProto());
+ dat->bIsMeta = dat->cache->isMeta() ? TRUE : FALSE;
+ if(dat->bIsMeta)
+ dat->cache->updateMeta(true);
+ dat->cache->updateUIN();
+
+ if (dat->hContact && dat->szProto != NULL) {
+ dat->wStatus = DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE);
+ mir_sntprintf(dat->szStatus, safe_sizeof(dat->szStatus), _T("%s"), (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, dat->szProto == NULL ? ID_STATUS_OFFLINE : dat->wStatus, GSMDF_TCHAR));
+ } else
+ dat->wStatus = ID_STATUS_OFFLINE;
+
+ GetMYUIN(dat);
+ GetClientIcon(dat);
+
+ CreateWindowEx(0, _T("TSButtonClass"), _T(""), WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0, 0, 6, DPISCALEY_S(20),
+ hwndDlg, (HMENU)IDC_TOGGLESIDEBAR, g_hInst, NULL);
+ dat->hwndPanelPicParent = CreateWindowEx(WS_EX_TOPMOST, _T("Static"), _T(""), SS_OWNERDRAW | WS_VISIBLE | WS_CHILD, 1, 1, 1, 1, hwndDlg, (HMENU)6000, NULL, NULL);
+ oldAvatarParentWndProc = (WNDPROC)SetWindowLongPtr(dat->hwndPanelPicParent, GWLP_WNDPROC, (INT_PTR)CInfoPanel::avatarParentSubclass);
+
+ dat->showUIElements = m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1;
+ dat->sendMode |= M->GetByte(dat->hContact, "forceansi", 0) ? SMODE_FORCEANSI : 0;
+ dat->sendMode |= dat->hContact == 0 ? SMODE_MULTIPLE : 0;
+ dat->sendMode |= M->GetByte(dat->hContact, "no_ack", 0) ? SMODE_NOACK : 0;
+
+ dat->hQueuedEvents = (HANDLE *)malloc(sizeof(HANDLE) * EVENT_QUEUE_SIZE);
+ dat->iEventQueueSize = EVENT_QUEUE_SIZE;
+ dat->iCurrentQueueError = -1;
+
+ /*
+ * message history limit
+ * hHistoryEvents holds up to n event handles
+ */
+
+ dat->maxHistory = M->GetDword(dat->hContact, "maxhist", M->GetDword("maxhist", 0));
+ dat->curHistory = 0;
+ if (dat->maxHistory)
+ dat->hHistoryEvents = (HANDLE *)malloc(dat->maxHistory * sizeof(HANDLE));
+ else
+ dat->hHistoryEvents = NULL;
+
+ if (dat->bIsMeta)
+ SendMessage(hwndDlg, DM_UPDATEMETACONTACTINFO, 0, 0);
+ else
+ SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0);
+ dat->bTabFlash = FALSE;
+ dat->mayFlashTab = FALSE;
+ GetMyNick(dat);
+
+ dat->multiSplitterX = (int) M->GetDword(SRMSGMOD, "multisplit", 150);
+ dat->nTypeMode = PROTOTYPE_SELFTYPING_OFF;
+ SetTimer(hwndDlg, TIMERID_TYPE, 1000, NULL);
+ dat->iLastEventType = 0xffffffff;
+
+
+ // load log option flags...
+ dat->dwFlags = dat->pContainer->theme.dwFlags;
+ /*
+ * consider per-contact message setting overrides
+ */
+
+ if (M->GetDword(dat->hContact, "mwmask", 0)) {
+ if (dat->hContact)
+ LoadLocalFlags(hwndDlg, dat);
+ }
+
+ /*
+ * allow disabling emoticons per contact (note: currently unused feature)
+ */
+
+ dwLocalSmAdd = (int)M->GetByte(dat->hContact, "doSmileys", 0xff);
+ if (dwLocalSmAdd != 0xffffffff)
+ dat->doSmileys = dwLocalSmAdd;
+
+ DM_InitTip(dat);
+ dat->Panel->getVisibility();
+
+ dat->dwFlagsEx |= M->GetByte(dat->hContact, "splitoverride", 0) ? MWF_SHOW_SPLITTEROVERRIDE : 0;
+ dat->fIsAutosizingInput = IsAutoSplitEnabled(dat);
+ dat->iInputAreaHeight = -1;
+ SetMessageLog(dat);
+ dat->panelWidth = -1;
+ if (dat->hContact) {
+ dat->codePage = M->GetDword(dat->hContact, "ANSIcodepage", CP_ACP);
+ dat->Panel->loadHeight();
+ }
+
+ dat->showPic = GetAvatarVisibility(hwndDlg, dat);
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_SMILEYBTN), &rc);
+
+ Utils::showDlgControl(hwndDlg, IDC_MULTISPLITTER, SW_HIDE);
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_SPLITTER), &rc);
+ pt.y = (rc.top + rc.bottom) / 2;
+ pt.x = 0;
+ ScreenToClient(hwndDlg, &pt);
+ dat->originalSplitterY = pt.y;
+ if (dat->splitterY == -1)
+ dat->splitterY = dat->originalSplitterY + 60;
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_MESSAGE), &rc);
+ dat->minEditBoxSize.cx = rc.right - rc.left;
+ dat->minEditBoxSize.cy = rc.bottom - rc.top;
+
+ BB_InitDlgButtons(dat);
+ SendMessage(hwndDlg, DM_LOADBUTTONBARICONS, 0, 0);
+
+ if (CSkin::m_skinEnabled && !SkinItems[ID_EXTBKBUTTONSNPRESSED].IGNORED &&
+ !SkinItems[ID_EXTBKBUTTONSPRESSED].IGNORED && !SkinItems[ID_EXTBKBUTTONSMOUSEOVER].IGNORED) {
+ isThemed = FALSE;
+ }
+
+ SendMessage(GetDlgItem(hwndDlg, IDC_ADD), BUTTONSETASFLATBTN, 0, 0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_CANCELADD), BUTTONSETASFLATBTN, 0, 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_TOGGLESIDEBAR, BUTTONSETASFLATBTN, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_TOGGLESIDEBAR, BUTTONSETASFLATBTN + 10, 0, isThemed ? 1 : 0);
+ SendDlgItemMessage(hwndDlg, IDC_TOGGLESIDEBAR, BUTTONSETASFLATBTN + 12, 0, (LPARAM)m_pContainer);
+ SendDlgItemMessage(hwndDlg, IDC_TOGGLESIDEBAR, BUTTONSETASTOOLBARBUTTON, 0, 1);
+
+ TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPENING, 0);
+
+ for (i = 0;;i++) {
+ if (tooltips[i].id == -1)
+ break;
+ SendDlgItemMessage(hwndDlg, tooltips[i].id, BUTTONADDTOOLTIP, (WPARAM)CTranslator::get(tooltips[i].translate_id), 0);
+ }
+ SetDlgItemText(hwndDlg, IDC_LOGFROZENTEXT, dat->bNotOnList ? CTranslator::get(CTranslator::GEN_MSG_CONTACT_NOT_ON_LIST) :
+ CTranslator::get(CTranslator::GEN_MSG_LOGFROZENSTATIC));
+
+ SendMessage(GetDlgItem(hwndDlg, IDC_SAVE), BUTTONADDTOOLTIP, (WPARAM)pszIDCSAVE_close, 0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_PROTOCOL), BUTTONADDTOOLTIP, (WPARAM) CTranslator::get(CTranslator::GEN_MSG_TIP_CONTACTMENU), 0);
+
+ SetWindowText(GetDlgItem(hwndDlg, IDC_RETRY), CTranslator::get(CTranslator::GEN_MSG_BUTTON_RETRY));
+
+ {
+ UINT _ctrls[] = {IDC_RETRY, IDC_CANCELSEND, IDC_MSGSENDLATER};
+ for(i = 0; i < 3; i++) {
+ SendDlgItemMessage(hwndDlg, _ctrls[i], BUTTONSETASPUSHBTN, 0, 0);
+ SendDlgItemMessage(hwndDlg, _ctrls[i], BUTTONSETASFLATBTN, 0, 1);
+ SendDlgItemMessage(hwndDlg, _ctrls[i], BUTTONSETASFLATBTN + 10, 0, 1);
+
+ }
+ }
+
+ SetWindowText(GetDlgItem(hwndDlg, IDC_CANCELSEND), CTranslator::get(CTranslator::GEN_MSG_BUTTON_CANCEL));
+ SetWindowText(GetDlgItem(hwndDlg, IDC_MSGSENDLATER), CTranslator::get(CTranslator::GEN_MSG_BUTTON_SENDLATER));
+
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETUNDOLIMIT, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_LINK);
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETEVENTMASK, 0, ENM_REQUESTRESIZE | ENM_MOUSEEVENTS | ENM_SCROLL | ENM_KEYEVENTS | ENM_CHANGE);
+#else
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_SCROLL | ENM_KEYEVENTS | ENM_CHANGE);
+#endif
+ dat->bActualHistory = M->GetByte(dat->hContact, "ActualHistory", 0);
+
+ /* OnO: higligh lines to their end */
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETEDITSTYLE, SES_EXTENDBACKCOLOR, SES_EXTENDBACKCOLOR);
+
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETLANGOPTIONS, 0, SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOFONTSIZEADJUST);
+
+ /*
+ * add us to the tray list (if it exists)
+ */
+
+ if (PluginConfig.g_hMenuTrayUnread != 0 && dat->hContact != 0 && dat->szProto != NULL)
+ UpdateTrayMenu(0, dat->wStatus, dat->szProto, dat->szStatus, dat->hContact, FALSE);
+
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_AUTOURLDETECT, (WPARAM) TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXLIMITTEXT, 0, 0x80000000);
+ /*
+ * subclassing stuff
+ */
+
+ OldMessageEditProc = (WNDPROC) SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWLP_WNDPROC, (LONG_PTR) MessageEditSubclassProc);
+ OldAvatarWndProc = (WNDPROC) SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CONTACTPIC), GWLP_WNDPROC, (LONG_PTR) AvatarSubclassProc);
+ OldSplitterProc = (WNDPROC) SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTER), GWLP_WNDPROC, (LONG_PTR) SplitterSubclassProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MULTISPLITTER), GWLP_WNDPROC, (LONG_PTR) SplitterSubclassProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PANELSPLITTER), GWLP_WNDPROC, (LONG_PTR) SplitterSubclassProc);
+
+ /*
+ * load old messages from history (if wanted...)
+ */
+
+ dat->cache->updateStats(TSessionStats::INIT_TIMER);
+ if (dat->hContact) {
+ FindFirstEvent(dat);
+ dat->nMax = dat->cache->getMaxMessageLength();
+ }
+ LoadContactAvatar(dat);
+ SendMessage(hwndDlg, DM_OPTIONSAPPLIED, 0, 0);
+ LoadOwnAvatar(dat);
+
+ /*
+ * restore saved msg if any...
+ */
+ if (dat->hContact) {
+ DBVARIANT dbv;
+ if (!DBGetContactSettingString(dat->hContact, SRMSGMOD, "SavedMsg", &dbv)) {
+ SETTEXTEX stx = {ST_DEFAULT, CP_UTF8};
+
+ if (dbv.type == DBVT_ASCIIZ && lstrlenA(dbv.pszVal) > 0)
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)dbv.pszVal);
+ DBFreeVariant(&dbv);
+ SendQueue::UpdateSaveAndSendButton(dat);
+ if (m_pContainer->hwndActive == hwndDlg)
+ UpdateReadChars(dat);
+ }
+ }
+ if (newData->szInitialText) {
+ int len;
+ if (newData->isWchar)
+ SetDlgItemTextW(hwndDlg, IDC_MESSAGE, (TCHAR *)newData->szInitialText);
+ else
+ SetDlgItemTextA(hwndDlg, IDC_MESSAGE, newData->szInitialText);
+ len = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ PostMessage(GetDlgItem(hwndDlg, IDC_MESSAGE), EM_SETSEL, len, len);
+ if (len)
+ EnableSendButton(dat, TRUE);
+ }
+ //dat->dwFlags &= ~MWF_INITMODE;
+ {
+ DBEVENTINFO dbei = { 0};
+ HANDLE hdbEvent;
+
+ dbei.cbSize = sizeof(dbei);
+ hdbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) dat->hContact, 0);
+ if (hdbEvent) {
+ do {
+ ZeroMemory(&dbei, sizeof(dbei));
+ dbei.cbSize = sizeof(dbei);
+ CallService(MS_DB_EVENT_GET, (WPARAM) hdbEvent, (LPARAM) & dbei);
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) {
+ dat->lastMessage = dbei.timestamp;
+ DM_UpdateLastMessage(dat);
+ break;
+ }
+ } while (hdbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDPREV, (WPARAM) hdbEvent, 0));
+ }
+
+ }
+ SendMessage(hwndContainer, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc);
+
+ {
+ WNDCLASSA wndClass;
+
+ ZeroMemory(&wndClass, sizeof(wndClass));
+ GetClassInfoA(g_hInst, "RichEdit20A", &wndClass);
+ OldMessageLogProc = wndClass.lpfnWndProc;
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWLP_WNDPROC, (LONG_PTR) MessageLogSubclassProc);
+ }
+ SetWindowPos(hwndDlg, 0, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), newData->iActivate ? 0 : SWP_NOZORDER | SWP_NOACTIVATE);
+ LoadSplitter(dat);
+ ShowPicture(dat, TRUE);
+
+ if (m_pContainer->dwFlags & CNT_CREATE_MINIMIZED || !newData->iActivate || m_pContainer->dwFlags & CNT_DEFERREDTABSELECT) {
+ DBEVENTINFO dbei = {0};
+
+ dbei.flags = 0;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dat->iFlashIcon = PluginConfig.g_IconMsgEvent;
+ SetTimer(hwndDlg, TIMERID_FLASHWND, TIMEOUT_FLASHWND, NULL);
+ dat->mayFlashTab = TRUE;
+ FlashOnClist(hwndDlg, dat, dat->hDbEventFirst, &dbei);
+ SendMessage(hwndContainer, DM_SETICON, (WPARAM)dat, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE));
+ m_pContainer->dwFlags |= CNT_NEED_UPDATETITLE;
+ dat->dwFlags |= (MWF_NEEDCHECKSIZE | MWF_WASBACKGROUNDCREATE);
+ dat->dwFlags |= MWF_DEFERREDSCROLL;
+ }
+ if (newData->iActivate) {
+ m_pContainer->hwndActive = hwndDlg;
+ ShowWindow(hwndDlg, SW_SHOW);
+ SetActiveWindow(hwndDlg);
+ SetForegroundWindow(hwndDlg);
+ //SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ PostMessage(hwndContainer, DM_UPDATETITLE, (WPARAM)dat->hContact, 0);
+ } else if (m_pContainer->dwFlags & CNT_CREATE_MINIMIZED) {
+ dat->dwFlags |= MWF_DEFERREDSCROLL;
+ ShowWindow(hwndDlg, SW_SHOWNOACTIVATE);
+ m_pContainer->hwndActive = hwndDlg;
+ m_pContainer->dwFlags |= CNT_DEFERREDCONFIGURE;
+ PostMessage(hwndContainer, DM_UPDATETITLE, (WPARAM)dat->hContact, 0);
+ }
+
+ DM_RecalcPictureSize(dat);
+ dat->dwLastActivity = GetTickCount() - 1000;
+ m_pContainer->dwLastActivity = dat->dwLastActivity;
+
+ if (dat->hwndHPP) {
+ WNDPROC wndProc = (WNDPROC)SetWindowLongPtr(dat->hwndHPP, GWLP_WNDPROC, (LONG_PTR)HPPKFSubclassProc);
+ dat->oldIEViewProc = wndProc;
+ }
+
+ dat->dwFlags &= ~MWF_INITMODE;
+ TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPEN, 0);
+
+ if(PluginConfig.g_bClientInStatusBar)
+ ChangeClientIconInStatusBar(dat);
+
+ /*
+ * show a popup if wanted...
+ */
+ if (newData->bWantPopup) {
+ DBEVENTINFO dbei = {0};
+ newData->bWantPopup = FALSE;
+ CallService(MS_DB_EVENT_GET, (WPARAM)newData->hdbEvent, (LPARAM)&dbei);
+ tabSRMM_ShowPopup((WPARAM)dat->hContact, (LPARAM)newData->hdbEvent, dbei.eventType, 0, 0, hwndDlg, dat->cache->getActiveProto(), dat);
+ }
+ if (m_pContainer->dwFlags & CNT_CREATE_MINIMIZED) {
+ m_pContainer->dwFlags &= ~CNT_CREATE_MINIMIZED;
+ m_pContainer->hwndActive = hwndDlg;
+ return FALSE;
+ }
+ return newData->iActivate ? TRUE : FALSE;
+ }
+ case WM_ERASEBKGND: {
+ HDC hdc = (HDC)wParam;
+
+ RECT rcClient, rcWindow, rc;
+ HDC hdcMem = 0;
+ HBITMAP hbm, hbmOld;
+ DWORD cx, cy;
+ HANDLE hpb = 0;
+
+ GetClientRect(hwndDlg, &rcClient);
+ cx = rcClient.right - rcClient.left;
+ cy = rcClient.bottom - rcClient.top;
+
+ if(CMimAPI::m_haveBufferedPaint)
+ hpb = CMimAPI::m_pfnBeginBufferedPaint(hdc, &rcClient, BPBF_TOPDOWNDIB, 0, &hdcMem);
+ else {
+ hdcMem = CreateCompatibleDC(hdc);
+ hbm = CSkin::CreateAeroCompatibleBitmap(rcClient, hdc);
+ hbmOld = (HBITMAP)SelectObject(hdcMem, hbm);
+ }
+
+ bool fInfoPanel = dat->Panel->isActive();
+ bool fAero = M->isAero();
+
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item;
+ POINT pt;
+ UINT item_ids[2] = {ID_EXTBKHISTORY, ID_EXTBKINPUTAREA};
+ UINT ctl_ids[2] = {IDC_LOG, IDC_MESSAGE};
+ int i;
+ BOOL isEditNotesReason = dat->fEditNotesActive;
+ BOOL isSendLaterReason = (dat->sendMode & SMODE_SENDLATER);
+ BOOL isMultipleReason = (dat->sendMode & SMODE_MULTIPLE || dat->sendMode & SMODE_CONTAINER);
+
+ CSkin::SkinDrawBG(hwndDlg, hwndContainer, m_pContainer, &rcClient, hdcMem);
+
+
+ for (i = 0; i < 2; i++) {
+ item = &SkinItems[item_ids[i]];
+ if (!item->IGNORED) {
+
+ GetWindowRect(GetDlgItem(hwndDlg, ctl_ids[i]), &rcWindow);
+ pt.x = rcWindow.left;
+ pt.y = rcWindow.top;
+ ScreenToClient(hwndDlg, &pt);
+ rc.left = pt.x - item->MARGIN_LEFT;
+ rc.top = pt.y - item->MARGIN_TOP;
+ rc.right = rc.left + item->MARGIN_RIGHT + (rcWindow.right - rcWindow.left) + item->MARGIN_LEFT;
+ rc.bottom = rc.top + item->MARGIN_BOTTOM + (rcWindow.bottom - rcWindow.top) + item->MARGIN_TOP;
+ if (item_ids[i] == ID_EXTBKINPUTAREA && (isMultipleReason || isEditNotesReason || isSendLaterReason)) {
+ HBRUSH br = CreateSolidBrush(isMultipleReason ? RGB(255, 130, 130) : (isEditNotesReason ? RGB(80, 255, 80) : RGB(80, 80, 255)));
+ FillRect(hdcMem, &rc, br);
+ DeleteObject(br);
+ }
+ else
+ CSkin::DrawItem(hdcMem, &rc, item);
+ }
+ }
+ }
+ else {
+ CSkin::FillBack(hdcMem, &rcClient);
+
+ if(M->isAero()) {
+ LONG temp = rcClient.bottom;
+ rcClient.bottom = dat->Panel->isActive() ? dat->Panel->getHeight() + 5 : 5;
+ FillRect(hdcMem, &rcClient, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ rcClient.bottom = temp;
+ }
+ }
+
+ /*
+ * draw the (new) infopanel background. Use the gradient from the statusitem.
+ */
+
+ GetClientRect(hwndDlg, &rc);
+ dat->Panel->renderBG(hdcMem, rc, &SkinItems[ID_EXTBKINFOPANELBG], fAero);
+
+ /*
+ * draw aero related stuff
+ */
+
+ if(!CSkin::m_skinEnabled)
+ CSkin::RenderToolbarBG(dat, hdcMem, rcClient);
+ /*
+ * render info panel fields
+ */
+ dat->Panel->renderContent(hdcMem);
+
+ if(hpb) {
+ CSkin::FinalizeBufferedPaint(hpb, &rcClient);
+ } else {
+ BitBlt(hdc, 0, 0, cx, cy, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hbmOld);
+ DeleteObject(hbm);
+ DeleteDC(hdcMem);
+ }
+ if(!dat->fLimitedUpdate)
+ SetAeroMargins(dat->pContainer);
+ return(1);
+ }
+ case WM_NCPAINT:
+ return 0;
+
+ case WM_PAINT: {
+ /*
+ * in skinned mode only, draw the background elements for the 2 richedit controls
+ * this allows border-less textboxes to appear "skinned" and blended with the
+ * background
+ */
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwndDlg, &ps);
+ EndPaint(hwndDlg, &ps);
+ return 0;
+ }
+
+ case WM_SIZE: {
+ UTILRESIZEDIALOG urd;
+ BITMAP bminfo;
+ RECT rc;
+ int saved = 0;
+ HBITMAP hbm = ((dat->Panel->isActive()) && m_pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown);
+
+ if (IsIconic(hwndDlg))
+ break;
+ ZeroMemory(&urd, sizeof(urd));
+ urd.cbSize = sizeof(urd);
+ urd.hInstance = g_hInst;
+ urd.hwndDlg = hwndDlg;
+ urd.lParam = (LPARAM) dat;
+ urd.lpTemplate = MAKEINTRESOURCEA(IDD_MSGSPLITNEW);
+ urd.pfnResizer = MessageDialogResize;
+
+ if (dat->ipFieldHeight == 0)
+ dat->ipFieldHeight = CInfoPanel::m_ipConfig.height2;
+
+ if (dat->pContainer->uChildMinHeight > 0 && HIWORD(lParam) >= dat->pContainer->uChildMinHeight) {
+ if (dat->splitterY > HIWORD(lParam) - DPISCALEY_S(MINLOGHEIGHT)) {
+ dat->splitterY = HIWORD(lParam) - DPISCALEY_S(MINLOGHEIGHT);
+ dat->dynaSplitter = dat->splitterY - DPISCALEY_S(34);
+ DM_RecalcPictureSize(dat);
+ }
+ if (dat->splitterY < DPISCALEY_S(MINSPLITTERY))
+ LoadSplitter(dat);
+ }
+
+ if (hbm != 0) {
+ GetObject(hbm, sizeof(bminfo), &bminfo);
+ CalcDynamicAvatarSize(dat, &bminfo);
+ }
+
+ GetClientRect(hwndDlg, &rc);
+ CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM) & urd);
+ BB_SetButtonsPos(dat);
+
+ /*
+ * size info panel fields
+ */
+
+ LONG cx = rc.right;
+ LONG panelHeight = dat->Panel->getHeight();
+ LONG panelWidth = (dat->panelWidth != -1 ? dat->panelWidth : 0);
+
+ rc.top = 1;
+ rc.left = cx - (panelWidth > 0 ? panelWidth : panelHeight);
+ rc.bottom = rc.top + (panelHeight - 3);
+ rc.right = cx;
+ rc.bottom--;
+
+ if (PluginConfig.g_FlashAvatarAvail) {
+ RECT rc1 = { 0, 0, rc.right - rc.left, rc.bottom - rc.top };
+ if (dat->Panel->isActive()) {
+ FLASHAVATAR fa = {0};
+
+ fa.hContact = dat->hContact;
+ fa.id = 25367;
+ fa.cProto = dat->szProto;
+ CallService(MS_FAVATAR_RESIZE, (WPARAM)&fa, (LPARAM)&rc1);
+ }
+ }
+ if(dat->showInfoPic && (dat->hwndPanelPic || dat->hwndFlash)) {
+ SetWindowPos(dat->hwndPanelPicParent, HWND_TOP, rc.left - 2, rc.top, rc.right - rc.left, (rc.bottom - rc.top) + 1, 0);
+ ShowWindow(dat->hwndPanelPicParent, (dat->panelWidth == -1) || !dat->Panel->isActive() ? SW_HIDE : SW_SHOW);
+ }
+ else if(dat->hwndPanelPicParent)
+ ShowWindow(dat->hwndPanelPicParent, SW_HIDE);
+
+ dat->rcPic = rc;
+
+ rc.right = cx - panelWidth;
+ rc.left = cx - panelWidth - dat->panelStatusCX;
+ rc.bottom = panelHeight - 3;
+ rc.top = rc.bottom - dat->ipFieldHeight;
+ dat->rcStatus = rc;
+
+ rc.left = CInfoPanel::LEFT_OFFSET_LOGO;
+ rc.right = cx - dat->panelWidth - (panelHeight < CInfoPanel::DEGRADE_THRESHOLD ? (dat->rcStatus.right - dat->rcStatus.left) + 3 : 0);
+ rc.bottom = panelHeight - (panelHeight >= CInfoPanel::DEGRADE_THRESHOLD ? dat->ipFieldHeight : 0) - 1;;
+ rc.top = 1;
+ dat->rcNick = rc;
+
+ rc.left = CInfoPanel::LEFT_OFFSET_LOGO;
+ rc.right = cx - (dat->panelWidth + 2) - dat->panelStatusCX;
+ rc.bottom = panelHeight - 3;
+ rc.top = rc.bottom - dat->ipFieldHeight;
+ dat->rcUIN = rc;
+
+ if (GetDlgItem(hwndDlg, IDC_CLIST) != 0) {
+ RECT rc, rcClient, rcLog;
+ GetClientRect(hwndDlg, &rcClient);
+ GetClientRect(GetDlgItem(hwndDlg, IDC_LOG), &rcLog);
+ rc.top = 0;
+ rc.right = rcClient.right;
+ rc.left = rcClient.right - dat->multiSplitterX;
+ rc.bottom = rcLog.bottom;
+ if (dat->Panel->isActive())
+ rc.top += (dat->Panel->getHeight() + 1);
+ MoveWindow(GetDlgItem(hwndDlg, IDC_CLIST), rc.left, rc.top, rc.right - rc.left, rcLog.bottom - rcLog.top, FALSE);
+ }
+
+ if (dat->hwndIEView || dat->hwndHPP)
+ ResizeIeView(dat, 0, 0, 0, 0);
+
+ dat->Panel->Invalidate();
+ DetermineMinHeight(dat);
+ break;
+ }
+
+ case WM_TIMECHANGE:
+ PostMessage(hwndDlg, DM_OPTIONSAPPLIED, 0, 0);
+ break;
+
+ case WM_NOTIFY:
+ if (dat != 0 && ((NMHDR *)lParam)->hwndFrom == dat->hwndTip) {
+ if (((NMHDR *)lParam)->code == NM_CLICK)
+ SendMessage(dat->hwndTip, TTM_TRACKACTIVATE, FALSE, 0);
+ break;
+ }
+ switch (((NMHDR *) lParam)->idFrom) {
+ case IDC_CLIST:
+ switch (((NMHDR *) lParam)->code) {
+ case CLN_OPTIONSCHANGED:
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETGREYOUTFLAGS, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETLEFTMARGIN, 2, 0);
+ break;
+ }
+ break;
+ case IDC_LOG:
+ case IDC_MESSAGE:
+ switch (((NMHDR *) lParam)->code) {
+ case EN_MSGFILTER: {
+ DWORD msg = ((MSGFILTER *) lParam)->msg;
+ WPARAM wp = ((MSGFILTER *) lParam)->wParam;
+ LPARAM lp = ((MSGFILTER *) lParam)->lParam;
+ CHARFORMAT2 cf2;
+ BOOL isCtrl, isShift, isAlt;
+ KbdState(dat, isShift, isCtrl, isAlt);
+
+ MSG message;
+ message.hwnd = hwndDlg;
+ message.message = msg;
+ message.lParam = lp;
+ message.wParam = wp;
+
+ if(msg == WM_SYSKEYUP) {
+ UINT ctrlId = 0;
+
+ if(wp == VK_MENU) {
+ if(!dat->fkeyProcessed && !(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000) && !(lp & (1 << 24)))
+ m_pContainer->MenuBar->autoShow();
+ }
+ return(_dlgReturn(hwndDlg, 0));
+ }
+
+ if ((msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) && !(GetKeyState(VK_RMENU) & 0x8000)) {
+ LRESULT mim_hotkey_check = CallService(MS_HOTKEY_CHECK, (WPARAM)&message, (LPARAM)(TABSRMM_HK_SECTION_IM));
+ if(mim_hotkey_check)
+ dat->fkeyProcessed = true;
+ switch(mim_hotkey_check) {
+ case TABSRMM_HK_SETUSERPREFS:
+ CallService(MS_TABMSG_SETUSERPREFS, (WPARAM)dat->hContact, 0);
+ return(_dlgReturn(hwndDlg, 1));
+ case TABSRMM_HK_NUDGE:
+ SendNudge(dat);
+ return(_dlgReturn(hwndDlg, 1));
+ case TABSRMM_HK_SENDFILE:
+ CallService(MS_FILE_SENDFILE, (WPARAM)dat->hContact, 0);
+ return(_dlgReturn(hwndDlg, 1));
+ case TABSRMM_HK_QUOTEMSG:
+ SendMessage(hwndDlg, WM_COMMAND, IDC_QUOTE, 0);
+ return(_dlgReturn(hwndDlg, 1));
+ case TABSRMM_HK_USERMENU:
+ SendMessage(hwndDlg, WM_COMMAND, IDC_PROTOCOL, 0);
+ return(_dlgReturn(hwndDlg, 1));
+ case TABSRMM_HK_USERDETAILS:
+ SendMessage(hwndDlg, WM_COMMAND, MAKELONG(IDC_NAME, BN_CLICKED), 0);
+ return(_dlgReturn(hwndDlg, 1));
+ case TABSRMM_HK_EDITNOTES:
+ PostMessage(hwndDlg, WM_COMMAND, MAKELONG(IDC_PIC, BN_CLICKED), 0);
+ return(_dlgReturn(hwndDlg, 1));
+ case TABSRMM_HK_TOGGLESENDLATER:
+ if(sendLater->isAvail()) {
+ dat->sendMode ^= SMODE_SENDLATER;
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER|
+ SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS);
+ RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_ALLCHILDREN);
+ }
+ else
+ CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK|MB_ICONINFORMATION, CTranslator::get(CTranslator::QMGR_ERROR_NOMULTISEND));
+ return(_dlgReturn(hwndDlg, 1));
+ case TABSRMM_HK_TOGGLERTL:
+ {
+ DWORD dwGlobal = M->GetDword("mwflags", MWF_LOG_DEFAULT);
+ DWORD dwOldFlags = dat->dwFlags;
+ DWORD dwMask = M->GetDword(dat->hContact, "mwmask", 0);
+ DWORD dwFlags = M->GetDword(dat->hContact, "mwflags", 0);
+
+ dat->dwFlags ^= MWF_LOG_RTL;
+ if((dwGlobal & MWF_LOG_RTL) != (dat->dwFlags & MWF_LOG_RTL)) {
+ dwMask |= MWF_LOG_RTL;
+ dwFlags |= (dat->dwFlags & MWF_LOG_RTL);
+ }
+ else {
+ dwMask &= ~MWF_LOG_RTL;
+ dwFlags &= ~MWF_LOG_RTL;
+ }
+ if(dwMask) {
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "mwmask", dwMask);
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "mwflags", dwFlags);
+ }
+ else {
+ DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "mwmask");
+ DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "mwflags");
+ }
+ SendMessage(hwndDlg, DM_OPTIONSAPPLIED, 0, 0);
+ SendMessage(hwndDlg, DM_DEFERREDREMAKELOG, (WPARAM)hwndDlg, 0);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ case TABSRMM_HK_TOGGLEMULTISEND:
+ {
+ HWND hwndEdit = GetDlgItem(hwndDlg, IDC_MESSAGE);
+
+ dat->sendMode ^= SMODE_MULTIPLE;
+ if (dat->sendMode & SMODE_MULTIPLE) {
+ HWND hwndClist = DM_CreateClist(dat);
+ } else {
+ if (IsWindow(GetDlgItem(hwndDlg, IDC_CLIST)))
+ DestroyWindow(GetDlgItem(hwndDlg, IDC_CLIST));
+ }
+ SetWindowPos(hwndEdit, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ RedrawWindow(hwndEdit, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW | RDW_ERASE);
+ DM_ScrollToBottom(dat, 0, 0);
+ Utils::showDlgControl(hwndDlg, IDC_MULTISPLITTER, (dat->sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE);
+ Utils::showDlgControl(hwndDlg, IDC_CLIST, (dat->sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE);
+ if (dat->sendMode & SMODE_MULTIPLE)
+ SetFocus(GetDlgItem(hwndDlg, IDC_CLIST));
+ else
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_ALLCHILDREN);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ default:
+ break;
+ }
+ if(DM_GenericHotkeysCheck(&message, dat)) {
+ dat->fkeyProcessed = true;
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ }
+ if (wp == VK_BROWSER_BACK || wp == VK_BROWSER_FORWARD)
+ return 1;
+
+ if (msg == WM_CHAR) {
+ if (isCtrl && !isShift && !isAlt) {
+ switch (wp) {
+ case 23: // ctrl - w
+ PostMessage(hwndDlg, WM_CLOSE, 1, 0);
+ break;
+ case 19:
+ PostMessage(hwndDlg, WM_COMMAND, IDC_SENDMENU, IDC_SENDMENU);
+ break;
+ case 16:
+ PostMessage(hwndDlg, WM_COMMAND, IDC_PROTOMENU, IDC_PROTOMENU);
+ break;
+ case 20:
+ PostMessage(hwndDlg, WM_COMMAND, IDC_TOGGLETOOLBAR, 1);
+ break;
+ }
+ return 1;
+ }
+ }
+ if (msg == WM_KEYDOWN) {
+ if ((wp == VK_INSERT && isShift && !isCtrl) || (wp == 'V' && isCtrl && !isShift && !isAlt)) {
+ SendMessage(GetDlgItem(hwndDlg, IDC_MESSAGE), EM_PASTESPECIAL, CF_TEXTT, 0);
+ _clrMsgFilter(lParam);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ if (isCtrl && isShift) {
+ if (wp == 0x9) { // ctrl-shift tab
+ SendMessage(hwndDlg, DM_SELECTTAB, DM_SELECT_PREV, 0);
+ _clrMsgFilter(lParam);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ }
+ if (isCtrl && !isShift && !isAlt) {
+ if (wp == VK_TAB) {
+ SendMessage(hwndDlg, DM_SELECTTAB, DM_SELECT_NEXT, 0);
+ _clrMsgFilter(lParam);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ if (wp == VK_F4) {
+ PostMessage(hwndDlg, WM_CLOSE, 1, 0);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ if (wp == VK_PRIOR) {
+ SendMessage(hwndDlg, DM_SELECTTAB, DM_SELECT_PREV, 0);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ if (wp == VK_NEXT) {
+ SendMessage(hwndDlg, DM_SELECTTAB, DM_SELECT_NEXT, 0);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ }
+ }
+ if (msg == WM_SYSKEYDOWN && isAlt) {
+ if(wp == 0x52) {
+ SendMessage(hwndDlg, DM_QUERYPENDING, DM_QUERY_MOSTRECENT, 0);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ if (wp == VK_MULTIPLY) {
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ if (wp == VK_DIVIDE) {
+ SetFocus(GetDlgItem(hwndDlg, IDC_LOG));
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ if (wp == VK_ADD) {
+ SendMessage(hwndContainer, DM_SELECTTAB, DM_SELECT_NEXT, 0);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ if (wp == VK_SUBTRACT) {
+ SendMessage(hwndContainer, DM_SELECTTAB, DM_SELECT_PREV, 0);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ }
+
+ if (msg == WM_KEYDOWN && wp == VK_F12) {
+ if (isShift || isCtrl || isAlt)
+ return(_dlgReturn(hwndDlg, 1));
+ if (dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED)
+ SendMessage(hwndDlg, DM_REPLAYQUEUE, 0, 0);
+ dat->dwFlagsEx ^= MWF_SHOW_SCROLLINGDISABLED;
+ Utils::showDlgControl(hwndDlg, IDC_LOGFROZENTEXT, (dat->bNotOnList || dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED) ? SW_SHOW : SW_HIDE);
+ if(!(dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED))
+ SetDlgItemText(hwndDlg, IDC_LOGFROZENTEXT, CTranslator::get(CTranslator::GEN_MSG_CONTACT_NOT_ON_LIST));
+ else
+ SetDlgItemText(hwndDlg, IDC_LOGFROZENTEXT, CTranslator::get(CTranslator::GEN_MSG_LOGFROZENSTATIC));
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ DM_ScrollToBottom(dat, 1, 1);
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ //MAD: tabulation mod
+ if(msg == WM_KEYDOWN && wp == VK_TAB) {
+ if(PluginConfig.m_AllowTab) {
+ if(((NMHDR *)lParam)->idFrom == IDC_MESSAGE)
+ SendMessage(GetDlgItem(hwndDlg, IDC_MESSAGE), EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\t");
+ _clrMsgFilter(lParam);
+ if(((NMHDR *)lParam)->idFrom != IDC_MESSAGE)
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ else {
+ if(((NMHDR *)lParam)->idFrom == IDC_MESSAGE) {
+ if(GetSendButtonState(hwndDlg) != PBS_DISABLED && !(dat->pContainer->dwFlags & CNT_HIDETOOLBAR)) {
+ SetFocus(GetDlgItem(hwndDlg, IDOK));
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ else {
+ SetFocus(GetDlgItem(hwndDlg, IDC_LOG));
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ }
+ if(((NMHDR *)lParam)->idFrom == IDC_LOG) {
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ return(_dlgReturn(hwndDlg, 1));
+ }
+ }
+ return(_dlgReturn(hwndDlg, 0));
+ }
+ //MAD_
+ if (msg == WM_MOUSEWHEEL && (((NMHDR *)lParam)->idFrom == IDC_LOG || ((NMHDR *)lParam)->idFrom == IDC_MESSAGE)) {
+ RECT rc;
+ POINT pt;
+
+ GetCursorPos(&pt);
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_LOG), &rc);
+ if (PtInRect(&rc, pt)) {
+ short wDirection = (short)HIWORD(wp);
+ if (LOWORD(wp) & MK_SHIFT) {
+ if (wDirection < 0)
+ SendMessage(GetDlgItem(hwndDlg, IDC_LOG), WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), 0);
+ else if (wDirection > 0)
+ SendMessage(GetDlgItem(hwndDlg, IDC_LOG), WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), 0);
+ return 0;
+ }
+ return 0;
+ }
+ return 1;
+ }
+
+ if (msg == WM_CHAR && wp == 'c') {
+ if (isCtrl) {
+ SendDlgItemMessage(hwndDlg, ((NMHDR *)lParam)->code, WM_COPY, 0, 0);
+ break;
+ }
+ }
+ if ((msg == WM_LBUTTONDOWN || msg == WM_KEYUP || msg == WM_LBUTTONUP) && ((NMHDR *)lParam)->idFrom == IDC_MESSAGE) {
+ int bBold = IsDlgButtonChecked(hwndDlg, IDC_FONTBOLD);
+ int bItalic = IsDlgButtonChecked(hwndDlg, IDC_FONTITALIC);
+ int bUnder = IsDlgButtonChecked(hwndDlg, IDC_FONTUNDERLINE);
+ //MAD
+ int bStrikeout = IsDlgButtonChecked(hwndDlg, IDC_FONTSTRIKEOUT);
+ //
+ cf2.cbSize = sizeof(CHARFORMAT2);
+ cf2.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_UNDERLINETYPE | CFM_STRIKEOUT;
+ cf2.dwEffects = 0;
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
+ if (cf2.dwEffects & CFE_BOLD) {
+ if (bBold == BST_UNCHECKED)
+ CheckDlgButton(hwndDlg, IDC_FONTBOLD, BST_CHECKED);
+ } else {
+ if (bBold == BST_CHECKED)
+ CheckDlgButton(hwndDlg, IDC_FONTBOLD, BST_UNCHECKED);
+ }
+
+ if (cf2.dwEffects & CFE_ITALIC) {
+ if (bItalic == BST_UNCHECKED)
+ CheckDlgButton(hwndDlg, IDC_FONTITALIC, BST_CHECKED);
+ } else {
+ if (bItalic == BST_CHECKED)
+ CheckDlgButton(hwndDlg, IDC_FONTITALIC, BST_UNCHECKED);
+ }
+
+ if (cf2.dwEffects & CFE_UNDERLINE && (cf2.bUnderlineType & CFU_UNDERLINE || cf2.bUnderlineType & CFU_UNDERLINEWORD)) {
+ if (bUnder == BST_UNCHECKED)
+ CheckDlgButton(hwndDlg, IDC_FONTUNDERLINE, BST_CHECKED);
+ } else {
+ if (bUnder == BST_CHECKED)
+ CheckDlgButton(hwndDlg, IDC_FONTUNDERLINE, BST_UNCHECKED);
+ }
+ if (cf2.dwEffects & CFE_STRIKEOUT) {
+ if (bStrikeout == BST_UNCHECKED)
+ CheckDlgButton(hwndDlg, IDC_FONTSTRIKEOUT, BST_CHECKED);
+ } else {
+ if (bStrikeout == BST_CHECKED)
+ CheckDlgButton(hwndDlg, IDC_FONTSTRIKEOUT, BST_UNCHECKED);
+ }
+ }
+ switch (msg) {
+ case WM_LBUTTONDOWN: {
+ HCURSOR hCur = GetCursor();
+ m_pContainer->MenuBar->Cancel();
+ if (hCur == LoadCursor(NULL, IDC_SIZENS) || hCur == LoadCursor(NULL, IDC_SIZEWE)
+ || hCur == LoadCursor(NULL, IDC_SIZENESW) || hCur == LoadCursor(NULL, IDC_SIZENWSE)) {
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ /*
+ * auto-select-and-copy handling...
+ * if enabled, releasing the lmb with an active selection automatically copies the selection
+ * to the clipboard.
+ * holding ctrl while releasing the button pastes the selection to the input area, using plain text
+ * holding ctrl-alt does the same, but pastes formatted text
+ */
+ case WM_LBUTTONUP:
+ if (((NMHDR *) lParam)->idFrom == IDC_LOG) {
+ CHARRANGE cr;
+ SendMessage(GetDlgItem(hwndDlg, IDC_LOG), EM_EXGETSEL, 0, (LPARAM)&cr);
+ if (cr.cpMax != cr.cpMin) {
+ cr.cpMin = cr.cpMax;
+ if (isCtrl && M->GetByte("autocopy", 0)) {
+ SETTEXTEX stx = {ST_KEEPUNDO | ST_SELECTION, CP_UTF8};
+ char *streamOut = NULL;
+ if (isAlt)
+ streamOut = Message_GetFromStream(GetDlgItem(hwndDlg, IDC_LOG), dat, (CP_UTF8 << 16) | (SF_RTFNOOBJS | SFF_PLAINRTF | SFF_SELECTION | SF_USECODEPAGE));
+ else
+ streamOut = Message_GetFromStream(GetDlgItem(hwndDlg, IDC_LOG), dat, (CP_UTF8 << 16) | (SF_TEXT | SFF_SELECTION | SF_USECODEPAGE));
+ if (streamOut) {
+ Utils::FilterEventMarkers(streamOut);
+ SendMessage(GetDlgItem(hwndDlg, IDC_MESSAGE), EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)streamOut);
+ free(streamOut);
+ }
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ } else if (M->GetByte("autocopy", 0) && !isShift) {
+ SendMessage(GetDlgItem(hwndDlg, IDC_LOG), WM_COPY, 0, 0);
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ if (m_pContainer->hwndStatus)
+ SendMessage(m_pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)CTranslator::get(CTranslator::GEN_MSG_SEL_COPIED));
+ }
+ }
+ }
+ break;
+ case WM_MOUSEMOVE: {
+ POINT pt;
+ HCURSOR hCur = GetCursor();
+ GetCursorPos(&pt);
+ DM_DismissTip(dat, pt);
+ dat->Panel->trackMouse(pt);
+ if (hCur == LoadCursor(NULL, IDC_SIZENS) || hCur == LoadCursor(NULL, IDC_SIZEWE)
+ || hCur == LoadCursor(NULL, IDC_SIZENESW) || hCur == LoadCursor(NULL, IDC_SIZENWSE))
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+
+ break;
+ }
+ }
+ break;
+ }
+
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ case EN_REQUESTRESIZE: {
+ REQRESIZE *rr = (REQRESIZE *)lParam;
+ DM_HandleAutoSizeRequest(dat, rr);
+ break;
+ }
+#endif
+ case EN_LINK:
+ switch (((ENLINK *) lParam)->msg) {
+ case WM_SETCURSOR:
+ SetCursor(PluginConfig.hCurHyperlinkHand);
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+ return TRUE;
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP: {
+ TEXTRANGEA tr;
+ CHARRANGE sel;
+
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXGETSEL, 0, (LPARAM) & sel);
+ if (sel.cpMin != sel.cpMax)
+ break;
+ tr.chrg = ((ENLINK *) lParam)->chrg;
+ tr.lpstrText = (char *)mir_alloc(tr.chrg.cpMax - tr.chrg.cpMin + 8);
+ SendDlgItemMessageA(hwndDlg, IDC_LOG, EM_GETTEXTRANGE, 0, (LPARAM) & tr);
+ if (strchr(tr.lpstrText, '@') != NULL && strchr(tr.lpstrText, ':') == NULL && strchr(tr.lpstrText, '/') == NULL) {
+ MoveMemory(tr.lpstrText + 7, tr.lpstrText, tr.chrg.cpMax - tr.chrg.cpMin + 1);
+ CopyMemory(tr.lpstrText, _T("mailto:"), 7);
+ }
+ if (IsStringValidLinkA(tr.lpstrText)) {
+ if (((ENLINK *) lParam)->msg == WM_RBUTTONDOWN) {
+ HMENU hMenu, hSubMenu;
+ POINT pt;
+
+ hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT));
+ hSubMenu = GetSubMenu(hMenu, 1);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hSubMenu, 0);
+ pt.x = (short) LOWORD(((ENLINK *) lParam)->lParam);
+ pt.y = (short) HIWORD(((ENLINK *) lParam)->lParam);
+ ClientToScreen(((NMHDR *) lParam)->hwndFrom, &pt);
+ switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL)) {
+ case IDM_OPENNEW:
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM) tr.lpstrText);
+ break;
+ case IDM_OPENEXISTING:
+ CallService(MS_UTILS_OPENURL, 0, (LPARAM) tr.lpstrText);
+ break;
+ case IDM_COPYLINK: {
+ HGLOBAL hData;
+ if (!OpenClipboard(hwndDlg))
+ break;
+ EmptyClipboard();
+ hData = GlobalAlloc(GMEM_MOVEABLE, lstrlenA(tr.lpstrText) + 1);
+ lstrcpyA((char *)GlobalLock(hData), tr.lpstrText);
+ GlobalUnlock(hData);
+ SetClipboardData(CF_TEXT, hData);
+ CloseClipboard();
+ break;
+ }
+ }
+ mir_free(tr.lpstrText);
+ DestroyMenu(hMenu);
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+ return TRUE;
+ } else {
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM) tr.lpstrText);
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ }
+ }
+ mir_free(tr.lpstrText);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case DM_TYPING: {
+ int preTyping = dat->nTypeSecs != 0;
+ dat->nTypeSecs = (int) lParam > 0 ? (int) lParam : 0;
+
+ if(dat->nTypeSecs)
+ dat->showTyping = 0;
+
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, preTyping);
+ return TRUE;
+ }
+ case DM_UPDATEWINICON: {
+ HWND t_hwnd;
+ const char* szProto = dat->cache->getActiveProto();
+ WORD wStatus = dat->cache->getActiveStatus();
+
+ t_hwnd = m_pContainer->hwnd;
+
+ if (dat->hXStatusIcon) {
+ DestroyIcon(dat->hXStatusIcon);
+ dat->hXStatusIcon = 0;
+ }
+
+ if (szProto) {
+ dat->hTabIcon = dat->hTabStatusIcon = MY_GetContactIcon(dat);
+ if (M->GetByte("use_xicons", 1))
+ dat->hXStatusIcon = GetXStatusIcon(dat);
+ SendDlgItemMessage(hwndDlg, IDC_PROTOCOL, BUTTONSETASFLATBTN + 11, 0, dat->dwFlagsEx & MWF_SHOW_ISIDLE ? 1 : 0);
+ SendDlgItemMessage(hwndDlg, IDC_PROTOCOL, BM_SETIMAGE, IMAGE_ICON, (LPARAM)(dat->hXStatusIcon ? dat->hXStatusIcon : dat->hTabIcon));
+
+ if (m_pContainer->hwndActive == hwndDlg)
+ SendMessage(t_hwnd, DM_SETICON, (WPARAM)dat, (LPARAM)(dat->hXStatusIcon ? dat->hXStatusIcon : dat->hTabIcon));
+
+ if(dat->pWnd)
+ dat->pWnd->updateIcon(dat->hXStatusIcon ? dat->hXStatusIcon : dat->hTabIcon);
+ }
+ return 0;
+ }
+ /*
+ * configures the toolbar only... if lParam != 0, then it also calls
+ * SetDialogToType() to reconfigure the message window
+ */
+
+ case DM_CONFIGURETOOLBAR:
+ dat->showUIElements = m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1;
+
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTER), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTER), GWL_EXSTYLE) & ~WS_EX_STATICEDGE);
+
+ if (lParam == 1) {
+ GetSendFormat(dat, 1);
+ SetDialogToType(hwndDlg);
+ }
+
+ if (lParam == 1) {
+ DM_RecalcPictureSize(dat);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ DM_ScrollToBottom(dat, 0, 1);
+ }
+ return 0;
+ case DM_LOADBUTTONBARICONS: {
+ int i;
+ for (i = 0;;i++) {
+ if (buttonicons[i].id == -1)
+ break;
+ SendDlgItemMessage(hwndDlg, buttonicons[i].id, BM_SETIMAGE, IMAGE_ICON, (LPARAM)*buttonicons[i].pIcon);
+ SendDlgItemMessage(hwndDlg, buttonicons[i].id, BUTTONSETASFLATBTN + 12, 0, (LPARAM)m_pContainer);
+ }
+ BB_UpdateIcons(hwndDlg, dat);
+ SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0);
+ return 0;
+ }
+ case DM_OPTIONSAPPLIED:
+ DM_OptionsApplied(dat, wParam, lParam);
+ return(0);
+ case DM_UPDATETITLE: {
+ DM_UpdateTitle(dat, wParam, lParam);
+ return(0);
+ }
+
+ case DM_UPDATESTATUSMSG:
+ dat->Panel->Invalidate();
+ return 0;
+ case DM_OWNNICKCHANGED:
+ GetMyNick(dat);
+ return 0;
+ case DM_ADDDIVIDER:
+ if (!(dat->dwFlags & MWF_DIVIDERSET) && PluginConfig.m_UseDividers) {
+ if (GetWindowTextLengthA(GetDlgItem(hwndDlg, IDC_LOG)) > 0) {
+ dat->dwFlags |= MWF_DIVIDERWANTED;
+ dat->dwFlags |= MWF_DIVIDERSET;
+ }
+ }
+ return 0;
+
+ case WM_SETFOCUS:
+ if (PluginConfig.g_FlashAvatarAvail) { // own avatar draw
+ FLASHAVATAR fa = { 0 };
+ fa.cProto = dat->szProto;
+ fa.id = 25367;
+
+ CallService(MS_FAVATAR_GETINFO, (WPARAM)&fa, 0);
+ if (fa.hWindow) {
+ if (dat->Panel->isActive()) {
+ SetParent(fa.hWindow, GetDlgItem(hwndDlg, IDC_CONTACTPIC));
+ ShowWindow(fa.hWindow, SW_SHOW);
+ } else {
+ ShowWindow(fa.hWindow, SW_HIDE);
+ }
+ }
+ }
+ MsgWindowUpdateState(dat, WM_SETFOCUS);
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ return 1;
+
+ case WM_ACTIVATE:
+ if (LOWORD(wParam) != WA_ACTIVE) {
+ //m_pContainer->hwndSaved = 0;
+ break;
+ }
+ //fall through
+ case WM_MOUSEACTIVATE:
+ MsgWindowUpdateState(dat, WM_ACTIVATE);
+ return 1;
+
+ case DM_UPDATEPICLAYOUT:
+ LoadContactAvatar(dat);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ return 0;
+
+ case DM_SPLITTERGLOBALEVENT: {
+ DM_SplitterGlobalEvent(dat, wParam, lParam);
+ return(0);
+ }
+
+ case DM_SPLITTERMOVED: {
+ POINT pt;
+ RECT rc;
+
+ if ((HWND) lParam == GetDlgItem(hwndDlg, IDC_MULTISPLITTER)) {
+ int oldSplitterX;
+ GetClientRect(hwndDlg, &rc);
+ pt.x = wParam;
+ pt.y = 0;
+ ScreenToClient(hwndDlg, &pt);
+ oldSplitterX = dat->multiSplitterX;
+ dat->multiSplitterX = rc.right - pt.x;
+ if (dat->multiSplitterX < 25)
+ dat->multiSplitterX = 25;
+
+ if (dat->multiSplitterX > ((rc.right - rc.left) - 80))
+ dat->multiSplitterX = oldSplitterX;
+ SendMessage(dat->hwnd, WM_SIZE, 0, 0);
+ } else if ((HWND) lParam == GetDlgItem(hwndDlg, IDC_SPLITTER)) {
+ int oldSplitterY, oldDynaSplitter;
+ int bottomtoolbarH=0;
+ GetClientRect(hwndDlg, &rc);
+ rc.top += (dat->Panel->isActive() ? dat->Panel->getHeight() + 40 : 30);
+ pt.x = 0;
+ pt.y = wParam;
+ ScreenToClient(hwndDlg, &pt);
+
+ oldSplitterY = dat->splitterY;
+ oldDynaSplitter = dat->dynaSplitter;
+
+ dat->splitterY = rc.bottom - pt.y +DPISCALEY_S(23);
+ /*
+ * attempt to fix splitter troubles..
+ * hardcoded limits... better solution is possible, but this works for now
+ */
+ //mad
+ if(dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR)
+ bottomtoolbarH = 22;
+ //
+ if (dat->splitterY < (DPISCALEY_S(MINSPLITTERY) + 5 + bottomtoolbarH)) { // min splitter size
+ dat->splitterY = (DPISCALEY_S(MINSPLITTERY) + 5 + bottomtoolbarH);
+ dat->dynaSplitter = dat->splitterY - DPISCALEY_S(34);
+ DM_RecalcPictureSize(dat);
+ }
+ else if (dat->splitterY > (rc.bottom - rc.top)) {
+ dat->splitterY = oldSplitterY;
+ dat->dynaSplitter = oldDynaSplitter;
+ DM_RecalcPictureSize(dat);
+ }
+ else {
+ dat->dynaSplitter = (rc.bottom - pt.y) - DPISCALEY_S(11);
+ DM_RecalcPictureSize(dat);
+ }
+ CSkin::UpdateToolbarBG(dat);
+ SendMessage(dat->hwnd, WM_SIZE, 0, 0);
+ } else if ((HWND) lParam == GetDlgItem(hwndDlg, IDC_PANELSPLITTER)) {
+ RECT rc;
+ POINT pt;
+
+ GetClientRect(GetDlgItem(hwndDlg, IDC_LOG), &rc);
+ pt.x = 0;
+ pt.y = wParam;
+ ScreenToClient(hwndDlg, &pt);
+ if ((pt.y + 2 >= MIN_PANELHEIGHT + 2) && (pt.y + 2 < 100) && (pt.y + 2 < rc.bottom - 30))
+ dat->Panel->setHeight(pt.y + 2, true);
+ dat->panelWidth = -1;
+ //SetAeroMargins(dat->pContainer);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
+ if(M->isAero())
+ InvalidateRect(GetParent(hwndDlg), NULL, FALSE);
+ break;
+ }
+ return 0;
+ }
+ /*
+ * queue a dm_remakelog
+ * wParam = hwnd of the sender, so we can directly do a DM_REMAKELOG if the msg came
+ * from ourself. otherwise, the dm_remakelog will be deferred until next window
+ * activation (focus)
+ */
+ case DM_DEFERREDREMAKELOG:
+ if ((HWND) wParam == hwndDlg)
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ else {
+ if (M->GetByte(dat->hContact, "mwoverride", 0) == 0) {
+ dat->dwFlags &= ~(MWF_LOG_ALL);
+ dat->dwFlags |= (lParam & MWF_LOG_ALL);
+ dat->dwFlags |= MWF_DEFERREDREMAKELOG;
+ }
+ }
+ return 0;
+ case DM_FORCEDREMAKELOG:
+ if ((HWND) wParam == hwndDlg)
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ else {
+ dat->dwFlags &= ~(MWF_LOG_ALL);
+ dat->dwFlags |= (lParam & MWF_LOG_ALL);
+ dat->dwFlags |= MWF_DEFERREDREMAKELOG;
+ }
+ return 0;
+ case DM_REMAKELOG:
+ dat->szMicroLf[0] = 0;
+ dat->lastEventTime = 0;
+ dat->iLastEventType = -1;
+ StreamInEvents(hwndDlg, dat->hDbEventFirst, -1, 0, NULL);
+ return 0;
+ case DM_APPENDTOLOG:
+ StreamInEvents(hwndDlg, (HANDLE) wParam, 1, 1, NULL);
+ return 0;
+ /*
+ * replays queued events after the message log has been frozen for a while
+ */
+ case DM_REPLAYQUEUE: {
+ int i;
+
+ for (i = 0; i < dat->iNextQueuedEvent; i++) {
+ if (dat->hQueuedEvents[i] != 0)
+ StreamInEvents(hwndDlg, dat->hQueuedEvents[i], 1, 1, NULL);
+ }
+ dat->iNextQueuedEvent = 0;
+ SetDlgItemText(hwndDlg, IDC_LOGFROZENTEXT, dat->bNotOnList ? CTranslator::get(CTranslator::GEN_MSG_CONTACT_NOT_ON_LIST) :
+ CTranslator::get(CTranslator::GEN_MSG_LOGFROZENSTATIC));
+ return 0;
+ }
+ case DM_SCROLLIEVIEW: {
+ IEVIEWWINDOW iew = {0};
+
+ iew.cbSize = sizeof(IEVIEWWINDOW);
+ iew.iType = IEW_SCROLLBOTTOM;
+ if (dat->hwndIEView) {
+ iew.hwnd = dat->hwndIEView;
+ CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&iew);
+ } else if (dat->hwndHPP) {
+ iew.hwnd = dat->hwndHPP;
+ CallService(MS_HPP_EG_WINDOW, 0, (LPARAM)&iew);
+ }
+ return 0;
+ }
+ case DM_FORCESCROLL: {
+ SCROLLINFO *psi = (SCROLLINFO *)lParam;
+ POINT *ppt = (POINT *)wParam;
+
+ HWND hwnd = GetDlgItem(hwndDlg, IDC_LOG);
+ int len;
+
+ if (wParam == 0 && lParam == 0)
+ return(DM_ScrollToBottom(dat, 0, 1));
+
+ if (dat->hwndIEView == 0 && dat->hwndHPP == 0) {
+ len = GetWindowTextLengthA(GetDlgItem(hwndDlg, IDC_LOG));
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETSEL, len - 1, len - 1);
+ }
+
+ if (psi == NULL)
+ return(DM_ScrollToBottom(dat, 0, 0));
+
+ if ((UINT)psi->nPos >= (UINT)psi->nMax - psi->nPage - 5 || psi->nMax - psi->nMin - psi->nPage < 50)
+ DM_ScrollToBottom(dat, 0, 0);
+ else
+ SendMessage((dat->hwndIEView || dat->hwndHPP) ? (dat->hwndIEView ? dat->hwndIEView : dat->hwndHPP) : hwnd, EM_SETSCROLLPOS, 0, (LPARAM)ppt);
+
+ return 0;
+ }
+ /*
+ * this is called whenever a new event has been added to the database.
+ * this CAN be posted (some sanity checks required).
+ */
+ case HM_DBEVENTADDED:
+ if (!dat)
+ return 0;
+ if ((HANDLE)wParam != dat->hContact)
+ return 0;
+ if (dat->hContact == NULL)
+ return 0;
+ DM_EventAdded(dat, wParam, lParam);
+ return(0);
+ case WM_TIMER:
+ /*
+ * timer to control info panel hovering
+ */
+ if (wParam == TIMERID_AWAYMSG) {
+ POINT pt;
+
+ KillTimer(hwndDlg, wParam);
+ GetCursorPos(&pt);
+
+ if (wParam == TIMERID_AWAYMSG && dat->Panel->hitTest(pt) != CInfoPanel::HTNIRVANA)
+ SendMessage(hwndDlg, DM_ACTIVATETOOLTIP, 0, 0);
+ else
+ dat->dwFlagsEx &= ~MWF_SHOW_AWAYMSGTIMER;
+ break;
+ }
+ /*
+ * timer id for message timeouts is composed like:
+ * for single message sends: basevalue (TIMERID_MSGSEND) + send queue index
+ */
+ if (wParam >= TIMERID_MSGSEND) {
+ int iIndex = wParam - TIMERID_MSGSEND;
+
+ if (iIndex < SendQueue::NR_SENDJOBS) { // single sendjob timer
+ SendJob *job = sendQueue->getJobByIndex(iIndex);
+ KillTimer(hwndDlg, wParam);
+ mir_sntprintf(job->szErrorMsg, safe_sizeof(job->szErrorMsg), CTranslator::get(CTranslator::GEN_MSG_DELIVERYFAILURE),
+ CTranslator::get(CTranslator::GEN_MSG_SENDTIMEOUT));
+ job->iStatus = SendQueue::SQ_ERROR;
+ if (!nen_options.iNoSounds && !(m_pContainer->dwFlags & CNT_NOSOUND))
+ SkinPlaySound("SendError");
+ if (!(dat->dwFlags & MWF_ERRORSTATE))
+ sendQueue->handleError(dat, iIndex);
+ break;
+ }
+ } else if (wParam == TIMERID_FLASHWND) {
+ if (dat->mayFlashTab)
+ FlashTab(dat, hwndTab, dat->iTabID, &dat->bTabFlash, TRUE, dat->hTabIcon);
+ break;
+ } else if (wParam == TIMERID_TYPE) {
+ DM_Typing(dat);
+ break;
+ }
+ break;
+ case DM_ERRORDECIDED:
+ switch (wParam) {
+ case MSGERROR_CANCEL:
+ case MSGERROR_SENDLATER: {
+ int iNextFailed;
+
+ if (!(dat->dwFlags & MWF_ERRORSTATE))
+ break;
+
+ dat->cache->saveHistory(0, 0);
+ if (wParam == MSGERROR_SENDLATER)
+ sendQueue->doSendLater(dat->iCurrentQueueError, dat); // to be implemented at a later time
+ dat->iOpenJobs--;
+ sendQueue->dec();
+ if (dat->iCurrentQueueError >= 0 && dat->iCurrentQueueError < SendQueue::NR_SENDJOBS)
+ sendQueue->clearJob(dat->iCurrentQueueError);
+ dat->iCurrentQueueError = -1;
+ sendQueue->showErrorControls(dat, FALSE);
+ if (wParam != MSGERROR_CANCEL || (wParam == MSGERROR_CANCEL && lParam == 0))
+ SetDlgItemText(hwndDlg, IDC_MESSAGE, _T(""));
+ sendQueue->checkQueue(dat);
+ if ((iNextFailed = sendQueue->findNextFailed(dat)) >= 0)
+ sendQueue->handleError(dat, iNextFailed);
+ break;
+ }
+ case MSGERROR_RETRY: {
+ int resent = 0;;
+
+ if (!(dat->dwFlags & MWF_ERRORSTATE))
+ break;
+
+ dat->cache->saveHistory(0, 0);
+ if (dat->iCurrentQueueError >= 0 && dat->iCurrentQueueError < SendQueue::NR_SENDJOBS) {
+ SendJob *job = sendQueue->getJobByIndex(dat->iCurrentQueueError);
+
+ if (job->hSendId == 0 && job->hOwner == 0)
+ break;
+ job->hSendId = (HANDLE) CallContactService(job->hOwner,
+ SendQueue::MsgServiceName(job->hOwner, dat, job->dwFlags), (dat->sendMode & SMODE_FORCEANSI) ? (job->dwFlags & ~PREF_UNICODE) : job->dwFlags, (LPARAM) job->sendBuffer);
+ resent++;
+ }
+
+ if (resent) {
+ int iNextFailed;
+ SendJob *job = sendQueue->getJobByIndex(dat->iCurrentQueueError);
+
+ SetTimer(hwndDlg, TIMERID_MSGSEND + dat->iCurrentQueueError, PluginConfig.m_MsgTimeout, NULL);
+ job->iStatus = SendQueue::SQ_INPROGRESS;
+ dat->iCurrentQueueError = -1;
+ sendQueue->showErrorControls(dat, FALSE);
+ SetDlgItemText(hwndDlg, IDC_MESSAGE, _T(""));
+ sendQueue->checkQueue(dat);
+ if ((iNextFailed = sendQueue->findNextFailed(dat)) >= 0)
+ sendQueue->handleError(dat, iNextFailed);
+ }
+ }
+ break;
+ }
+ break;
+ case DM_SELECTTAB:
+ SendMessage(hwndContainer, DM_SELECTTAB, wParam, lParam); // pass the msg to our container
+ return 0;
+
+ case DM_SETLOCALE:
+ if (dat->dwFlags & MWF_WASBACKGROUNDCREATE)
+ break;
+ if (m_pContainer->hwndActive == hwndDlg && PluginConfig.m_AutoLocaleSupport && hwndContainer == GetForegroundWindow() && hwndContainer == GetActiveWindow()) {
+ if(lParam)
+ dat->hkl = (HKL)lParam;
+
+ if (dat->hkl)
+ ActivateKeyboardLayout(dat->hkl, 0);
+ }
+ return 0;
+ /*
+ * return timestamp (in ticks) of last recent message which has not been read yet.
+ * 0 if there is none
+ * lParam = pointer to a dword receiving the value.
+ */
+ case DM_QUERYLASTUNREAD: {
+ DWORD *pdw = (DWORD *)lParam;
+ if (pdw)
+ *pdw = dat->dwTickLastEvent;
+ return 0;
+ }
+ case DM_QUERYCONTAINER: {
+ struct TContainerData **pc = (struct TContainerData **) lParam;
+ if (pc)
+ *pc = m_pContainer;
+ return 0;
+ }
+
+ case DM_QUERYHCONTACT: {
+ HANDLE *phContact = (HANDLE *) lParam;
+ if (phContact)
+ *phContact = dat->hContact;
+ return 0;
+ }
+
+ case DM_UPDATELASTMESSAGE:
+ DM_UpdateLastMessage(dat);
+ return 0;
+
+ case DM_SAVESIZE: {
+ RECT rcClient;
+
+ if (dat->dwFlags & MWF_NEEDCHECKSIZE)
+ lParam = 0;
+
+ dat->dwFlags &= ~MWF_NEEDCHECKSIZE;
+ if (dat->dwFlags & MWF_WASBACKGROUNDCREATE) {
+ dat->dwFlags &= ~MWF_INITMODE;
+ if (dat->lastMessage)
+ DM_UpdateLastMessage(dat);
+ }
+ SendMessage(hwndContainer, DM_QUERYCLIENTAREA, 0, (LPARAM)&rcClient);
+ MoveWindow(hwndDlg, rcClient.left, rcClient.top, (rcClient.right - rcClient.left), (rcClient.bottom - rcClient.top), TRUE);
+ if (dat->dwFlags & MWF_WASBACKGROUNDCREATE) {
+ dat->dwFlags &= ~MWF_WASBACKGROUNDCREATE;
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ PostMessage(hwndDlg, DM_UPDATEPICLAYOUT, 0, 0);
+ if(PluginConfig.m_AutoLocaleSupport) {
+ if(dat->hkl == 0)
+ DM_LoadLocale(dat);
+ else
+ PostMessage(hwndDlg, DM_SETLOCALE, 0, 0);
+ }
+ if (dat->hwndIEView != 0)
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ if(dat->pContainer->dwFlags & CNT_SIDEBAR)
+ dat->pContainer->SideBar->Layout();
+ } else {
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ if (lParam == 0)
+ PostMessage(hwndDlg, DM_FORCESCROLL, 0, 0);
+ }
+ return 0;
+ }
+ case DM_CHECKSIZE:
+ dat->dwFlags |= MWF_NEEDCHECKSIZE;
+ return 0;
+ /*
+ * sent by the message input area hotkeys. just pass it to our container
+ */
+ case DM_QUERYPENDING:
+ SendMessage(hwndContainer, DM_QUERYPENDING, wParam, lParam);
+ return 0;
+
+ case WM_LBUTTONDOWN: {
+ POINT tmp; //+ Protogenes
+ POINTS cur; //+ Protogenes
+ GetCursorPos(&tmp); //+ Protogenes
+ cur.x = (SHORT)tmp.x; //+ Protogenes
+ cur.y = (SHORT)tmp.y; //+ Protogenes
+ if(!dat->Panel->isHovered())
+ SendMessage(hwndContainer, WM_NCLBUTTONDOWN, HTCAPTION, *((LPARAM*)(&cur))); //+ Protogenes
+ break;
+ }
+ case WM_LBUTTONUP: {
+ POINT tmp; //+ Protogenes
+ POINTS cur; //+ Protogenes
+ GetCursorPos(&tmp); //+ Protogenes
+ if(dat->Panel->isHovered())
+ dat->Panel->handleClick(tmp);
+ else {
+ cur.x = (SHORT)tmp.x; //+ Protogenes
+ cur.y = (SHORT)tmp.y; //+ Protogenes
+ SendMessage(hwndContainer, WM_NCLBUTTONUP, HTCAPTION, *((LPARAM*)(&cur))); //+ Protogenes
+ }
+ break;
+ }
+
+ case WM_RBUTTONUP: {
+ POINT pt;
+ int iSelection;
+ HMENU subMenu;
+ int isHandled;
+ RECT rcPicture, rcPanelNick = {0};
+ int menuID = 0;
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_CONTACTPIC), &rcPicture);
+ rcPanelNick.left = rcPanelNick.right - 30;
+ GetCursorPos(&pt);
+
+ if(dat->Panel->invokeConfigDialog(pt))
+ break;
+
+ if (PtInRect(&rcPicture, pt))
+ menuID = MENU_PICMENU;
+
+ if ((menuID == MENU_PICMENU && ((dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown) || dat->hOwnPic) && dat->showPic != 0)) {
+ int iSelection, isHandled;
+ HMENU submenu = 0;
+
+ submenu = GetSubMenu(m_pContainer->hMenuContext, menuID == MENU_PICMENU ? 1 : 11);
+ GetCursorPos(&pt);
+ MsgWindowUpdateMenu(dat, submenu, menuID);
+ iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL);
+ isHandled = MsgWindowMenuHandler(dat, iSelection, menuID);
+ break;
+ }
+ subMenu = GetSubMenu(m_pContainer->hMenuContext, 0);
+
+ MsgWindowUpdateMenu(dat, subMenu, MENU_TABCONTEXT);
+
+ iSelection = TrackPopupMenu(subMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL);
+ if (iSelection >= IDM_CONTAINERMENU) {
+ DBVARIANT dbv = {0};
+ char szIndex[10];
+ char *szKey = "TAB_ContainersW";
+
+ _snprintf(szIndex, 8, "%d", iSelection - IDM_CONTAINERMENU);
+ if (iSelection - IDM_CONTAINERMENU >= 0) {
+ if (!M->GetTString(NULL, szKey, szIndex, &dbv)) {
+ SendMessage(hwndDlg, DM_CONTAINERSELECTED, 0, (LPARAM)dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ break;
+ }
+ isHandled = MsgWindowMenuHandler(dat, iSelection, MENU_TABCONTEXT);
+ break;
+ }
+ case WM_MOUSEMOVE: {
+ POINT pt;
+ GetCursorPos(&pt);
+ DM_DismissTip(dat, pt);
+ dat->Panel->trackMouse(pt);
+ break;
+ }
+ case WM_MEASUREITEM: {
+ LPMEASUREITEMSTRUCT lpmi = (LPMEASUREITEMSTRUCT) lParam;
+ if(dat->Panel->isHovered()) {
+ lpmi->itemHeight = 0;
+ lpmi->itemWidth = 6;
+ return(TRUE);
+ }
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+ }
+
+ case WM_NCHITTEST:
+ SendMessage(hwndContainer, WM_NCHITTEST, wParam, lParam);
+ break;
+ case WM_DRAWITEM:
+ return MsgWindowDrawHandler(wParam, lParam, dat);
+ case WM_APPCOMMAND: {
+ DWORD cmd = GET_APPCOMMAND_LPARAM(lParam);
+ if (cmd == APPCOMMAND_BROWSER_BACKWARD || cmd == APPCOMMAND_BROWSER_FORWARD) {
+ SendMessage(hwndContainer, DM_SELECTTAB, cmd == APPCOMMAND_BROWSER_BACKWARD ? DM_SELECT_PREV : DM_SELECT_NEXT, 0);
+ return 1;
+ }
+ break;
+ }
+ case WM_COMMAND:
+
+ if (!dat)
+ break;
+ // custom button handling
+ if(LOWORD(wParam)>=MIN_CBUTTONID&&LOWORD(wParam)<=MAX_CBUTTONID) {
+ BB_CustomButtonClick(dat,LOWORD(wParam) ,GetDlgItem(hwndDlg,LOWORD(wParam)),0);
+ break;
+ }
+
+ switch (LOWORD(wParam)) {
+ case IDOK: {
+ if(dat->fEditNotesActive) {
+ SendMessage(hwndDlg, DM_ACTIVATETOOLTIP, IDC_PIC, (LPARAM)CTranslator::get(CTranslator::GEN_MSG_EDIT_NOTES_TIP));
+ return(0);
+ }
+ int bufSize = 0, memRequired = 0, flags = 0;
+ char *streamOut = NULL;
+ TCHAR *decoded = NULL, *converted = NULL;
+ FINDTEXTEXA fi = {0};
+ int final_sendformat = dat->SendFormat;
+ HWND hwndEdit = GetDlgItem(hwndDlg, IDC_MESSAGE);
+ PARAFORMAT2 pf2;
+
+ // don't parse text formatting when the message contains curly braces - these are used by the rtf syntax
+ // and the parser currently cannot handle them properly in the text - XXX needs to be fixed later.
+
+ ZeroMemory(&pf2, sizeof(PARAFORMAT2));
+ fi.chrg.cpMin = 0;
+ fi.chrg.cpMax = -1;
+ fi.lpstrText = "{";
+ final_sendformat = SendDlgItemMessageA(hwndDlg, IDC_MESSAGE, EM_FINDTEXTEX, FR_DOWN, (LPARAM) & fi) == -1 ? final_sendformat : 0;
+ fi.lpstrText = "}";
+ final_sendformat = SendDlgItemMessageA(hwndDlg, IDC_MESSAGE, EM_FINDTEXTEX, FR_DOWN, (LPARAM) & fi) == -1 ? final_sendformat : 0;
+
+ if (GetSendButtonState(hwndDlg) == PBS_DISABLED)
+ break;
+
+ streamOut = Message_GetFromStream(GetDlgItem(hwndDlg, IDC_MESSAGE), dat, final_sendformat ? 0 : (CP_UTF8 << 16) | (SF_TEXT | SF_USECODEPAGE));
+ if (streamOut != NULL) {
+ decoded = M->utf8_decodeW(streamOut);
+ if (decoded != NULL) {
+ char* utfResult = NULL;
+ if (final_sendformat)
+ DoRtfToTags(decoded, dat);
+ DoTrimMessage(decoded);
+ bufSize = WideCharToMultiByte(dat->codePage, 0, decoded, -1, dat->sendBuffer, 0, 0, 0);
+
+ if (!IsUtfSendAvailable(dat->hContact)) {
+ flags |= PREF_UNICODE;
+ memRequired = bufSize + ((lstrlenW(decoded) + 1) * sizeof(WCHAR));
+ } else {
+ flags |= PREF_UTF;
+ utfResult = M->utf8_encodeW(decoded);
+ memRequired = (int)(strlen(utfResult)) + 1;
+ }
+
+ /*
+ * try to detect RTL
+ */
+
+ SendMessage(hwndEdit, WM_SETREDRAW, FALSE, 0);
+ pf2.cbSize = sizeof(pf2);
+ pf2.dwMask = PFM_RTLPARA;
+ SendMessage(hwndEdit, EM_SETSEL, 0, -1);
+ SendMessage(hwndEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf2);
+ if (pf2.wEffects & PFE_RTLPARA)
+ if (SendQueue::RTL_Detect(decoded))
+ flags |= PREF_RTL;
+
+ SendMessage(hwndEdit, WM_SETREDRAW, TRUE, 0);
+ SendMessage(hwndEdit, EM_SETSEL, -1, -1);
+ InvalidateRect(hwndEdit, NULL, FALSE);
+
+ if (memRequired > dat->iSendBufferSize) {
+ dat->sendBuffer = (char *) realloc(dat->sendBuffer, memRequired);
+ dat->iSendBufferSize = memRequired;
+ }
+ if (utfResult) {
+ CopyMemory(dat->sendBuffer, utfResult, memRequired);
+ mir_free(utfResult);
+ } else {
+ WideCharToMultiByte(dat->codePage, 0, decoded, -1, dat->sendBuffer, bufSize, 0, 0);
+ if (flags & PREF_UNICODE)
+ CopyMemory(&dat->sendBuffer[bufSize], decoded, (lstrlenW(decoded) + 1) * sizeof(WCHAR));
+ }
+ mir_free(decoded);
+ }
+ free(streamOut);
+ }
+ if (memRequired == 0 || dat->sendBuffer[0] == 0)
+ break;
+
+ if (dat->sendMode & SMODE_CONTAINER && m_pContainer->hwndActive == hwndDlg && GetForegroundWindow() == hwndContainer) {
+ HWND contacthwnd;
+ TCITEM tci;
+ int tabCount = TabCtrl_GetItemCount(hwndTab), i;
+ char *szFromStream = NULL;
+
+ szFromStream = Message_GetFromStream(GetDlgItem(hwndDlg, IDC_MESSAGE), dat, dat->SendFormat ? 0 : (CP_UTF8 << 16) | (SF_TEXT | SF_USECODEPAGE));
+ ZeroMemory((void *)&tci, sizeof(tci));
+ tci.mask = TCIF_PARAM;
+
+ for (i = 0; i < tabCount; i++) {
+ TabCtrl_GetItem(hwndTab, i, &tci);
+ // get the contact from the tabs lparam which hopefully is the tabs hwnd so we can get its userdata.... hopefully
+ contacthwnd = (HWND)tci.lParam;
+ if (IsWindow(contacthwnd)) {
+ // if the contact hwnd is the current contact then ignore it and let the normal code deal with the msg
+ if (contacthwnd != hwndDlg) {
+ SETTEXTEX stx = {ST_DEFAULT, CP_UTF8};
+ // send the buffer to the contacts msg typing area
+ SendDlgItemMessage(contacthwnd, IDC_MESSAGE, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szFromStream);
+ SendMessage(contacthwnd, WM_COMMAND, IDOK, 0);
+ }
+ }
+ }
+ if (szFromStream)
+ free(szFromStream);
+ }
+// END /all /MOD
+ if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON) {
+ DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+ }
+ DeletePopupsForContact(dat->hContact, PU_REMOVE_ON_SEND);
+ if (M->GetByte("allow_sendhook", 0)) {
+ int result = TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CUSTOM, MAKELONG(flags, tabMSG_WINDOW_EVT_CUSTOM_BEFORESEND));
+ if (result)
+ return TRUE;
+ }
+ sendQueue->addTo(dat, memRequired, flags);
+ return TRUE;
+ }
+ case IDC_QUOTE: {
+ CHARRANGE sel;
+ TCHAR* szQuoted, *szText;
+ char* szFromStream = NULL;
+ HANDLE hDBEvent = 0;
+ int iCharsPerLine = M->GetDword("quoteLineLength", 64);
+ TCHAR *szConverted;
+ int iAlloced = 0;
+ unsigned int iSize = 0;
+ SETTEXTEX stx = {ST_SELECTION, 1200};
+
+ if (dat->hwndIEView || dat->hwndHPP) { // IEView quoting support..
+ TCHAR *selected = 0, *szQuoted = 0;
+ IEVIEWEVENT event;
+ ZeroMemory((void *)&event, sizeof(event));
+ event.cbSize = sizeof(IEVIEWEVENT);
+ event.hContact = dat->hContact;
+ event.dwFlags = 0;
+ event.iType = IEE_GET_SELECTION;
+
+ if (dat->hwndIEView) {
+ event.hwnd = dat->hwndIEView;
+ selected = (TCHAR *)CallService(MS_IEVIEW_EVENT, 0, (LPARAM) & event);
+ } else {
+ event.hwnd = dat->hwndHPP;
+ selected = (TCHAR *)CallService(MS_HPP_EG_EVENT, 0, (LPARAM) & event);
+ }
+
+ if (selected != NULL) {
+ szQuoted = QuoteText(selected, iCharsPerLine, 0);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szQuoted);
+ if (szQuoted)
+ free(szQuoted);
+ break;
+ } else {
+ hDBEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)dat->hContact, 0);
+ goto quote_from_last;
+ }
+ }
+ if (dat->hDbEventLast == NULL)
+ break;
+ else
+ hDBEvent = dat->hDbEventLast;
+quote_from_last:
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXGETSEL, 0, (LPARAM)&sel);
+ if (sel.cpMin == sel.cpMax) {
+ DBEVENTINFO dbei = {0};
+ int iDescr;
+
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDBEvent, 0);
+ szText = (TCHAR *)malloc((dbei.cbBlob + 1) * sizeof(TCHAR)); //URLs are made one char bigger for crlf
+ dbei.pBlob = (BYTE *)szText;
+ CallService(MS_DB_EVENT_GET, (WPARAM)hDBEvent, (LPARAM)&dbei);
+ iSize = (int)(strlen((char *)dbei.pBlob)) + 1;
+ if (dbei.flags & DBEF_UTF) {
+ szConverted = M->utf8_decodeW((char*)szText);
+ iAlloced = TRUE;
+ } else {
+ if (iSize != dbei.cbBlob)
+ szConverted = (TCHAR *) & dbei.pBlob[iSize];
+ else {
+ szConverted = (TCHAR *)malloc(sizeof(TCHAR) * iSize);
+ iAlloced = TRUE;
+ MultiByteToWideChar(CP_ACP, 0, (char *) dbei.pBlob, -1, szConverted, iSize);
+ }
+ }
+ if (dbei.eventType == EVENTTYPE_FILE) {
+ iDescr = lstrlenA((char *)(szText + sizeof(DWORD)));
+ MoveMemory(szText, szText + sizeof(DWORD), iDescr);
+ MoveMemory(szText + iDescr + 2, szText + sizeof(DWORD) + iDescr, dbei.cbBlob - iDescr - sizeof(DWORD) - 1);
+ szText[iDescr] = '\r';
+ szText[iDescr+1] = '\n';
+ szConverted = (TCHAR *)malloc(sizeof(TCHAR) * (1 + lstrlenA((char *)szText)));
+ MultiByteToWideChar(CP_ACP, 0, (char *) szText, -1, szConverted, 1 + lstrlenA((char *)szText));
+ iAlloced = TRUE;
+ }
+ szQuoted = QuoteText(szConverted, iCharsPerLine, 0);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szQuoted);
+ free(szText);
+ free(szQuoted);
+ if (iAlloced)
+ mir_free(szConverted);
+ } else {
+ wchar_t *converted = 0;
+ szFromStream = Message_GetFromStream(GetDlgItem(hwndDlg, IDC_LOG), dat, SF_TEXT | SF_USECODEPAGE | SFF_SELECTION);
+ converted = M->utf8_decodeW(szFromStream);
+ Utils::FilterEventMarkers(converted);
+ szQuoted = QuoteText(converted, iCharsPerLine, 0);
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szQuoted);
+ free(szQuoted);
+ mir_free(converted);
+ free(szFromStream);
+ }
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ break;
+ }
+
+ case IDC_ADD: {
+ ADDCONTACTSTRUCT acs = {0};
+
+ acs.handle = dat->hContact;
+ acs.handleType = HANDLE_CONTACT;
+ acs.szProto = 0;
+ CallService(MS_ADDCONTACT_SHOW, (WPARAM) hwndDlg, (LPARAM) & acs);
+ if (!M->GetByte(dat->hContact, "CList", "NotOnList", 0)) {
+ dat->bNotOnList = FALSE;
+ ShowMultipleControls(hwndDlg, addControls, 2, SW_HIDE);
+ if(!(dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED))
+ Utils::showDlgControl(hwndDlg, IDC_LOGFROZENTEXT, SW_HIDE);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ }
+ break;
+ }
+ case IDC_CANCELADD:
+ dat->bNotOnList = FALSE;
+ ShowMultipleControls(hwndDlg, addControls, 2, SW_HIDE);
+ if(!(dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED))
+ Utils::showDlgControl(hwndDlg, IDC_LOGFROZENTEXT, SW_HIDE);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ break;
+
+ case IDC_MESSAGE:
+ if (PluginConfig.m_MathModAvail && HIWORD(wParam) == EN_CHANGE)
+ MTH_updateMathWindow(dat);
+
+ if (HIWORD(wParam) == EN_CHANGE) {
+ if (m_pContainer->hwndActive == hwndDlg)
+ UpdateReadChars(dat);
+ dat->dwFlags |= MWF_NEEDHISTORYSAVE;
+ dat->dwLastActivity = GetTickCount();
+ m_pContainer->dwLastActivity = dat->dwLastActivity;
+ SendQueue::UpdateSaveAndSendButton(dat);
+ if (!(GetKeyState(VK_CONTROL) & 0x8000)) {
+ dat->nLastTyping = GetTickCount();
+ if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE))) {
+ if (dat->nTypeMode == PROTOTYPE_SELFTYPING_OFF) {
+ if (!(dat->dwFlags & MWF_INITMODE))
+ DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_ON);
+ }
+ } else {
+ if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON) {
+ DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+ }
+ }
+ }
+ }
+ break;
+ default:
+ Utils::CmdDispatcher(Utils::CMD_MSGDIALOG, hwndDlg, LOWORD(wParam), wParam, lParam, dat, m_pContainer);
+ break;
+ }
+ break;
+ case WM_CONTEXTMENU: {
+ //mad
+ DWORD idFrom=GetDlgCtrlID((HWND)wParam);
+
+ if(idFrom>=MIN_CBUTTONID&&idFrom<=MAX_CBUTTONID) {
+ BB_CustomButtonClick(dat,idFrom,(HWND) wParam,1);
+ break;
+ }
+ //
+ if ((HWND)wParam == GetDlgItem(hwndDlg,IDC_NAME/* IDC_PROTOCOL*/) && dat->hContact != 0) {
+ POINT pt;
+ HMENU hMC;
+
+ GetCursorPos(&pt);
+ hMC = BuildMCProtocolMenu(hwndDlg);
+ if (hMC) {
+ int iSelection = 0;
+ iSelection = TrackPopupMenu(hMC, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL);
+ if (iSelection < 1000 && iSelection >= 100) { // the "force" submenu...
+ if (iSelection == 999) { // un-force
+ if (CallService(MS_MC_UNFORCESENDCONTACT, (WPARAM)dat->hContact, 0) == 0)
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "tabSRMM_forced", -1);
+ else
+ _DebugPopup(dat->hContact, TranslateT("Unforce failed"));
+ } else {
+ if (CallService(MS_MC_FORCESENDCONTACTNUM, (WPARAM)dat->hContact, (LPARAM)(iSelection - 100)) == 0)
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "tabSRMM_forced", (DWORD)(iSelection - 100));
+ else
+ _DebugPopup(dat->hContact, TranslateT("The selected protocol cannot be forced at this time"));
+ }
+ } else if (iSelection >= 1000) { // the "default" menu...
+ CallService(MS_MC_SETDEFAULTCONTACTNUM, (WPARAM)dat->hContact, (LPARAM)(iSelection - 1000));
+ }
+ DestroyMenu(hMC);
+ InvalidateRect(GetParent(hwndDlg), NULL, FALSE);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ /*
+ * this is now *only* called from the global ME_PROTO_ACK handler (static int ProtoAck() in msgs.c)
+ * it receives:
+ * wParam = index of the sendjob in the queue in the low word, index of the found sendID in the high word
+ (normally 0, but if its a multisend job, then the sendjob may contain more than one hContact/hSendId
+ pairs.)
+ * lParam = the original ackdata
+ *
+ * the "per message window" ACK hook is gone, the global ack handler cares about all types of ack's (currently
+ * *_MESSAGE and *_AVATAR and dispatches them to the owner windows).
+ */
+ case HM_EVENTSENT:
+ sendQueue->ackMessage(dat, wParam, lParam);
+ return 0;
+
+ case DM_ACTIVATEME:
+ ActivateExistingTab(m_pContainer, hwndDlg);
+ return 0;
+ /*
+ * sent by the select container dialog box when a container was selected...
+ * lParam = (TCHAR *)selected name...
+ */
+ case DM_CONTAINERSELECTED: {
+ struct TContainerData *pNewContainer = 0;
+ TCHAR *szNewName = (TCHAR *)lParam;
+
+ if(!_tcscmp(szNewName, CTranslator::get(CTranslator::GEN_DEFAULT_CONTAINER_NAME)))
+ szNewName = CGlobals::m_default_container_name;
+
+ int iOldItems = TabCtrl_GetItemCount(hwndTab);
+ if (!_tcsncmp(m_pContainer->szName, szNewName, CONTAINER_NAMELEN))
+ break;
+ pNewContainer = FindContainerByName(szNewName);
+ if (pNewContainer == NULL)
+ pNewContainer = CreateContainer(szNewName, FALSE, dat->hContact);
+ M->WriteTString(dat->hContact, SRMSGMOD_T, "containerW", szNewName);
+ dat->fIsReattach = TRUE;
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_DOCREATETAB, (WPARAM)pNewContainer, (LPARAM)dat->hContact);
+ if (iOldItems > 1) // there were more than 1 tab, container is still valid
+ SendMessage(m_pContainer->hwndActive, WM_SIZE, 0, 0);
+ SetForegroundWindow(pNewContainer->hwnd);
+ SetActiveWindow(pNewContainer->hwnd);
+ break;
+ }
+
+ case DM_STATUSBARCHANGED:
+ UpdateStatusBar(dat);
+ return 0;
+
+ case DM_UINTOCLIPBOARD: {
+ Utils::CopyToClipBoard(const_cast<TCHAR *>(dat->cache->getUIN()), hwndDlg);
+ return 0;
+ }
+ /*
+ * broadcasted when GLOBAL info panel setting changes
+ */
+ case DM_SETINFOPANEL:
+ CInfoPanel::setPanelHandler(dat, wParam, lParam);
+ return(0);
+
+ /*
+ * show the balloon tooltip control.
+ * wParam == id of the "anchor" element, defaults to the panel status field (for away msg retrieval)
+ * lParam == new text to show
+ */
+
+ case DM_ACTIVATETOOLTIP: {
+ if (IsIconic(hwndContainer) || m_pContainer->hwndActive != hwndDlg)
+ break;
+
+ dat->Panel->showTip(wParam, lParam);
+ break;
+ }
+ case WM_NEXTDLGCTL:
+ if (dat->dwFlags & MWF_WASBACKGROUNDCREATE)
+ return 1;
+ break;
+ /*
+ * save the contents of the log as rtf file
+ */
+ case DM_SAVEMESSAGELOG:
+ DM_SaveLogAsRTF(dat);
+ return(0);
+
+ /*
+ * sent from the containers heartbeat timer
+ * wParam = inactivity timer in seconds
+ */
+ /*
+ case DM_CHECKAUTOCLOSE: {
+ if (GetWindowTextLengthA(GetDlgItem(hwndDlg, IDC_MESSAGE)) > 0)
+ break; // don't autoclose if message input area contains text
+ if (M->GetByte(dat->hContact, "NoAutoClose", 0))
+ break;
+ if (dat->dwTickLastEvent >= dat->dwLastActivity)
+ break; // don't autoclose if possibly unread message is waiting
+ if (((GetTickCount() - dat->dwLastActivity) / 1000) >= wParam) {
+ if (TabCtrl_GetItemCount(GetParent(hwndDlg)) > 1 || M->GetByte("autocloselast", 0))
+ SendMessage(hwndDlg, WM_CLOSE, 0, 1);
+ }
+ break;
+ }
+ */
+ case DM_CHECKAUTOHIDE:
+ DM_CheckAutoHide(dat, wParam, lParam);
+ return(0);
+
+ // metacontact support
+
+ case DM_UPDATEMETACONTACTINFO: { // update the icon in the statusbar for the "most online" protocol
+ DWORD isForced;
+ if ((isForced = M->GetDword(dat->hContact, "tabSRMM_forced", -1)) >= 0) {
+ char szTemp[64];
+ mir_snprintf(szTemp, sizeof(szTemp), "Status%d", isForced);
+ if (DBGetContactSettingWord(dat->hContact, PluginConfig.szMetaName, szTemp, 0) == ID_STATUS_OFFLINE) {
+ TCHAR szBuffer[200];
+ mir_sntprintf(szBuffer, 200, CTranslator::get(CTranslator::GEN_MSG_MC_OFFLINEPROTOCOL));
+ SendMessage(hwndDlg, DM_ACTIVATETOOLTIP, IDC_MESSAGE, (LPARAM)szBuffer);
+ }
+ }
+ SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0);
+ break;
+ }
+ case DM_IEVIEWOPTIONSCHANGED:
+ if (dat->hwndIEView)
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ break;
+ case DM_SMILEYOPTIONSCHANGED:
+ ConfigureSmileyButton(dat);
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ break;
+ case DM_PROTOAVATARCHANGED:
+ dat->ace = Utils::loadAvatarFromAVS(dat->hContact);
+ dat->panelWidth = -1; // force new size calculations
+ ShowPicture(dat, TRUE);
+ if (dat->Panel->isActive()) {
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ }
+ return 0;
+ case DM_MYAVATARCHANGED: {
+ const char *szProto = dat->cache->getActiveProto();
+
+ if (!strcmp((char *)wParam, szProto) && lstrlenA(szProto) == lstrlenA((char *)wParam))
+ LoadOwnAvatar(dat);
+ break;
+ }
+ case DM_GETWINDOWSTATE: {
+ UINT state = 0;
+
+ state |= MSG_WINDOW_STATE_EXISTS;
+ if (IsWindowVisible(hwndDlg))
+ state |= MSG_WINDOW_STATE_VISIBLE;
+ if (GetForegroundWindow() == hwndContainer)
+ state |= MSG_WINDOW_STATE_FOCUS;
+ if (IsIconic(hwndContainer))
+ state |= MSG_WINDOW_STATE_ICONIC;
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, state);
+ return TRUE;
+ }
+ case DM_CLIENTCHANGED: {
+ GetClientIcon(dat);
+ if (dat->hClientIcon && dat->Panel->isActive())
+ InvalidateRect(hwndDlg, NULL, TRUE);
+ if(PluginConfig.g_bClientInStatusBar)
+ ChangeClientIconInStatusBar(dat);
+ return 0;
+ }
+ case DM_UPDATEUIN:
+ if(dat->Panel->isActive())
+ dat->Panel->Invalidate();
+ if(dat->pContainer->dwFlags & CNT_UINSTATUSBAR)
+ UpdateStatusBar(dat);
+ return(0);
+
+ case DM_REMOVEPOPUPS:
+ DeletePopupsForContact(dat->hContact, (DWORD)wParam);
+ return 0;
+ case EM_THEMECHANGED:
+ DM_FreeTheme(dat);
+ return DM_ThemeChanged(dat);
+ case DM_PLAYINCOMINGSOUND:
+ if (!dat)
+ return 0;
+ PlayIncomingSound(dat);
+ return 0;
+ case DM_REFRESHTABINDEX:
+ dat->iTabID = GetTabIndexFromHWND(GetParent(hwndDlg), hwndDlg);
+ return 0;
+ case DM_STATUSICONCHANGE:
+ if (m_pContainer->hwndStatus) {
+ SendMessage(dat->pContainer->hwnd, WM_SIZE, 0, 0);
+ SendMessage(m_pContainer->hwndStatus, SB_SETTEXT, (WPARAM)(SBT_OWNERDRAW) | 2, (LPARAM)0);
+ InvalidateRect(m_pContainer->hwndStatus, NULL, TRUE);
+ }
+ return 0;
+//mad: bb-api
+ case DM_BBNEEDUPDATE:{
+ if(lParam)
+ CB_ChangeButton(hwndDlg,dat,(CustomButtonData*)lParam);
+ else
+ BB_InitDlgButtons(dat);
+
+ BB_SetButtonsPos(dat);
+ return 0;
+ }
+
+ case DM_CBDESTROY:{
+ if(lParam)
+ CB_DestroyButton(hwndDlg,dat,(DWORD)wParam,(DWORD)lParam);
+ else
+ CB_DestroyAllButtons(hwndDlg,dat);
+ return 0;
+ }
+ //
+ case WM_DROPFILES: {
+ BOOL not_sending = GetKeyState(VK_CONTROL) & 0x8000;
+ if (!not_sending) {
+ const char* szProto = dat->cache->getActiveProto();
+ int pcaps;
+
+ if (szProto == NULL)
+ break;
+
+ pcaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (!(pcaps & PF1_FILESEND))
+ break;
+ if (dat->wStatus == ID_STATUS_OFFLINE) {
+ pcaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0);
+ if (!(pcaps & PF4_OFFLINEFILES)) {
+ TCHAR szBuffer[256];
+
+ _sntprintf(szBuffer, safe_sizeof(szBuffer), CTranslator::get(CTranslator::GEN_MSG_OFFLINE_NO_FILE));
+ SendMessage(hwndDlg, DM_ACTIVATETOOLTIP, IDC_MESSAGE, (LPARAM)szBuffer);
+ break;
+ }
+ }
+ }
+ if (dat->hContact != NULL) {
+ if (CMimAPI::m_MimVersion >= PLUGIN_MAKE_VERSION(0, 9, 0, 0)) {
+
+ TCHAR szFilename[MAX_PATH];
+ HDROP hDrop = (HDROP)wParam;
+ int fileCount = DragQueryFile(hDrop, -1, NULL, 0), totalCount = 0, i;
+ TCHAR** ppFiles = NULL;
+ for (i = 0; i < fileCount; i++) {
+ DragQueryFile(hDrop, i, szFilename, SIZEOF(szFilename));
+ Utils::AddToFileList(&ppFiles, &totalCount, szFilename);
+ }
+
+ if (!not_sending) {
+ CallService(MS_FILE_SENDSPECIFICFILEST, (WPARAM)dat->hContact, (LPARAM)ppFiles);
+ } else {
+ if (ServiceExists(MS_HTTPSERVER_ADDFILENAME)) {
+ char *szHTTPText;
+ int i;
+
+ for (i = 0;i < totalCount;i++) {
+ char* szFileName = mir_t2a( ppFiles[i] );
+ char *szTemp = (char*)CallService(MS_HTTPSERVER_ADDFILENAME, (WPARAM)szFileName, 0);
+ mir_free( szFileName );
+ }
+ szHTTPText = "DEBUG";
+ SendDlgItemMessageA(hwndDlg, IDC_MESSAGE, EM_REPLACESEL, TRUE, (LPARAM)szHTTPText);
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ }
+ }
+ for (i = 0;ppFiles[i];i++) mir_free(ppFiles[i]);
+ mir_free(ppFiles);
+ }
+ else {
+ TCHAR szFilename[MAX_PATH];
+ HDROP hDrop = (HDROP)wParam;
+ int fileCount = DragQueryFile(hDrop, -1, NULL, 0), totalCount = 0, i;
+ char** ppFiles = NULL;
+ for (i = 0; i < fileCount; i++) {
+ DragQueryFile(hDrop, i, szFilename, SIZEOF(szFilename));
+ Utils::AddToFileList(&ppFiles, &totalCount, szFilename);
+ }
+
+ if (!not_sending) {
+ CallService(MS_FILE_SENDSPECIFICFILES, (WPARAM)dat->hContact, (LPARAM)ppFiles);
+ } else {
+ if (ServiceExists(MS_HTTPSERVER_ADDFILENAME)) {
+ char *szHTTPText;
+ int i;
+
+ for (i = 0;i < totalCount;i++) {
+ char* szFileName = ppFiles[i];
+ char *szTemp = (char*)CallService(MS_HTTPSERVER_ADDFILENAME, (WPARAM)szFileName, 0);
+ }
+ szHTTPText = "DEBUG";
+ SendDlgItemMessageA(hwndDlg, IDC_MESSAGE, EM_REPLACESEL, TRUE, (LPARAM)szHTTPText);
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+ }
+ }
+ for (i = 0;ppFiles[i];i++)
+ mir_free(ppFiles[i]);
+ mir_free(ppFiles);
+ }
+ }
+ }
+ return 0;
+
+ case DM_CHECKQUEUEFORCLOSE: {
+ int *uOpen = (int *)lParam;
+
+ if (uOpen)
+ *uOpen += dat->iOpenJobs;
+ return 0;
+ }
+
+ case WM_CLOSE: {
+ int iTabs, i;
+ TCITEM item = {0};
+ RECT rc;
+ TContainerData *pContainer = dat->pContainer;
+
+ // esc handles error controls if we are in error state (error controls visible)
+
+ if (wParam == 0 && lParam == 0 && dat->dwFlags & MWF_ERRORSTATE) {
+ SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_CANCEL, 0);
+ return TRUE;
+ }
+
+ if (wParam == 0 && lParam == 0) {
+ if(PluginConfig.m_EscapeCloses == 1) {
+ SendMessage(hwndContainer, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+ return(TRUE);
+ } else if(PluginConfig.m_HideOnClose && PluginConfig.m_EscapeCloses == 2) {
+ ShowWindow(hwndContainer, SW_HIDE);
+ return(TRUE);
+ }
+ _dlgReturn(hwndDlg, TRUE);
+ }
+
+ if (dat->iOpenJobs > 0 && lParam != 2) {
+ if (dat->dwFlags & MWF_ERRORSTATE)
+ SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_CANCEL, 1);
+ else if (dat) {
+ LRESULT result;
+
+ if (dat->dwFlagsEx & MWF_EX_WARNCLOSE)
+ return TRUE;
+
+ dat->dwFlagsEx |= MWF_EX_WARNCLOSE;
+ result = SendQueue::WarnPendingJobs(0);
+ dat->dwFlagsEx &= ~MWF_EX_WARNCLOSE;
+ if (result == IDNO)
+ return TRUE;
+ }
+ }
+ iTabs = TabCtrl_GetItemCount(hwndTab);
+ if (iTabs == 1) {
+ PostMessage(hwndContainer, WM_CLOSE, 0, 1);
+ return 1;
+ }
+
+ TStatusBarIconNode *current;
+
+ while (dat->pSINod) {
+ current = dat->pSINod;
+ dat->pSINod = dat->pSINod->next;
+
+ mir_free(current->sid.szModule);
+ DestroyIcon(current->sid.hIcon);
+ if (current->sid.hIconDisabled) DestroyIcon(current->sid.hIconDisabled);
+ if (current->sid.szTooltip) mir_free(current->sid.szTooltip);
+ mir_free(current);
+ }
+
+ m_pContainer->iChilds--;
+ i = GetTabIndexFromHWND(hwndTab, hwndDlg);
+
+ /*
+ * after closing a tab, we need to activate the tab to the left side of
+ * the previously open tab.
+ * normally, this tab has the same index after the deletion of the formerly active tab
+ * unless, of course, we closed the last (rightmost) tab.
+ */
+ if (!m_pContainer->bDontSmartClose && iTabs > 1 && lParam != 3) {
+ if (i == iTabs - 1)
+ i--;
+ else
+ i++;
+ TabCtrl_SetCurSel(hwndTab, i);
+ item.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, i, &item); // retrieve dialog hwnd for the now active tab...
+
+ m_pContainer->hwndActive = (HWND) item.lParam;
+ SendMessage(hwndContainer, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc);
+ SetWindowPos(m_pContainer->hwndActive, HWND_TOP, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), SWP_SHOWWINDOW);
+ ShowWindow((HWND)item.lParam, SW_SHOW);
+ SetForegroundWindow(m_pContainer->hwndActive);
+ SetFocus(m_pContainer->hwndActive);
+ SendMessage(hwndContainer, WM_SIZE, 0, 0);
+ }
+
+ DestroyWindow(hwndDlg);
+ if (iTabs == 1)
+ PostMessage(GetParent(GetParent(hwndDlg)), WM_CLOSE, 0, 1);
+ else
+ SendMessage(pContainer->hwnd, WM_SIZE, 0, 0);
+ break;
+ }
+ case WM_DESTROY:
+ if (PluginConfig.g_FlashAvatarAvail) {
+ FLASHAVATAR fa = {0};
+
+ fa.hContact = dat->hContact;
+ fa.id = 25367;
+ fa.cProto = dat->szProto;
+ CallService(MS_FAVATAR_DESTROY, (WPARAM)&fa, 0);
+ }
+
+ if(dat->hwndContactPic)
+ DestroyWindow(dat->hwndContactPic);
+
+ if(dat->hwndPanelPic)
+ DestroyWindow(dat->hwndPanelPic);
+
+ if(dat->hClientIcon)
+ DestroyIcon(dat->hClientIcon);
+
+ if(dat->hwndPanelPicParent) {
+ if(oldAvatarParentWndProc)
+ SetWindowLongPtr(dat->hwndPanelPicParent, GWLP_WNDPROC, (LONG_PTR)oldAvatarParentWndProc);
+ DestroyWindow(dat->hwndPanelPicParent);
+ }
+
+ if (dat->cache->isValid()) { // not valid means the contact was deleted
+ TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSING, 0);
+ AddContactToFavorites(dat->hContact, dat->cache->getNick(), dat->cache->getActiveProto(), dat->szStatus, dat->wStatus,
+ LoadSkinnedProtoIcon(dat->cache->getActiveProto(), dat->cache->getActiveStatus()), 1, PluginConfig.g_hMenuRecent);
+ if (dat->hContact) {
+
+ if(!dat->fEditNotesActive) {
+ char *msg = Message_GetFromStream(GetDlgItem(hwndDlg, IDC_MESSAGE), dat, (CP_UTF8 << 16) | (SF_TEXT | SF_USECODEPAGE));
+ if (msg) {
+ DBWriteContactSettingString(dat->hContact, SRMSGMOD, "SavedMsg", msg);
+ free(msg);
+ } else
+ DBWriteContactSettingString(dat->hContact, SRMSGMOD, "SavedMsg", "");
+ }
+ else
+ SendMessage(hwndDlg, WM_COMMAND, IDC_PIC, 0);
+ }
+ }
+
+ if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON)
+ DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+
+ DM_FreeTheme(dat);
+
+ if (dat->sendBuffer != NULL)
+ free(dat->sendBuffer);
+ if (dat->hHistoryEvents)
+ free(dat->hHistoryEvents);
+ {
+ int i;
+ /*
+ * search the sendqueue for unfinished send jobs and free them. Leave unsent
+ * messages in the queue as they can be acked later
+ */
+ SendJob *jobs = sendQueue->getJobByIndex(0);
+
+ for (i = 0; i < SendQueue::NR_SENDJOBS; i++) {
+ if (jobs[i].hOwner == dat->hContact) {
+ if (jobs[i].iStatus > (unsigned)SendQueue::SQ_INPROGRESS)
+ sendQueue->clearJob(i);
+ /*
+ * unfinished jobs which did not yet return anything are kept in the queue.
+ * the hwndOwner is set to 0 because the window handle is now no longer valid.
+ * Response for such a job is still silently handled by AckMessage() (sendqueue.c)
+ */
+ if (jobs[i].iStatus == (unsigned)SendQueue::SQ_INPROGRESS)
+ jobs[i].hwndOwner = 0;
+ }
+ }
+ if (dat->hQueuedEvents)
+ free(dat->hQueuedEvents);
+ }
+
+ if (dat->hSmileyIcon)
+ DestroyIcon(dat->hSmileyIcon);
+
+ if (dat->hXStatusIcon)
+ DestroyIcon(dat->hXStatusIcon);
+
+ if (dat->hwndTip)
+ DestroyWindow(dat->hwndTip);
+
+ if (dat->hTaskbarIcon)
+ DestroyIcon(dat->hTaskbarIcon);
+
+ UpdateTrayMenuState(dat, FALSE); // remove me from the tray menu (if still there)
+ if (PluginConfig.g_hMenuTrayUnread)
+ DeleteMenu(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)dat->hContact, MF_BYCOMMAND);
+ M->RemoveWindow(hwndDlg);
+
+ if (dat->cache->isValid()) {
+ M->WriteDword(SRMSGMOD, "multisplit", dat->multiSplitterX);
+ WriteStatsOnClose(dat);
+ }
+
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MULTISPLITTER), GWLP_WNDPROC, (LONG_PTR) OldSplitterProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PANELSPLITTER), GWLP_WNDPROC, (LONG_PTR) OldSplitterProc);
+
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTER), GWLP_WNDPROC, (LONG_PTR) OldSplitterProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CONTACTPIC), GWLP_WNDPROC, (LONG_PTR) OldAvatarWndProc);
+
+ {
+ HFONT hFont;
+ TCITEM item;
+ int i;
+
+ hFont = (HFONT) SendDlgItemMessage(hwndDlg, IDC_MESSAGE, WM_GETFONT, 0, 0);
+ if (hFont != NULL && hFont != (HFONT) SendDlgItemMessage(hwndDlg, IDOK, WM_GETFONT, 0, 0))
+ DeleteObject(hFont);
+
+ ZeroMemory((void *)&item, sizeof(item));
+ item.mask = TCIF_PARAM;
+
+ i = GetTabIndexFromHWND(hwndTab, hwndDlg);
+ if (i >= 0) {
+ SendMessage(hwndTab, WM_USER + 100, 0, 0); // remove tooltip
+ TabCtrl_DeleteItem(hwndTab, i);
+ BroadCastContainer(m_pContainer, DM_REFRESHTABINDEX, 0, 0);
+ dat->iTabID = -1;
+ }
+ }
+ TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSE, 0);
+
+ /*
+ * clean up IEView and H++ log windows
+ */
+
+ if (dat->hwndIEView != 0) {
+ IEVIEWWINDOW ieWindow;
+ ieWindow.cbSize = sizeof(IEVIEWWINDOW);
+ ieWindow.iType = IEW_DESTROY;
+ ieWindow.hwnd = dat->hwndIEView;
+ if (dat->oldIEViewProc) {
+ SetWindowLongPtr(dat->hwndIEView, GWLP_WNDPROC, (LONG_PTR)dat->oldIEViewProc);
+ dat->oldIEViewProc = 0;
+ }
+ CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
+ }
+ if (dat->hwndHPP) {
+ IEVIEWWINDOW ieWindow;
+ ieWindow.cbSize = sizeof(IEVIEWWINDOW);
+ ieWindow.iType = IEW_DESTROY;
+ ieWindow.hwnd = dat->hwndHPP;
+ if (dat->oldIEViewProc) {
+ SetWindowLongPtr(dat->hwndHPP, GWLP_WNDPROC, (LONG_PTR)dat->oldIEViewProc);
+ dat->oldIEViewProc = 0;
+ }
+ CallService(MS_HPP_EG_WINDOW, 0, (LPARAM)&ieWindow);
+ }
+ if(dat->pWnd) {
+ delete dat->pWnd;
+ dat->pWnd = 0;
+ }
+ break;
+ case WM_DWMCOMPOSITIONCHANGED:
+ BB_RefreshTheme(dat);
+ memset((void *)&dat->pContainer->mOld, -1000, sizeof(MARGINS));
+ CProxyWindow::verify(dat);
+ break;
+
+ case DM_FORCEREDRAW:
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW);
+ return(0);
+
+ case DM_CHECKINFOTIP:
+ dat->Panel->hideTip(reinterpret_cast<HWND>(lParam));
+ return(0);
+
+ case WM_NCDESTROY:
+ if (dat) {
+ memset((void *)&dat->pContainer->mOld, -1000, sizeof(MARGINS));
+ PostMessage(dat->pContainer->hwnd, WM_SIZE, 0, 1);
+ if(m_pContainer->dwFlags & CNT_SIDEBAR)
+ m_pContainer->SideBar->removeSession(dat);
+ dat->cache->setWindowData();
+ if (dat->cache->isValid() && !dat->fIsReattach && dat->hContact && M->GetByte("deletetemp", 0)) {
+ if (M->GetByte(dat->hContact, "CList", "NotOnList", 0)) {
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM)dat->hContact, 0);
+ }
+ }
+ delete dat->Panel;
+ free(dat);
+ }
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+ break;
+ }
+ return FALSE;
+}
diff --git a/plugins/TabSRMM/src/msgdlgutils.cpp b/plugins/TabSRMM/src/msgdlgutils.cpp
new file mode 100644
index 0000000000..caefdcffc3
--- /dev/null
+++ b/plugins/TabSRMM/src/msgdlgutils.cpp
@@ -0,0 +1,2555 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: msgdlgutils.cpp 13650 2011-05-30 11:53:13Z silvercircle@gmail.com $
+ *
+ * Helper functions for the message dialog.
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+//#include "m_MathModule.h"
+
+extern NEN_OPTIONS nen_options;
+extern LOGFONTA logfonts[MSGDLGFONTCOUNT + 2];
+extern COLORREF fontcolors[MSGDLGFONTCOUNT + 2];
+extern TTemplateSet LTR_Active, RTL_Active;
+
+#ifndef SHVIEW_THUMBNAIL
+#define SHVIEW_THUMBNAIL 0x702D
+#endif
+
+#define EVENTTYPE_NICKNAME_CHANGE 9001
+#define EVENTTYPE_STATUSMESSAGE_CHANGE 9002
+#define EVENTTYPE_AVATAR_CHANGE 9003
+#define EVENTTYPE_CONTACTLEFTCHANNEL 9004
+#define EVENTTYPE_WAT_ANSWER 9602
+#define EVENTTYPE_JABBER_CHATSTATES 2000
+#define EVENTTYPE_JABBER_PRESENCE 2001
+
+static int g_status_events[] = {
+ EVENTTYPE_STATUSCHANGE,
+ EVENTTYPE_CONTACTLEFTCHANNEL,
+ EVENTTYPE_WAT_ANSWER,
+ EVENTTYPE_JABBER_CHATSTATES,
+ EVENTTYPE_JABBER_PRESENCE
+};
+
+static int g_status_events_size = 0;
+#define MAX_REGS(_A_) ( sizeof(_A_) / sizeof(_A_[0]) )
+
+BOOL TSAPI IsStatusEvent(int eventType)
+{
+ int i;
+
+ if (g_status_events_size == 0)
+ g_status_events_size = MAX_REGS(g_status_events);
+
+ for (i = 0; i < g_status_events_size; i++) {
+ if (eventType == g_status_events[i])
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * reorder tabs within a container. fSavePos indicates whether the new position should be saved to the
+ * contacts db record (if so, the container will try to open the tab at the saved position later)
+ */
+
+void TSAPI RearrangeTab(HWND hwndDlg, const TWindowData *dat, int iMode, BOOL fSavePos)
+{
+ TCITEM item = {0};
+ HWND hwndTab = GetParent(hwndDlg);
+ int newIndex;
+ TCHAR oldText[512];
+ item.mask = TCIF_IMAGE | TCIF_TEXT | TCIF_PARAM;
+ item.pszText = oldText;
+ item.cchTextMax = 500;
+
+ if (dat == NULL || !IsWindow(hwndDlg))
+ return;
+
+ TabCtrl_GetItem(hwndTab, dat->iTabID, &item);
+ newIndex = LOWORD(iMode);
+
+ if (newIndex >= 0 && newIndex <= TabCtrl_GetItemCount(hwndTab)) {
+ TabCtrl_DeleteItem(hwndTab, dat->iTabID);
+ item.lParam = (LPARAM)hwndDlg;
+ TabCtrl_InsertItem(hwndTab, newIndex, &item);
+ BroadCastContainer(dat->pContainer, DM_REFRESHTABINDEX, 0, 0);
+ ActivateTabFromHWND(hwndTab, hwndDlg);
+ if (fSavePos)
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "tabindex", newIndex * 100);
+ }
+}
+
+/*
+ * subclassing for the save as file dialog (needed to set it to thumbnail view on Windows 2000
+ * or later
+ */
+
+static BOOL CALLBACK OpenFileSubclass(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG: {
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)lParam);
+ break;
+ }
+ case WM_NOTIFY: {
+ OPENFILENAMEA *ofn = (OPENFILENAMEA *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ HWND hwndParent = GetParent(hwnd);
+ HWND hwndLv = FindWindowEx(hwndParent, NULL, _T("SHELLDLL_DefView"), NULL) ;
+
+ if (hwndLv != NULL && *((DWORD *)(ofn->lCustData))) {
+ SendMessage(hwndLv, WM_COMMAND, SHVIEW_THUMBNAIL, 0);
+ *((DWORD *)(ofn->lCustData)) = 0;
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * saves a contact picture to disk
+ * takes hbm (bitmap handle) and bool isOwnPic (1 == save the picture as your own avatar)
+ * requires AVS and ADVAIMG services (Miranda 0.7+)
+ */
+
+static void SaveAvatarToFile(TWindowData *dat, HBITMAP hbm, int isOwnPic)
+{
+ TCHAR szFinalPath[MAX_PATH];
+ TCHAR szFinalFilename[MAX_PATH];
+ TCHAR szBaseName[MAX_PATH];
+ TCHAR szTimestamp[100];
+ OPENFILENAME ofn = {0};
+ time_t t = time(NULL);
+ struct tm *lt = localtime(&t);
+ DWORD setView = 1;
+
+ mir_sntprintf(szTimestamp, 100, _T("%04u %02u %02u_%02u%02u"), lt->tm_year + 1900, lt->tm_mon, lt->tm_mday, lt->tm_hour, lt->tm_min);
+
+ TCHAR *szProto = mir_a2t(dat->cache->getActiveProto());
+
+ mir_sntprintf(szFinalPath, MAX_PATH, _T("%s\\%s"), M->getSavedAvatarPath(), szProto);
+ mir_free(szProto);
+
+ if (CreateDirectory(szFinalPath, 0) == 0) {
+ if (GetLastError() != ERROR_ALREADY_EXISTS) {
+ MessageBox(0, CTranslator::get(CTranslator::GEN_MSG_SAVE_NODIR),
+ CTranslator::get(CTranslator::GEN_MSG_SAVE), MB_OK | MB_ICONSTOP);
+ return;
+ }
+ }
+ if (isOwnPic)
+ mir_sntprintf(szBaseName, MAX_PATH,_T("My Avatar_%s"), szTimestamp);
+ else
+ mir_sntprintf(szBaseName, MAX_PATH, _T("%s_%s"), dat->cache->getNick(), szTimestamp);
+
+ mir_sntprintf(szFinalFilename, MAX_PATH, _T("%s.png"), szBaseName);
+ ofn.lpstrDefExt = _T("png");
+
+ /*
+ * do not allow / or \ or % in the filename
+ */
+ Utils::sanitizeFilename(szFinalFilename);
+
+ TCHAR filter[MAX_PATH];
+ mir_sntprintf(filter, SIZEOF(filter), _T("%s%c*.bmp;*.png;*.jpg;*.gif%c%c"), TranslateT("Image files"), 0, 0, 0);
+ ofn.lpstrFilter = filter;
+ if (IsWinVer2000Plus()) {
+ ofn.Flags = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ENABLESIZING | OFN_ENABLEHOOK;
+ ofn.lpfnHook = (LPOFNHOOKPROC)OpenFileSubclass;
+ ofn.lStructSize = sizeof(ofn);
+ } else {
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.Flags = OFN_HIDEREADONLY;
+ }
+ ofn.hwndOwner = 0;
+ ofn.lpstrFile = szFinalFilename;
+ ofn.lpstrInitialDir = szFinalPath;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lCustData = (LPARAM) & setView;
+ if (GetSaveFileName(&ofn)) {
+ if (PathFileExists(szFinalFilename)) {
+ if (MessageBox(0, CTranslator::get(CTranslator::GEN_MSG_SAVE_FILE_EXISTS),
+ CTranslator::get(CTranslator::GEN_MSG_SAVE), MB_YESNO | MB_ICONQUESTION) == IDNO)
+ return;
+ }
+ IMGSRVC_INFO ii;
+ ii.cbSize = sizeof(ii);
+ ii.wszName = szFinalFilename;
+ ii.hbm = hbm;
+ ii.dwMask = IMGI_HBITMAP;
+ ii.fif = FIF_UNKNOWN; // get the format from the filename extension. png is default.
+ CallService(MS_IMG_SAVE, (WPARAM)&ii, IMGL_TCHAR);
+ }
+}
+
+/*
+ * flash a tab icon if mode = true, otherwise restore default icon
+ * store flashing state into bState
+ */
+
+void TSAPI FlashTab(struct TWindowData *dat, HWND hwndTab, int iTabindex, BOOL *bState, BOOL mode, HICON origImage)
+{
+ TCITEM item;
+
+ ZeroMemory((void *)&item, sizeof(item));
+ item.mask = TCIF_IMAGE;
+
+ if (mode)
+ *bState = !(*bState);
+ else
+ dat->hTabIcon = origImage;
+ item.iImage = 0;
+ TabCtrl_SetItem(hwndTab, iTabindex, &item);
+ if(dat->pContainer->dwFlags & CNT_SIDEBAR)
+ dat->pContainer->SideBar->updateSession(dat);
+}
+
+/*
+ * calculates avatar layouting, based on splitter position to find the optimal size
+ * for the avatar w/o disturbing the toolbar too much.
+ */
+
+void TSAPI CalcDynamicAvatarSize(TWindowData *dat, BITMAP *bminfo)
+{
+ RECT rc;
+ double aspect = 0, newWidth = 0, picAspect = 0;
+ double picProjectedWidth = 0;
+ BOOL bBottomToolBar=dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR;
+ BOOL bToolBar=dat->pContainer->dwFlags & CNT_HIDETOOLBAR?0:1;
+ bool fInfoPanel = dat->Panel->isActive();
+ int iSplitOffset = dat->fIsAutosizingInput ? 1 : 0;
+
+ if (PluginConfig.g_FlashAvatarAvail) {
+ FLASHAVATAR fa = {0};
+ fa.cProto = dat->szProto;
+ fa.id = 25367;
+ fa.hContact = fInfoPanel ? NULL : dat->hContact;
+ CallService(MS_FAVATAR_GETINFO, (WPARAM)&fa, 0);
+ if (fa.hWindow) {
+ bminfo->bmHeight = FAVATAR_HEIGHT;
+ bminfo->bmWidth = FAVATAR_WIDTH;
+ }
+ }
+ GetClientRect(dat->hwnd, &rc);
+
+ if (dat->dwFlags & MWF_WASBACKGROUNDCREATE || dat->pContainer->dwFlags & CNT_DEFERREDCONFIGURE || dat->pContainer->dwFlags & CNT_CREATE_MINIMIZED || IsIconic(dat->pContainer->hwnd))
+ return; // at this stage, the layout is not yet ready...
+
+ if (bminfo->bmWidth == 0 || bminfo->bmHeight == 0)
+ picAspect = 1.0;
+ else
+ picAspect = (double)(bminfo->bmWidth / (double)bminfo->bmHeight);
+ picProjectedWidth = (double)((dat->dynaSplitter-((bBottomToolBar && bToolBar)? DPISCALEX_S(24):0) + ((dat->showUIElements != 0) ? DPISCALEX_S(28) : DPISCALEX_S(2)))) * picAspect;
+
+ if ((rc.right - (int)picProjectedWidth) > (dat->iButtonBarReallyNeeds) && !PluginConfig.m_AlwaysFullToolbarWidth && bToolBar)
+ dat->iRealAvatarHeight = dat->dynaSplitter + 3 + (dat->showUIElements ? DPISCALEY_S(28):DPISCALEY_S(2));
+ else
+ dat->iRealAvatarHeight = dat->dynaSplitter + DPISCALEY_S(6) + DPISCALEY_S(iSplitOffset);
+
+ dat->iRealAvatarHeight-=((bBottomToolBar&&bToolBar) ? DPISCALEY_S(22) : 0);
+
+ if (PluginConfig.m_LimitStaticAvatarHeight > 0)
+ dat->iRealAvatarHeight = min(dat->iRealAvatarHeight, PluginConfig.m_LimitStaticAvatarHeight);
+
+ if (M->GetByte(dat->hContact, "dontscaleavatars", M->GetByte("dontscaleavatars", 0)))
+ dat->iRealAvatarHeight = min(bminfo->bmHeight, dat->iRealAvatarHeight);
+
+ if (bminfo->bmHeight != 0)
+ aspect = (double)dat->iRealAvatarHeight / (double)bminfo->bmHeight;
+ else
+ aspect = 1;
+
+ newWidth = (double)bminfo->bmWidth * aspect;
+ if (newWidth > (double)(rc.right) * 0.8)
+ newWidth = (double)(rc.right) * 0.8;
+ dat->pic.cy = dat->iRealAvatarHeight + 2;
+ dat->pic.cx = (int)newWidth + 2;
+}
+
+void TSAPI WriteStatsOnClose(TWindowData *dat)
+{
+ /*
+ DBEVENTINFO dbei;
+ char buffer[450];
+ HANDLE hNewEvent;
+ time_t now = time(NULL);
+ now = now - dat->stats.started;
+
+ return;
+
+ if (dat->hContact != 0 &&(PluginConfig.m_LogStatusChanges != 0) && dat->dwFlags & MWF_LOG_STATUSCHANGES) {
+ mir_snprintf(buffer, sizeof(buffer), "Session close - active for: %d:%02d:%02d, Sent: %d (%d), Rcvd: %d (%d)", now / 3600, now / 60, now % 60, dat->stats.iSent, dat->stats.iSentBytes, dat->stats.iReceived, dat->stats.iReceivedBytes);
+ dbei.cbSize = sizeof(dbei);
+ dbei.pBlob = (PBYTE) buffer;
+ dbei.cbBlob = (int)(strlen(buffer)) + 1;
+ dbei.eventType = EVENTTYPE_STATUSCHANGE;
+ dbei.flags = DBEF_READ;
+ dbei.timestamp = time(NULL);
+ dbei.szModule = dat->szProto;
+ hNewEvent = (HANDLE) CallService(MS_DB_EVENT_ADD, (WPARAM) dat->hContact, (LPARAM) & dbei);
+ if (dat->hDbEventFirst == NULL) {
+ dat->hDbEventFirst = hNewEvent;
+ SendMessage(dat->hwnd, DM_REMAKELOG, 0, 0);
+ }
+ }
+ */
+}
+
+int TSAPI MsgWindowUpdateMenu(TWindowData *dat, HMENU submenu, int menuID)
+{
+ HWND hwndDlg = dat->hwnd;
+ bool fInfoPanel = dat->Panel->isActive();
+
+ if (menuID == MENU_TABCONTEXT) {
+ SESSION_INFO *si = (SESSION_INFO *)dat->si;
+ int iTabs = TabCtrl_GetItemCount(GetParent(hwndDlg));
+
+ EnableMenuItem(submenu, ID_TABMENU_ATTACHTOCONTAINER, M->GetByte("useclistgroups", 0) || M->GetByte("singlewinmode", 0) ? MF_GRAYED : MF_ENABLED);
+ EnableMenuItem(submenu, ID_TABMENU_CLEARSAVEDTABPOSITION, (M->GetDword(dat->hContact, "tabindex", -1) != -1) ? MF_ENABLED : MF_GRAYED);
+ } else if (menuID == MENU_PICMENU) {
+ MENUITEMINFO mii = {0};
+ TCHAR *szText = NULL;
+ char avOverride = (char)M->GetByte(dat->hContact, "hideavatar", -1);
+ HMENU visMenu = GetSubMenu(submenu, 0);
+ BOOL picValid = fInfoPanel ? (dat->hOwnPic != 0) : (dat->ace && dat->ace->hbmPic && dat->ace->hbmPic != PluginConfig.g_hbmUnknown);
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STRING;
+
+ EnableMenuItem(submenu, ID_PICMENU_SAVETHISPICTUREAS, MF_BYCOMMAND | (picValid ? MF_ENABLED : MF_GRAYED));
+
+ CheckMenuItem(visMenu, ID_VISIBILITY_DEFAULT, MF_BYCOMMAND | (avOverride == -1 ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(visMenu, ID_VISIBILITY_HIDDENFORTHISCONTACT, MF_BYCOMMAND | (avOverride == 0 ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(visMenu, ID_VISIBILITY_VISIBLEFORTHISCONTACT, MF_BYCOMMAND | (avOverride == 1 ? MF_CHECKED : MF_UNCHECKED));
+
+ CheckMenuItem(submenu, ID_PICMENU_ALWAYSKEEPTHEBUTTONBARATFULLWIDTH, MF_BYCOMMAND | (PluginConfig.m_AlwaysFullToolbarWidth ? MF_CHECKED : MF_UNCHECKED));
+ if (!fInfoPanel) {
+ EnableMenuItem(submenu, ID_PICMENU_SETTINGS, MF_BYCOMMAND | (ServiceExists(MS_AV_GETAVATARBITMAP) ? MF_ENABLED : MF_GRAYED));
+ szText = const_cast<TCHAR *>(CTranslator::get(CTranslator::GEN_AVATAR_SETTINGS));
+ EnableMenuItem(submenu, 0, MF_BYPOSITION | MF_ENABLED);
+ } else {
+ EnableMenuItem(submenu, 0, MF_BYPOSITION | MF_GRAYED);
+ EnableMenuItem(submenu, ID_PICMENU_SETTINGS, MF_BYCOMMAND | ((ServiceExists(MS_AV_SETMYAVATAR) && CallService(MS_AV_CANSETMYAVATAR, (WPARAM)(dat->cache->getActiveProto()), 0)) ? MF_ENABLED : MF_GRAYED));
+ szText = const_cast<TCHAR *>(CTranslator::get(CTranslator::GEN_AVATAR_SETOWN));
+ }
+ mii.dwTypeData = szText;
+ mii.cch = lstrlen(szText) + 1;
+ SetMenuItemInfo(submenu, ID_PICMENU_SETTINGS, FALSE, &mii);
+ } else if (menuID == MENU_PANELPICMENU) {
+ HMENU visMenu = GetSubMenu(submenu, 0);
+ char avOverride = (char)M->GetByte(dat->hContact, "hideavatar", -1);
+
+ CheckMenuItem(visMenu, ID_VISIBILITY_DEFAULT, MF_BYCOMMAND | (avOverride == -1 ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(visMenu, ID_VISIBILITY_HIDDENFORTHISCONTACT, MF_BYCOMMAND | (avOverride == 0 ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(visMenu, ID_VISIBILITY_VISIBLEFORTHISCONTACT, MF_BYCOMMAND | (avOverride == 1 ? MF_CHECKED : MF_UNCHECKED));
+
+ EnableMenuItem(submenu, ID_PICMENU_SETTINGS, MF_BYCOMMAND | (ServiceExists(MS_AV_GETAVATARBITMAP) ? MF_ENABLED : MF_GRAYED));
+ EnableMenuItem(submenu, ID_PANELPICMENU_SAVETHISPICTUREAS, MF_BYCOMMAND | ((ServiceExists(MS_AV_SAVEBITMAP) && dat->ace && dat->ace->hbmPic && dat->ace->hbmPic != PluginConfig.g_hbmUnknown) ? MF_ENABLED : MF_GRAYED));
+ }
+ return 0;
+}
+
+int TSAPI MsgWindowMenuHandler(TWindowData *dat, int selection, int menuId)
+{
+ if(dat == 0)
+ return(0);
+
+ HWND hwndDlg = dat->hwnd;
+
+ if (menuId == MENU_PICMENU || menuId == MENU_PANELPICMENU || menuId == MENU_TABCONTEXT) {
+ switch (selection) {
+ case ID_TABMENU_ATTACHTOCONTAINER:
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_SELECTCONTAINER), hwndDlg, SelectContainerDlgProc, (LPARAM) hwndDlg);
+ return 1;
+ case ID_TABMENU_CONTAINEROPTIONS:
+ if (dat->pContainer->hWndOptions == 0)
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CONTAINEROPTIONS), hwndDlg, DlgProcContainerOptions, (LPARAM) dat->pContainer);
+ return 1;
+ case ID_TABMENU_CLOSECONTAINER:
+ SendMessage(dat->pContainer->hwnd, WM_CLOSE, 0, 0);
+ return 1;
+ case ID_TABMENU_CLOSETAB:
+ SendMessage(hwndDlg, WM_CLOSE, 1, 0);
+ return 1;
+ case ID_TABMENU_SAVETABPOSITION:
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "tabindex", dat->iTabID * 100);
+ break;
+ case ID_TABMENU_CLEARSAVEDTABPOSITION:
+ DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "tabindex");
+ break;
+ case ID_TABMENU_LEAVECHATROOM: {
+ if (dat && dat->bType == SESSIONTYPE_CHAT) {
+ SESSION_INFO *si = (SESSION_INFO *)dat->si;
+ if ( (si != NULL) && (dat->hContact != NULL) ) {
+ char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) dat->hContact, 0);
+ if ( szProto )
+ CallProtoService( szProto, PS_LEAVECHAT, (WPARAM)dat->hContact, 0 );
+ }
+ }
+ return 1;
+ }
+ case ID_VISIBILITY_DEFAULT:
+ case ID_VISIBILITY_HIDDENFORTHISCONTACT:
+ case ID_VISIBILITY_VISIBLEFORTHISCONTACT: {
+ BYTE avOverrideMode;
+
+ if (selection == ID_VISIBILITY_DEFAULT)
+ avOverrideMode = -1;
+ else if (selection == ID_VISIBILITY_HIDDENFORTHISCONTACT)
+ avOverrideMode = 0;
+ else if (selection == ID_VISIBILITY_VISIBLEFORTHISCONTACT)
+ avOverrideMode = 1;
+ M->WriteByte(dat->hContact, SRMSGMOD_T, "hideavatar", avOverrideMode);
+ dat->panelWidth = -1;
+ ShowPicture(dat, FALSE);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ DM_ScrollToBottom(dat, 0, 1);
+ return 1;
+ }
+ case ID_PICMENU_ALWAYSKEEPTHEBUTTONBARATFULLWIDTH:
+ PluginConfig.m_AlwaysFullToolbarWidth = !PluginConfig.m_AlwaysFullToolbarWidth;
+ M->WriteByte(SRMSGMOD_T, "alwaysfulltoolbar", (BYTE)PluginConfig.m_AlwaysFullToolbarWidth);
+ M->BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1);
+ break;
+ case ID_PICMENU_SAVETHISPICTUREAS:
+ if (dat->Panel->isActive()) {
+ if (dat)
+ SaveAvatarToFile(dat, dat->hOwnPic, 1);
+ } else {
+ if (dat && dat->ace)
+ SaveAvatarToFile(dat, dat->ace->hbmPic, 0);
+ }
+ break;
+ case ID_PANELPICMENU_SAVETHISPICTUREAS:
+ if (dat && dat->ace)
+ SaveAvatarToFile(dat, dat->ace->hbmPic, 0);
+ break;
+ case ID_PICMENU_SETTINGS: {
+ if (menuId == MENU_PANELPICMENU)
+ CallService(MS_AV_CONTACTOPTIONS, (WPARAM)dat->hContact, 0);
+ else if (menuId == MENU_PICMENU) {
+ if (dat->Panel->isActive()) {
+ if (ServiceExists(MS_AV_SETMYAVATAR) && CallService(MS_AV_CANSETMYAVATAR, (WPARAM)(dat->cache->getActiveProto()), 0))
+ CallService(MS_AV_SETMYAVATAR, (WPARAM)(dat->cache->getActiveProto()), 0);
+ } else
+ CallService(MS_AV_CONTACTOPTIONS, (WPARAM)dat->hContact, 0);
+ }
+ }
+ return 1;
+ }
+ } else if (menuId == MENU_LOGMENU) {
+ int iLocalTime = 0;
+ int iRtl = (PluginConfig.m_RTLDefault == 0 ? M->GetByte(dat->hContact, "RTL", 0) : M->GetByte(dat->hContact, "RTL", 1));
+ int iLogStatus = (PluginConfig.m_LogStatusChanges != 0) && dat->dwFlags & MWF_LOG_STATUSCHANGES;
+
+ DWORD dwOldFlags = dat->dwFlags;
+
+ switch (selection) {
+ case ID_MESSAGELOGSETTINGS_GLOBAL: {
+ OPENOPTIONSDIALOG ood = {0};
+
+ ood.cbSize = sizeof(OPENOPTIONSDIALOG);
+ ood.pszGroup = NULL;
+ ood.pszPage = "Message Sessions";
+ ood.pszTab = NULL;
+ M->WriteByte(SRMSGMOD_T, "opage", 3); // force 3th tab to appear
+ CallService (MS_OPT_OPENOPTIONS, 0, (LPARAM)&ood);
+ return 1;
+ }
+
+ case ID_MESSAGELOGSETTINGS_FORTHISCONTACT:
+ CallService(MS_TABMSG_SETUSERPREFS, (WPARAM)dat->hContact, (LPARAM)0);
+ return 1;
+
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * update the status bar field which displays the number of characters in the input area
+ * and various indicators (caps lock, num lock, insert mode).
+ */
+
+void TSAPI UpdateReadChars(const TWindowData *dat)
+{
+
+ if(dat && (dat->pContainer->hwndStatus && dat->pContainer->hwndActive == dat->hwnd)) {
+ TCHAR buf[128];
+ int len;
+ TCHAR szIndicators[20];
+ BOOL fCaps, fNum;
+
+ szIndicators[0] = 0;
+ if (dat->bType == SESSIONTYPE_CHAT)
+ len = GetWindowTextLength(GetDlgItem(dat->hwnd, IDC_CHAT_MESSAGE));
+ else {
+ /*
+ * retrieve text length in UTF8 bytes, because this is the relevant length for most protocols
+ */
+ GETTEXTLENGTHEX gtxl = {0};
+ gtxl.codepage = CP_UTF8;
+ gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMBYTES;
+
+ len = SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_GETTEXTLENGTHEX, (WPARAM) & gtxl, 0);
+ }
+
+ fCaps = (GetKeyState(VK_CAPITAL) & 1);
+ fNum = (GetKeyState(VK_NUMLOCK) & 1);
+
+ if (dat->fInsertMode)
+ lstrcat(szIndicators, _T("O"));
+ if (fCaps)
+ lstrcat(szIndicators, _T("C"));
+ if (fNum)
+ lstrcat(szIndicators, _T("N"));
+ if (dat->fInsertMode || fCaps || fNum)
+ lstrcat(szIndicators, _T(" | "));
+
+ mir_sntprintf(buf, safe_sizeof(buf), _T("%s%s %d/%d"), szIndicators, dat->lcID, dat->iOpenJobs, len);
+ SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 1, (LPARAM) buf);
+ if(PluginConfig.m_visualMessageSizeIndicator)
+ InvalidateRect(dat->pContainer->hwndStatus, NULL, FALSE);
+ }
+}
+
+/*
+ * update all status bar fields and force a redraw of the status bar.
+ */
+
+void TSAPI UpdateStatusBar(const TWindowData *dat)
+{
+ if (dat && dat->pContainer->hwndStatus && dat->pContainer->hwndActive == dat->hwnd) {
+ if (dat->bType == SESSIONTYPE_IM) {
+ if(dat->szStatusBar[0]) {
+ SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]);
+ SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)dat->szStatusBar);
+ }
+ else {
+ SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, 0);
+ DM_UpdateLastMessage(dat);
+ }
+ }
+ else
+ SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, 0);
+ UpdateReadChars(dat);
+ InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE);
+ SendMessage(dat->pContainer->hwndStatus, WM_USER + 101, 0, (LPARAM)dat);
+ }
+}
+
+/*
+ * provide user feedback via icons on tabs. Used to indicate "send in progress" or
+ * any error state.
+ *
+ * NOT used for typing notification feedback as this is handled directly from the
+ * MTN handler.
+ */
+
+void TSAPI HandleIconFeedback(TWindowData *dat, HICON iIcon)
+{
+ TCITEM item = {0};
+ HICON iOldIcon = dat->hTabIcon;
+
+ if (iIcon == (HICON) - 1) { // restore status image
+ if (dat->dwFlags & MWF_ERRORSTATE) {
+ dat->hTabIcon = PluginConfig.g_iconErr;
+ } else {
+ dat->hTabIcon = dat->hTabStatusIcon;
+ }
+ } else
+ dat->hTabIcon = iIcon;
+ item.iImage = 0;
+ item.mask = TCIF_IMAGE;
+ if(dat->pContainer->dwFlags & CNT_SIDEBAR)
+ dat->pContainer->SideBar->updateSession(dat);
+ else
+ TabCtrl_SetItem(GetDlgItem(dat->pContainer->hwnd, IDC_MSGTABS), dat->iTabID, &item);
+}
+
+/*
+ * retrieve the visiblity of the avatar window, depending on the global setting
+ * and local mode
+ */
+
+int TSAPI GetAvatarVisibility(HWND hwndDlg, struct TWindowData *dat)
+{
+ BYTE bAvatarMode = dat->pContainer->avatarMode;
+ BYTE bOwnAvatarMode = dat->pContainer->ownAvatarMode;
+ char hideOverride = (char)M->GetByte(dat->hContact, "hideavatar", -1);
+ // infopanel visible, consider own avatar display
+
+ dat->showPic = 0;
+
+ if (dat->Panel->isActive() && bAvatarMode != 3) {
+ if (bOwnAvatarMode)
+ dat->showPic = FALSE;
+ else {
+ FLASHAVATAR fa = {0};
+ if (PluginConfig.g_FlashAvatarAvail) {
+ fa.cProto = dat->szProto;
+ fa.id = 25367;
+ fa.hParentWindow = GetDlgItem(hwndDlg, IDC_CONTACTPIC);
+
+ CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0);
+ if (fa.hWindow != NULL&&dat->hwndContactPic) {
+ DestroyWindow(dat->hwndContactPic);
+ dat->hwndContactPic = NULL;
+ }
+ dat->showPic = ((dat->hOwnPic && dat->hOwnPic != PluginConfig.g_hbmUnknown) || (fa.hWindow != NULL)) ? 1 : 0;
+ } else
+ dat->showPic = (dat->hOwnPic && dat->hOwnPic != PluginConfig.g_hbmUnknown) ? 1 : 0;
+
+ if (!PluginConfig.g_bDisableAniAvatars && fa.hWindow == NULL && !dat->hwndContactPic)
+ dat->hwndContactPic =CreateWindowEx(WS_EX_TOPMOST, AVATAR_CONTROL_CLASS, _T(""), WS_VISIBLE | WS_CHILD, 1, 1, 1, 1, GetDlgItem(hwndDlg, IDC_CONTACTPIC), (HMENU)0, NULL, NULL);
+
+ }
+ switch (bAvatarMode) {
+ case 2:
+ dat->showInfoPic = 0;
+ break;
+ case 0:
+ dat->showInfoPic = 1;
+ case 1: {
+ FLASHAVATAR fa = {0};
+ HBITMAP hbm = ((dat->ace && !(dat->ace->dwFlags & AVS_HIDEONCLIST)) ? dat->ace->hbmPic : 0);
+
+ if(0 == hbm && 0 == bAvatarMode && !PluginConfig.g_bDisableAniAvatars) {
+ dat->showInfoPic = 0;
+ break;
+ }
+
+ if (PluginConfig.g_FlashAvatarAvail) {
+ fa.cProto = dat->szProto;
+ fa.id = 25367;
+ fa.hContact = dat->hContact;
+ fa.hParentWindow = dat->hwndPanelPicParent;
+
+ CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0);
+ if (fa.hWindow != NULL && dat->hwndPanelPic) {
+ DestroyWindow(dat->hwndPanelPic);
+ dat->hwndPanelPic = NULL;
+ ShowWindow(dat->hwndPanelPicParent, SW_SHOW);
+ EnableWindow(dat->hwndPanelPicParent, TRUE);
+ }
+ }
+ if (!PluginConfig.g_bDisableAniAvatars && fa.hWindow == NULL && !dat->hwndPanelPic) {
+ dat->hwndPanelPic = CreateWindowEx(WS_EX_TOPMOST, AVATAR_CONTROL_CLASS, _T(""), WS_VISIBLE | WS_CHILD, 1, 1, 1, 1, dat->hwndPanelPicParent, (HMENU)7000, NULL, NULL);
+ if(dat->hwndPanelPic)
+ SendMessage(dat->hwndPanelPic, AVATAR_SETAEROCOMPATDRAWING, 0, TRUE);
+ }
+ if(bAvatarMode != 0) {
+ if ((hbm && hbm != PluginConfig.g_hbmUnknown) || (fa.hWindow != NULL))
+ dat->showInfoPic = 1;
+ else
+ dat->showInfoPic = 0;
+ }
+ break;
+ }
+ }
+ if (dat->showInfoPic)
+ dat->showInfoPic = hideOverride == 0 ? 0 : dat->showInfoPic;
+ else
+ dat->showInfoPic = hideOverride == 1 ? 1 : dat->showInfoPic;
+ //Bolshevik: reloads avatars
+ if (dat->showInfoPic) {
+ /** panel and contact is shown, reloads contact's avatar -> panel
+ * user avatar -> bottom picture
+ */
+ SendMessage(dat->hwndPanelPic, AVATAR_SETCONTACT, (WPARAM)0, (LPARAM)dat->hContact);
+ if (dat->hwndContactPic)
+ SendMessage(dat->hwndContactPic, AVATAR_SETPROTOCOL, (WPARAM)0, (LPARAM)dat->szProto);
+ }
+ else {
+ //show only user picture(contact is unaccessible)
+ if (dat->hwndContactPic)
+ SendMessage(dat->hwndContactPic, AVATAR_SETPROTOCOL, (WPARAM)0, (LPARAM)dat->szProto);
+ }
+//Bolshevik_
+ } else {
+ dat->showInfoPic = 0;
+
+ switch (bAvatarMode) {
+ case 0: // globally on
+ dat->showPic = 1;
+ break;
+ case 2: // globally OFF
+ dat->showPic = 0;
+ break;
+ case 3: // on, if present
+ case 1: {
+ FLASHAVATAR fa = {0};
+ HBITMAP hbm = (dat->ace && !(dat->ace->dwFlags & AVS_HIDEONCLIST)) ? dat->ace->hbmPic : 0;
+
+ if (PluginConfig.g_FlashAvatarAvail) {
+ fa.cProto = dat->szProto;
+ fa.id = 25367;
+ fa.hContact = dat->hContact;
+ fa.hParentWindow = GetDlgItem(hwndDlg, IDC_CONTACTPIC);
+
+ CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0);
+
+ if (fa.hWindow != NULL&&dat->hwndContactPic) {
+ DestroyWindow(dat->hwndContactPic);
+ dat->hwndContactPic = NULL;
+ }
+ }
+ if (!PluginConfig.g_bDisableAniAvatars&&fa.hWindow == NULL&&!dat->hwndContactPic)
+ dat->hwndContactPic =CreateWindowEx(WS_EX_TOPMOST, AVATAR_CONTROL_CLASS, _T(""), WS_VISIBLE | WS_CHILD, 1, 1, 1, 1, GetDlgItem(hwndDlg, IDC_CONTACTPIC), (HMENU)0, NULL, NULL);
+
+ if ((hbm && hbm != PluginConfig.g_hbmUnknown) || (fa.hWindow != NULL))
+ dat->showPic = 1;
+ else
+ dat->showPic = 0;
+ break;
+ }
+ }
+ if (dat->showPic)
+ dat->showPic = hideOverride == 0 ? 0 : dat->showPic;
+ else
+ dat->showPic = hideOverride == 1 ? 1 : dat->showPic;
+ //Bolshevik: reloads avatars
+ if (dat->showPic)
+ //shows contact or user picture, depending on panel visibility
+ if (dat->hwndPanelPic)
+ SendMessage(dat->hwndContactPic, AVATAR_SETPROTOCOL, (WPARAM)0, (LPARAM)dat->szProto);
+ if (dat->hwndContactPic)
+ SendMessage(dat->hwndContactPic, AVATAR_SETCONTACT, (WPARAM)0, (LPARAM)dat->hContact);
+
+ }
+ return dat->showPic;
+}
+
+/*
+ * checks, if there is a valid smileypack installed for the given protocol
+ */
+
+int TSAPI CheckValidSmileyPack(const char *szProto, HANDLE hContact)
+{
+ SMADD_INFO2 smainfo = {0};
+
+ if (PluginConfig.g_SmileyAddAvail) {
+ smainfo.cbSize = sizeof(smainfo);
+ smainfo.Protocolname = const_cast<char *>(szProto);
+ smainfo.hContact = hContact;
+ CallService(MS_SMILEYADD_GETINFO2, 0, (LPARAM)&smainfo);
+ if(smainfo.ButtonIcon)
+ DestroyIcon(smainfo.ButtonIcon);
+ return smainfo.NumberOfVisibleSmileys;
+ } else
+ return 0;
+}
+
+/*
+ * return value MUST be free()'d by caller.
+ */
+
+TCHAR* TSAPI QuoteText(const TCHAR *text, int charsPerLine, int removeExistingQuotes)
+{
+ int inChar, outChar, lineChar;
+ int justDoneLineBreak, bufSize;
+ TCHAR *strout;
+
+ bufSize = lstrlenW(text) + 23;
+ strout = (TCHAR*)malloc(bufSize * sizeof(TCHAR));
+ inChar = 0;
+ justDoneLineBreak = 1;
+ for (outChar = 0, lineChar = 0;text[inChar];) {
+ if (outChar >= bufSize - 8) {
+ bufSize += 20;
+ strout = (TCHAR *)realloc(strout, bufSize * sizeof(TCHAR));
+ }
+ if (justDoneLineBreak && text[inChar] != '\r' && text[inChar] != '\n') {
+ if (removeExistingQuotes)
+ if (text[inChar] == '>') {
+ while (text[++inChar] != '\n');
+ inChar++;
+ continue;
+ }
+ strout[outChar++] = '>';
+ strout[outChar++] = ' ';
+ lineChar = 2;
+ }
+ if (lineChar == charsPerLine && text[inChar] != '\r' && text[inChar] != '\n') {
+ int decreasedBy;
+ for (decreasedBy = 0;lineChar > 10;lineChar--, inChar--, outChar--, decreasedBy++)
+ if (strout[outChar] == ' ' || strout[outChar] == '\t' || strout[outChar] == '-') break;
+ if (lineChar <= 10) {
+ lineChar += decreasedBy;
+ inChar += decreasedBy;
+ outChar += decreasedBy;
+ } else inChar++;
+ strout[outChar++] = '\r';
+ strout[outChar++] = '\n';
+ justDoneLineBreak = 1;
+ continue;
+ }
+ strout[outChar++] = text[inChar];
+ lineChar++;
+ if (text[inChar] == '\n' || text[inChar] == '\r') {
+ if (text[inChar] == '\r' && text[inChar+1] != '\n')
+ strout[outChar++] = '\n';
+ justDoneLineBreak = 1;
+ lineChar = 0;
+ } else justDoneLineBreak = 0;
+ inChar++;
+ }
+ strout[outChar++] = '\r';
+ strout[outChar++] = '\n';
+ strout[outChar] = 0;
+ return strout;
+}
+
+
+void TSAPI AdjustBottomAvatarDisplay(TWindowData *dat)
+{
+ if(dat) {
+ bool fInfoPanel = dat->Panel->isActive();
+ HBITMAP hbm = (fInfoPanel && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown);
+ HWND hwndDlg = dat->hwnd;
+
+ if (PluginConfig.g_FlashAvatarAvail) {
+ FLASHAVATAR fa = {0};
+
+ fa.hContact = dat->hContact;
+ fa.hWindow = 0;
+ fa.id = 25367;
+ fa.cProto = dat->szProto;
+ CallService(MS_FAVATAR_GETINFO, (WPARAM)&fa, 0);
+ if (fa.hWindow) {
+ dat->hwndFlash = fa.hWindow;
+ SetParent(dat->hwndFlash, fInfoPanel ? dat->hwndPanelPicParent : GetDlgItem(dat->hwnd, IDC_CONTACTPIC));
+ }
+ fa.hContact = 0;
+ fa.hWindow = 0;
+ if (fInfoPanel) {
+ fa.hParentWindow = GetDlgItem(hwndDlg, IDC_CONTACTPIC);
+ CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0);
+ if (fa.hWindow) {
+ SetParent(fa.hWindow, GetDlgItem(hwndDlg, IDC_CONTACTPIC));
+ ShowWindow(fa.hWindow, SW_SHOW);
+ }
+ } else {
+ CallService(MS_FAVATAR_GETINFO, (WPARAM)&fa, 0);
+ if (fa.hWindow)
+ ShowWindow(fa.hWindow, SW_HIDE);
+ }
+ }
+
+ if (hbm) {
+ dat->showPic = GetAvatarVisibility(hwndDlg, dat);
+ if (dat->dynaSplitter == 0 || dat->splitterY == 0)
+ LoadSplitter(dat);
+ dat->dynaSplitter = dat->splitterY - DPISCALEY_S(34);
+ DM_RecalcPictureSize(dat);
+ Utils::showDlgControl(hwndDlg, IDC_CONTACTPIC, dat->showPic ? SW_SHOW : SW_HIDE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_CONTACTPIC), NULL, TRUE);
+ } else {
+ dat->showPic = GetAvatarVisibility(hwndDlg, dat);
+ Utils::showDlgControl(hwndDlg, IDC_CONTACTPIC, dat->showPic ? SW_SHOW : SW_HIDE);
+ dat->pic.cy = dat->pic.cx = DPISCALEY_S(60);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_CONTACTPIC), NULL, TRUE);
+ }
+ }
+}
+
+void TSAPI ShowPicture(TWindowData *dat, BOOL showNewPic)
+{
+ DBVARIANT dbv = {0};
+ RECT rc;
+ HWND hwndDlg = dat->hwnd;
+
+ if (!dat->Panel->isActive())
+ dat->pic.cy = dat->pic.cx = DPISCALEY_S(60);
+
+ if (showNewPic) {
+ if (dat->Panel->isActive() && dat->pContainer->avatarMode != 3) {
+ if (!dat->hwndPanelPic) {
+ dat->panelWidth = -1;
+ InvalidateRect(dat->hwnd, NULL, TRUE);
+ UpdateWindow(dat->hwnd);
+ SendMessage(dat->hwnd, WM_SIZE, 0, 0);
+ }
+ return;
+ }
+ AdjustBottomAvatarDisplay(dat);
+ } else {
+ dat->showPic = dat->showPic ? 0 : 1;
+ DBWriteContactSettingByte(dat->hContact, SRMSGMOD_T, "MOD_ShowPic", (BYTE)dat->showPic);
+ }
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_CONTACTPIC), &rc);
+ if (dat->minEditBoxSize.cy + DPISCALEY_S(3)> dat->splitterY)
+ SendMessage(hwndDlg, DM_SPLITTERMOVED, (WPARAM)rc.bottom - dat->minEditBoxSize.cy, (LPARAM)GetDlgItem(hwndDlg, IDC_SPLITTER));
+ if (!showNewPic)
+ SetDialogToType(hwndDlg);
+ else
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+
+}
+
+void TSAPI FlashOnClist(HWND hwndDlg, struct TWindowData *dat, HANDLE hEvent, DBEVENTINFO *dbei)
+{
+ CLISTEVENT cle;
+
+ dat->dwTickLastEvent = GetTickCount();
+
+ if ((GetForegroundWindow() != dat->pContainer->hwnd || dat->pContainer->hwndActive != hwndDlg) && !(dbei->flags & DBEF_SENT) && dbei->eventType == EVENTTYPE_MESSAGE) {
+ dat->dwUnread++;
+ UpdateTrayMenu(dat, (WORD)(dat->cache->getActiveStatus()), dat->cache->getActiveProto(), dat->szStatus, dat->hContact, 0L);
+ if (nen_options.bTraySupport)
+ return;
+ }
+ if (hEvent == 0)
+ return;
+
+ if (!PluginConfig.m_FlashOnClist)
+ return;
+ if ((GetForegroundWindow() != dat->pContainer->hwnd || dat->pContainer->hwndActive != hwndDlg) && !(dbei->flags & DBEF_SENT) && dbei->eventType == EVENTTYPE_MESSAGE && !(dat->dwFlagsEx & MWF_SHOW_FLASHCLIST)) {
+ ZeroMemory(&cle, sizeof(cle));
+ cle.cbSize = sizeof(cle);
+ cle.hContact = (HANDLE) dat->hContact;
+ cle.hDbEvent = hEvent;
+ cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ cle.pszService = "SRMsg/ReadMessage";
+ CallService(MS_CLIST_ADDEVENT, 0, (LPARAM) & cle);
+ dat->dwFlagsEx |= MWF_SHOW_FLASHCLIST;
+ dat->hFlashingEvent = hEvent;
+ }
+}
+
+/*
+ * callback function for text streaming
+ */
+
+static DWORD CALLBACK Message_StreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb)
+{
+ static DWORD dwRead;
+ char ** ppText = (char **) dwCookie;
+
+ if (*ppText == NULL) {
+ *ppText = (char *)malloc(cb + 2);
+ CopyMemory(*ppText, pbBuff, cb);
+ *pcb = cb;
+ dwRead = cb;
+ *(*ppText + cb) = '\0';
+ } else {
+ char *p = (char *)realloc(*ppText, dwRead + cb + 2);
+ CopyMemory(p + dwRead, pbBuff, cb);
+ *ppText = p;
+ *pcb = cb;
+ dwRead += cb;
+ *(*ppText + dwRead) = '\0';
+ }
+ return 0;
+}
+
+/*
+ * retrieve contents of the richedit control by streaming. Used to get the
+ * typed message before sending it.
+ * caller must free the returned pointer.
+ * UNICODE version returns UTF-8 encoded string.
+ */
+
+char* TSAPI Message_GetFromStream(HWND hwndRtf, const TWindowData* dat, DWORD dwPassedFlags)
+{
+ EDITSTREAM stream;
+ char *pszText = NULL;
+ DWORD dwFlags = 0;
+
+ if (hwndRtf == 0 || dat == 0)
+ return NULL;
+
+ ZeroMemory(&stream, sizeof(stream));
+ stream.pfnCallback = Message_StreamCallback;
+ stream.dwCookie = (DWORD_PTR) & pszText; // pass pointer to pointer
+ if (dwPassedFlags == 0)
+ dwFlags = (CP_UTF8 << 16) | (SF_RTFNOOBJS | SFF_PLAINRTF | SF_USECODEPAGE);
+ else
+ dwFlags = (CP_UTF8 << 16) | dwPassedFlags;
+ SendMessage(hwndRtf, EM_STREAMOUT, (WPARAM)dwFlags, (LPARAM) & stream);
+
+ return pszText; // pszText contains the text
+}
+
+/*
+ * convert rich edit code to bbcode (if wanted). Otherwise, strip all RTF formatting
+ * tags and return plain text
+ */
+
+BOOL TSAPI DoRtfToTags(TCHAR * pszText, const TWindowData *dat)
+{
+ TCHAR * p1;
+ BOOL bJustRemovedRTF = TRUE;
+ BOOL bTextHasStarted = FALSE;
+ LOGFONTA lf;
+ COLORREF color;
+ static int inColor = 0;
+
+ if (!pszText)
+ return FALSE;
+
+ /*
+ * used to filter out attributes which are already set for the default message input area
+ * font
+ */
+
+ lf = dat->pContainer->theme.logFonts[MSGFONTID_MESSAGEAREA];
+ color = dat->pContainer->theme.fontColors[MSGFONTID_MESSAGEAREA];
+
+ // create an index of colors in the module and map them to
+ // corresponding colors in the RTF color table
+
+ Utils::CreateColorMap(pszText);
+ // scan the file for rtf commands and remove or parse them
+ inColor = 0;
+ p1 = _tcsstr(pszText, _T("\\pard"));
+ if (p1) {
+ size_t iRemoveChars;
+ TCHAR InsertThis[50];
+ p1 += 5;
+
+ MoveMemory(pszText, p1, (lstrlen(p1) + 1) * sizeof(TCHAR));
+ p1 = pszText;
+ // iterate through all characters, if rtf control character found then take action
+ while (*p1 != (TCHAR) '\0') {
+ _sntprintf(InsertThis, 50, _T(""));
+ iRemoveChars = 0;
+
+ switch (*p1) {
+ case (TCHAR) '\\':
+ if (p1 == _tcsstr(p1, _T("\\cf"))) { // foreground color
+ TCHAR szTemp[20];
+ int iCol = _ttoi(p1 + 3);
+ int iInd = Utils::RTFColorToIndex(iCol);
+ bJustRemovedRTF = TRUE;
+
+ _sntprintf(szTemp, 20, _T("%d"), iCol);
+ iRemoveChars = 3 + lstrlen(szTemp);
+ if (bTextHasStarted || iCol)
+ _sntprintf(InsertThis, sizeof(InsertThis) / sizeof(TCHAR), (iInd > 0) ? (inColor ? _T("[/color][color=%s]") : _T("[color=%s]")) : (inColor ? _T("[/color]") : _T("")), Utils::rtf_ctable[iInd - 1].szName);
+ inColor = iInd > 0 ? 1 : 0;
+ } else if (p1 == _tcsstr(p1, _T("\\highlight"))) { //background color
+ TCHAR szTemp[20];
+ int iCol = _ttoi(p1 + 10);
+ bJustRemovedRTF = TRUE;
+
+ _sntprintf(szTemp, 20, _T("%d"), iCol);
+ iRemoveChars = 10 + lstrlen(szTemp);
+ } else if (p1 == _tcsstr(p1, _T("\\par"))) { // newline
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 4;
+ } else if (p1 == _tcsstr(p1, _T("\\line"))) { // soft line break;
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 5;
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("\n"));
+ } else if (p1 == _tcsstr(p1, _T("\\endash"))) {
+ bTextHasStarted = bJustRemovedRTF = TRUE;
+ iRemoveChars = 7;
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x2013);
+ } else if (p1 == _tcsstr(p1, _T("\\emdash"))) {
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 7;
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x2014);
+ } else if (p1 == _tcsstr(p1, _T("\\bullet"))) {
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 7;
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x2022);
+ } else if (p1 == _tcsstr(p1, _T("\\ldblquote"))) {
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 10;
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x201C);
+ } else if (p1 == _tcsstr(p1, _T("\\rdblquote"))) {
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 10;
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x201D);
+ } else if (p1 == _tcsstr(p1, _T("\\lquote"))) {
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 7;
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x2018);
+ } else if (p1 == _tcsstr(p1, _T("\\rquote"))) {
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 7;
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x2019);
+ } else if (p1 == _tcsstr(p1, _T("\\b"))) { //bold
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = (p1[2] != (TCHAR) '0') ? 2 : 3;
+ if (!(lf.lfWeight == FW_BOLD)) { // only allow bold if the font itself isn't a bold one, otherwise just strip it..
+ if (dat->SendFormat)
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), (p1[2] != (TCHAR) '0') ? _T("[b]") : _T("[/b]"));
+ }
+
+ } else if (p1 == _tcsstr(p1, _T("\\i"))) { // italics
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = (p1[2] != (TCHAR) '0') ? 2 : 3;
+ if (!lf.lfItalic) { // same as for bold
+ if (dat->SendFormat)
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), (p1[2] != (TCHAR) '0') ? _T("[i]") : _T("[/i]"));
+ }
+
+ } else if (p1 == _tcsstr(p1, _T("\\strike"))) { // strike-out
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = (p1[7] != (TCHAR) '0') ? 7 : 8;
+ if (!lf.lfStrikeOut) { // same as for bold
+ if (dat->SendFormat)
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), (p1[7] != (TCHAR) '0') ? _T("[s]") : _T("[/s]"));
+ }
+
+ } else if (p1 == _tcsstr(p1, _T("\\ul"))) { // underlined
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ if (p1[3] == (TCHAR) 'n')
+ iRemoveChars = 7;
+ else if (p1[3] == (TCHAR) '0')
+ iRemoveChars = 4;
+ else
+ iRemoveChars = 3;
+ if (!lf.lfUnderline) { // same as for bold
+ if (dat->SendFormat)
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), (p1[3] != (TCHAR) '0' && p1[3] != (TCHAR) 'n') ? _T("[u]") : _T("[/u]"));
+ }
+
+ } else if (p1 == _tcsstr(p1, _T("\\tab"))) { // tab
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = TRUE;
+ iRemoveChars = 4;
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x09);
+ } else if (p1[1] == (TCHAR) '\\' || p1[1] == (TCHAR) '{' || p1[1] == (TCHAR) '}') { // escaped characters
+ bTextHasStarted = TRUE;
+ //bJustRemovedRTF = TRUE;
+ iRemoveChars = 2;
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), p1[1]);
+ } else if (p1[1] == (TCHAR) '\'') { // special character
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = FALSE;
+ if (p1[2] != (TCHAR) ' ' && p1[2] != (TCHAR) '\\') {
+ int iLame = 0;
+ TCHAR * p3;
+ TCHAR *stoppedHere;
+
+ if (p1[3] != (TCHAR) ' ' && p1[3] != (TCHAR) '\\') {
+ _tcsncpy(InsertThis, p1 + 2, 3);
+ iRemoveChars = 4;
+ InsertThis[2] = 0;
+ } else {
+ _tcsncpy(InsertThis, p1 + 2, 2);
+ iRemoveChars = 3;
+ InsertThis[2] = 0;
+ }
+ // convert string containing char in hex format to int.
+ p3 = InsertThis;
+ iLame = _tcstol(p3, &stoppedHere, 16);
+ _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), (TCHAR) iLame);
+
+ } else
+ iRemoveChars = 2;
+ } else { // remove unknown RTF command
+ int j = 1;
+ bJustRemovedRTF = TRUE;
+ while (!_tcschr(_T(" !$%()#*\"'"), p1[j]) && p1[j] != (TCHAR) '§' && p1[j] != (TCHAR) '\\' && p1[j] != (TCHAR) '\0')
+ // while(!_tcschr(_T(" !§$%&()#*"), p1[j]) && p1[j] != (TCHAR)'\\' && p1[j] != (TCHAR)'\0')
+ j++;
+ // while(p1[j] != (TCHAR)' ' && p1[j] != (TCHAR)'\\' && p1[j] != (TCHAR)'\0')
+ // j++;
+ iRemoveChars = j;
+ }
+ break;
+
+ case (TCHAR) '{': // other RTF control characters
+ case (TCHAR) '}':
+ iRemoveChars = 1;
+ break;
+
+ case (TCHAR) ' ': // remove spaces following a RTF command
+ if (bJustRemovedRTF)
+ iRemoveChars = 1;
+ bJustRemovedRTF = FALSE;
+ bTextHasStarted = TRUE;
+ break;
+
+ default: // other text that should not be touched
+ bTextHasStarted = TRUE;
+ bJustRemovedRTF = FALSE;
+
+ break;
+ }
+
+ // move the memory and paste in new commands instead of the old RTF
+ if (lstrlen(InsertThis) || iRemoveChars) {
+ MoveMemory(p1 + lstrlen(InsertThis), p1 + iRemoveChars, (lstrlen(p1) - iRemoveChars + 1) * sizeof(TCHAR));
+ CopyMemory(p1, InsertThis, lstrlen(InsertThis) * sizeof(TCHAR));
+ p1 += lstrlen(InsertThis);
+ } else
+ p1++;
+ }
+
+ } else {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * trims the output from DoRtfToTags(), removes trailing newlines and whitespaces...
+ */
+
+void TSAPI DoTrimMessage(TCHAR *msg)
+{
+ size_t iLen = lstrlen(msg);
+ size_t i = iLen;
+
+ while (i && (msg[i-1] == '\r' || msg[i-1] == '\n') || msg[i-1] == ' ') {
+ i--;
+ }
+ if (i < iLen)
+ msg[i] = '\0';
+}
+
+/*
+ * retrieve both buddys and my own UIN for a message session and store them in the message window *dat
+ * respects metacontacts and uses the current protocol if the contact is a MC
+ */
+
+void TSAPI GetMYUIN(TWindowData *dat)
+{
+ CONTACTINFO ci;
+ ZeroMemory((void *)&ci, sizeof(ci));
+
+ /*
+ * get my uin
+ */
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = 0;
+ ci.szProto = const_cast<char *>(dat->cache->getActiveProto());
+ ci.dwFlag = CNF_TCHAR | CNF_DISPLAYUID;
+
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ switch (ci.type) {
+ case CNFT_ASCIIZ:
+ mir_sntprintf(dat->myUin, safe_sizeof(dat->myUin), _T("%s"), reinterpret_cast<TCHAR *>(ci.pszVal));
+ mir_free((void *)ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ mir_sntprintf(dat->myUin, safe_sizeof(dat->myUin), _T("%u"), ci.dVal);
+ break;
+ default:
+ dat->myUin[0] = 0;
+ break;
+ }
+ } else
+ dat->myUin[0] = 0;
+}
+
+static int g_IEViewAvail = -1;
+static int g_HPPAvail = -1;
+
+UINT TSAPI GetIEViewMode(HWND hwndDlg, HANDLE hContact)
+{
+ int iWantIEView = 0, iWantHPP = 0;
+
+ if (g_IEViewAvail == -1)
+ g_IEViewAvail = ServiceExists(MS_IEVIEW_WINDOW);
+
+ if (g_HPPAvail == -1)
+ g_HPPAvail = ServiceExists("History++/ExtGrid/NewWindow");
+
+ PluginConfig.g_WantIEView = g_IEViewAvail && M->GetByte("default_ieview", 0);
+ PluginConfig.g_WantHPP = g_HPPAvail && M->GetByte("default_hpp", 0);
+
+ iWantIEView = (PluginConfig.g_WantIEView) || (M->GetByte(hContact, "ieview", 0) == 1 && g_IEViewAvail);
+ iWantIEView = (M->GetByte(hContact, "ieview", 0) == (BYTE) - 1) ? 0 : iWantIEView;
+
+ iWantHPP = (PluginConfig.g_WantHPP) || (M->GetByte(hContact, "hpplog", 0) == 1 && g_HPPAvail);
+ iWantHPP = (M->GetByte(hContact, "hpplog", 0) == (BYTE) - 1) ? 0 : iWantHPP;
+
+ return iWantHPP ? WANT_HPP_LOG : (iWantIEView ? WANT_IEVIEW_LOG : 0);
+}
+
+#if defined(__FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER)
+static void CheckAndDestroyHPP(struct TWindowData *dat)
+{
+ if (dat->hwndHPP) {
+ IEVIEWWINDOW ieWindow;
+ ieWindow.cbSize = sizeof(IEVIEWWINDOW);
+ ieWindow.iType = IEW_DESTROY;
+ ieWindow.hwnd = dat->hwndHPP;
+ if(dat->oldIEViewProc) {
+ SetWindowLongPtr(dat->hwndHPP, GWLP_WNDPROC, (LONG_PTR)dat->oldIEViewProc);
+ dat->oldIEViewProc = 0;
+ }
+ CallService(MS_HPP_EG_WINDOW, 0, (LPARAM)&ieWindow);
+ dat->hwndHPP = 0;
+ }
+}
+
+void TSAPI CheckAndDestroyIEView(TWindowData *dat)
+{
+ if (dat->hwndIEView) {
+ IEVIEWWINDOW ieWindow;
+ ieWindow.cbSize = sizeof(IEVIEWWINDOW);
+ ieWindow.iType = IEW_DESTROY;
+ ieWindow.hwnd = dat->hwndIEView;
+ if (dat->oldIEViewProc){
+ SetWindowLongPtr(dat->hwndIEView, GWLP_WNDPROC, (LONG_PTR)dat->oldIEViewProc);
+ dat->oldIEViewProc =0;
+ }
+ CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
+ dat->oldIEViewProc = 0;
+ dat->hwndIEView = 0;
+ }
+}
+#endif
+
+void TSAPI SetMessageLog(TWindowData *dat)
+{
+ HWND hwndDlg = dat->hwnd;
+ unsigned int iLogMode = GetIEViewMode(hwndDlg, dat->hContact);
+
+ if (iLogMode == WANT_IEVIEW_LOG && dat->hwndIEView == 0) {
+ IEVIEWWINDOW ieWindow;
+
+ ZeroMemory(&ieWindow, sizeof(ieWindow));
+#if defined(__FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER)
+ CheckAndDestroyHPP(dat);
+#endif
+ ieWindow.cbSize = sizeof(IEVIEWWINDOW);
+ ieWindow.iType = IEW_CREATE;
+ ieWindow.dwFlags = 0;
+ ieWindow.dwMode = IEWM_TABSRMM;
+ ieWindow.parent = hwndDlg;
+ ieWindow.x = 0;
+ ieWindow.y = 0;
+ ieWindow.cx = 200;
+ ieWindow.cy = 200;
+ CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
+ dat->hwndIEView = ieWindow.hwnd;
+ Utils::showDlgControl(hwndDlg, IDC_LOG, SW_HIDE);
+ Utils::enableDlgControl(hwndDlg, IDC_LOG, FALSE);
+ } else if (iLogMode == WANT_HPP_LOG && dat->hwndHPP == 0) {
+ IEVIEWWINDOW ieWindow;
+#if defined(__FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER)
+ CheckAndDestroyIEView(dat);
+#endif
+ ieWindow.cbSize = sizeof(IEVIEWWINDOW);
+ ieWindow.iType = IEW_CREATE;
+ ieWindow.dwFlags = 0;
+ ieWindow.dwMode = IEWM_TABSRMM;
+ ieWindow.parent = hwndDlg;
+ ieWindow.x = 0;
+ ieWindow.y = 0;
+ ieWindow.cx = 10;
+ ieWindow.cy = 10;
+ CallService(MS_HPP_EG_WINDOW, 0, (LPARAM)&ieWindow);
+ dat->hwndHPP = ieWindow.hwnd;
+ Utils::showDlgControl(hwndDlg, IDC_LOG, SW_HIDE);
+ Utils::enableDlgControl(hwndDlg, IDC_LOG, FALSE);
+ } else {
+#if defined(__FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER)
+ if (iLogMode != WANT_IEVIEW_LOG)
+ CheckAndDestroyIEView(dat);
+ if (iLogMode != WANT_HPP_LOG)
+ CheckAndDestroyHPP(dat);
+ Utils::showDlgControl(hwndDlg, IDC_LOG, SW_SHOW);
+ Utils::enableDlgControl(hwndDlg, IDC_LOG, TRUE);
+ dat->hwndIEView = 0;
+ dat->hwndIWebBrowserControl = 0;
+ dat->hwndHPP = 0;
+#endif
+ }
+}
+
+#if defined(__FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER)
+void TSAPI SwitchMessageLog(TWindowData *dat, int iMode)
+{
+ HWND hwndDlg = dat->hwnd;
+
+ if (iMode) { // switch from rtf to IEview or hpp
+ SetDlgItemText(hwndDlg, IDC_LOG, _T(""));
+ Utils::enableDlgControl(hwndDlg, IDC_LOG, FALSE);
+ Utils::showDlgControl(hwndDlg, IDC_LOG, SW_HIDE);
+ SetMessageLog(dat);
+ } else // switch from IEView or hpp to rtf
+ SetMessageLog(dat);
+
+ SetDialogToType(hwndDlg);
+ SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+
+ if (dat->hwndIEView) {
+ if (M->GetByte("subclassIEView", 0)&&dat->oldIEViewProc == 0) {
+ WNDPROC wndProc = (WNDPROC)SetWindowLongPtr(dat->hwndIEView, GWLP_WNDPROC, (LONG_PTR)IEViewSubclassProc);
+ dat->oldIEViewProc = wndProc;
+ }
+ } else if (dat->hwndHPP) {
+ if (dat->oldIEViewProc == 0) {
+ WNDPROC wndProc = (WNDPROC)SetWindowLongPtr(dat->hwndHPP, GWLP_WNDPROC, (LONG_PTR)HPPKFSubclassProc);
+ dat->oldIEViewProc = wndProc;
+ }
+ }
+}
+#endif
+
+void TSAPI FindFirstEvent(TWindowData *dat)
+{
+ int historyMode = (int)M->GetByte(dat->hContact, SRMSGMOD, SRMSGSET_LOADHISTORY, -1);
+ if (historyMode == -1)
+ historyMode = (int)M->GetByte(SRMSGMOD, SRMSGSET_LOADHISTORY, SRMSGDEFSET_LOADHISTORY);
+
+ dat->hDbEventFirst = (HANDLE) CallService(MS_DB_EVENT_FINDFIRSTUNREAD, (WPARAM) dat->hContact, 0);
+
+ if(dat->bActualHistory)
+ historyMode = LOADHISTORY_COUNT;
+
+ switch (historyMode) {
+ case LOADHISTORY_COUNT: {
+ int i;
+ HANDLE hPrevEvent;
+ DBEVENTINFO dbei = { 0};
+ dbei.cbSize = sizeof(dbei);
+ //MAD: ability to load only current session's history
+ if (dat->bActualHistory)
+ i = dat->cache->getSessionMsgCount();
+ else
+ i = DBGetContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADCOUNT, SRMSGDEFSET_LOADCOUNT);
+ //
+ for (; i > 0; i--) {
+ if (dat->hDbEventFirst == NULL)
+ hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) dat->hContact, 0);
+ else
+ hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDPREV, (WPARAM) dat->hDbEventFirst, 0);
+ if (hPrevEvent == NULL)
+ break;
+ dbei.cbBlob = 0;
+ dat->hDbEventFirst = hPrevEvent;
+ CallService(MS_DB_EVENT_GET, (WPARAM) dat->hDbEventFirst, (LPARAM) & dbei);
+ if (!DbEventIsShown(dat, &dbei))
+ i++;
+ }
+ break;
+ }
+ case LOADHISTORY_TIME: {
+ HANDLE hPrevEvent;
+ DBEVENTINFO dbei = { 0};
+ DWORD firstTime;
+
+ dbei.cbSize = sizeof(dbei);
+ if (dat->hDbEventFirst == NULL)
+ dbei.timestamp = time(NULL);
+ else
+ CallService(MS_DB_EVENT_GET, (WPARAM) dat->hDbEventFirst, (LPARAM) & dbei);
+ firstTime = dbei.timestamp - 60 * DBGetContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADTIME, SRMSGDEFSET_LOADTIME);
+ for (;;) {
+ if (dat->hDbEventFirst == NULL)
+ hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) dat->hContact, 0);
+ else
+ hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDPREV, (WPARAM) dat->hDbEventFirst, 0);
+ if (hPrevEvent == NULL)
+ break;
+ dbei.cbBlob = 0;
+ CallService(MS_DB_EVENT_GET, (WPARAM) hPrevEvent, (LPARAM) & dbei);
+ if (dbei.timestamp < firstTime)
+ break;
+ dat->hDbEventFirst = hPrevEvent;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+void TSAPI SaveSplitter(TWindowData *dat)
+{
+ /*
+ * group chats save their normal splitter position independently
+ */
+
+ if(dat->bType == SESSIONTYPE_CHAT)
+ return;
+
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ if(dat->fIsAutosizingInput)
+ return;
+#endif
+ if (dat->splitterY < DPISCALEY_S(MINSPLITTERY) || dat->splitterY < 0)
+ dat->splitterY = DPISCALEY_S(MINSPLITTERY);
+
+ if (dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE)
+ M->WriteDword(dat->hContact, SRMSGMOD_T, "splitsplity", dat->splitterY);
+ else {
+ if(dat->pContainer->settings->fPrivate)
+ dat->pContainer->settings->splitterPos = dat->splitterY;
+ else
+ M->WriteDword(SRMSGMOD_T, "splitsplity", dat->splitterY);
+ }
+}
+
+void TSAPI LoadSplitter(TWindowData *dat)
+{
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ if (dat->fIsAutosizingInput) {
+ dat->splitterY = GetDefaultMinimumInputHeight(dat);
+ return;
+ }
+#endif
+ if (!(dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE))
+ if(!dat->pContainer->settings->fPrivate)
+ dat->splitterY = (int)M->GetDword("splitsplity", (DWORD) 60);
+ else
+ dat->splitterY = dat->pContainer->settings->splitterPos;
+ else
+ dat->splitterY = (int)M->GetDword(dat->hContact, "splitsplity", M->GetDword("splitsplity", (DWORD) 70));
+
+ if (dat->splitterY < MINSPLITTERY || dat->splitterY < 0)
+ dat->splitterY = 150;
+}
+
+void TSAPI PlayIncomingSound(const TWindowData *dat)
+{
+ int iPlay = Utils::mustPlaySound(dat);
+
+ if (iPlay) {
+ if (GetForegroundWindow() == dat->pContainer->hwnd && dat->pContainer->hwndActive == dat->hwnd)
+ SkinPlaySound("RecvMsgActive");
+ else
+ SkinPlaySound("RecvMsgInactive");
+ }
+}
+
+/*
+ * reads send format and configures the toolbar buttons
+ * if mode == 0, int only configures the buttons and does not change send format
+ */
+
+void TSAPI GetSendFormat(TWindowData *dat, int mode)
+{
+ UINT controls[5] = {IDC_FONTBOLD, IDC_FONTITALIC, IDC_FONTUNDERLINE,IDC_FONTSTRIKEOUT, IDC_FONTFACE};
+ int i;
+
+ if (mode) {
+ dat->SendFormat = M->GetDword(dat->hContact, "sendformat", PluginConfig.m_SendFormat);
+ if (dat->SendFormat == -1) // per contact override to disable it..
+ dat->SendFormat = 0;
+ else if (dat->SendFormat == 0)
+ dat->SendFormat = PluginConfig.m_SendFormat ? 1 : 0;
+ }
+ for (i = 0; i < 5; i++)
+ Utils::enableDlgControl(dat->hwnd, controls[i], dat->SendFormat != 0 ? TRUE : FALSE);
+ return;
+}
+
+/*
+ * get user-readable locale information for the currently selected
+ * keyboard layout.
+ *
+ * GetLocaleInfo() should no longer be used on Vista and later
+ */
+
+void TSAPI GetLocaleID(TWindowData *dat, const TCHAR *szKLName)
+{
+ TCHAR szLI[256], *stopped = NULL;
+ USHORT langID;
+ WORD wCtype2[3];
+ PARAFORMAT2 pf2;
+ BOOL fLocaleNotSet;
+ char szTest[4] = {(char)0xe4, (char)0xf6, (char)0xfc, 0 };
+
+ szLI[0] = szLI[1] = 0;
+
+ ZeroMemory(&pf2, sizeof(PARAFORMAT2));
+ langID = (USHORT)_tcstol(szKLName, &stopped, 16);
+ dat->lcid = MAKELCID(langID, 0);
+ /*
+ * Vista+: read ISO locale names from the registry
+ */
+ if(PluginConfig.m_bIsVista) {
+ HKEY hKey = 0;
+ TCHAR szKey[20];
+ DWORD dwLID = _tcstoul(szKLName, &stopped, 16);
+
+ mir_sntprintf(szKey, 20, _T("%04.04x"), LOWORD(dwLID));
+ if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, _T("MIME\\Database\\Rfc1766"), 0, KEY_READ, &hKey)) {
+ DWORD dwLength = 255;
+ if(ERROR_SUCCESS == RegQueryValueEx(hKey, szKey, 0, 0, (unsigned char *)szLI, &dwLength)) {
+ TCHAR* p;
+
+ szLI[255] = 0;
+ if((p = _tcschr(szLI, ';')) != 0)
+ *p = 0;
+ }
+ RegCloseKey(hKey);
+ }
+ szLI[0] = _totupper(szLI[0]);
+ szLI[1] = _totupper(szLI[1]);
+ }
+ else {
+ GetLocaleInfo(dat->lcid, LOCALE_SISO639LANGNAME, szLI, 10);
+ _tcsupr(szLI);
+ }
+ fLocaleNotSet = (dat->lcID[0] == 0 && dat->lcID[1] == 0);
+ mir_sntprintf(dat->lcID, safe_sizeof(dat->lcID), szLI);
+ GetStringTypeA(dat->lcid, CT_CTYPE2, szTest, 3, wCtype2);
+ pf2.cbSize = sizeof(pf2);
+ pf2.dwMask = PFM_RTLPARA;
+ SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_GETPARAFORMAT, 0, (LPARAM)&pf2);
+ if (Utils::FindRTLLocale(dat) && fLocaleNotSet) {
+ if (wCtype2[0] == C2_RIGHTTOLEFT || wCtype2[1] == C2_RIGHTTOLEFT || wCtype2[2] == C2_RIGHTTOLEFT) {
+ ZeroMemory(&pf2, sizeof(pf2));
+ pf2.dwMask = PFM_RTLPARA;
+ pf2.cbSize = sizeof(pf2);
+ pf2.wEffects = PFE_RTLPARA;
+ SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+ } else {
+ ZeroMemory(&pf2, sizeof(pf2));
+ pf2.dwMask = PFM_RTLPARA;
+ pf2.cbSize = sizeof(pf2);
+ pf2.wEffects = 0;
+ SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+ }
+ SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_SETLANGOPTIONS, 0, (LPARAM) SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
+ }
+}
+
+void TSAPI LoadContactAvatar(TWindowData *dat)
+{
+ if(dat)
+ dat->ace = Utils::loadAvatarFromAVS(dat->hContact);
+
+ if (dat && (!(dat->Panel->isActive()) || dat->pContainer->avatarMode == 3)) {
+ BITMAP bm;
+ dat->iRealAvatarHeight = 0;
+
+ if (dat->ace && dat->ace->hbmPic) {
+ AdjustBottomAvatarDisplay(dat);
+ GetObject(dat->ace->hbmPic, sizeof(bm), &bm);
+ CalcDynamicAvatarSize(dat, &bm);
+ PostMessage(dat->hwnd, WM_SIZE, 0, 0);
+ } else if (dat->ace == NULL) {
+ AdjustBottomAvatarDisplay(dat);
+ GetObject(PluginConfig.g_hbmUnknown, sizeof(bm), &bm);
+ CalcDynamicAvatarSize(dat, &bm);
+ PostMessage(dat->hwnd, WM_SIZE, 0, 0);
+ }
+ }
+}
+
+void TSAPI LoadOwnAvatar(TWindowData *dat)
+{
+ AVATARCACHEENTRY *ace = NULL;
+
+ if (ServiceExists(MS_AV_GETMYAVATAR))
+ ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)(dat->cache->getActiveProto()));
+
+ if (ace) {
+ dat->hOwnPic = ace->hbmPic;
+ dat->ownAce = ace;
+ } else {
+ dat->hOwnPic = PluginConfig.g_hbmUnknown;
+ dat->ownAce = NULL;
+ }
+ if (dat->Panel->isActive() && dat->pContainer->avatarMode != 3) {
+ BITMAP bm;
+
+ dat->iRealAvatarHeight = 0;
+ AdjustBottomAvatarDisplay(dat);
+ GetObject(dat->hOwnPic, sizeof(bm), &bm);
+ CalcDynamicAvatarSize(dat, &bm);
+ SendMessage(dat->hwnd, WM_SIZE, 0, 0);
+ }
+}
+
+void TSAPI LoadTimeZone(TWindowData *dat)
+{
+ if (dat)
+ dat->hTimeZone = tmi.createByContact ? tmi.createByContact(dat->hContact, TZF_KNOWNONLY) : 0;
+}
+
+/*
+ * paste contents of the clipboard into the message input area and send it immediately
+ */
+
+void TSAPI HandlePasteAndSend(const TWindowData *dat)
+{
+ UINT ctrlID = dat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE;
+
+ if (!PluginConfig.m_PasteAndSend) {
+ SendMessage(dat->hwnd, DM_ACTIVATETOOLTIP, ctrlID, (LPARAM)CTranslator::get(CTranslator::GEN_WARNING_PASTEANDSEND_DISABLED));
+ return; // feature disabled
+ }
+
+ SendMessage(GetDlgItem(dat->hwnd, ctrlID), EM_PASTESPECIAL, CF_TEXTT, 0);
+ if (GetWindowTextLengthA(GetDlgItem(dat->hwnd, ctrlID)) > 0)
+ SendMessage(dat->hwnd, WM_COMMAND, IDOK, 0);
+}
+
+/*
+ * draw various elements of the message window, like avatar(s), info panel fields
+ * and the color formatting menu
+ */
+
+int TSAPI MsgWindowDrawHandler(WPARAM wParam, LPARAM lParam, TWindowData *dat)
+{
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT) lParam;
+
+ if (!dat)
+ return 0;
+
+ bool fAero = M->isAero();
+ HWND hwndDlg = dat->hwnd;
+
+ if (dis->CtlType == ODT_MENU && dis->hwndItem == (HWND)GetSubMenu(PluginConfig.g_hMenuContext, 7)) {
+ RECT rc = { 0 };
+ HBRUSH old, col;
+ COLORREF clr;
+ switch (dis->itemID) {
+ case ID_FONT_RED:
+ clr = RGB(255, 0, 0);
+ break;
+ case ID_FONT_BLUE:
+ clr = RGB(0, 0, 255);
+ break;
+ case ID_FONT_GREEN:
+ clr = RGB(0, 255, 0);
+ break;
+ case ID_FONT_MAGENTA:
+ clr = RGB(255, 0, 255);
+ break;
+ case ID_FONT_YELLOW:
+ clr = RGB(255, 255, 0);
+ break;
+ case ID_FONT_WHITE:
+ clr = RGB(255, 255, 255);
+ break;
+ case ID_FONT_DEFAULTCOLOR:
+ clr = GetSysColor(COLOR_MENU);
+ break;
+ case ID_FONT_CYAN:
+ clr = RGB(0, 255, 255);
+ break;
+ case ID_FONT_BLACK:
+ clr = RGB(0, 0, 0);
+ break;
+ default:
+ clr = 0;
+ }
+ col = (HBRUSH)CreateSolidBrush(clr);
+ old = (HBRUSH)SelectObject(dis->hDC, col);
+ rc.left = 2;
+ rc.top = dis->rcItem.top - 5;
+ rc.right = 15;
+ rc.bottom = dis->rcItem.bottom + 4;
+ Rectangle(dis->hDC, rc.left - 1, rc.top - 1, rc.right + 1, rc.bottom + 1);
+ FillRect(dis->hDC, &rc, col);
+ SelectObject(dis->hDC, old);
+ DeleteObject(col);
+ return TRUE;
+ }
+ else if ((dis->hwndItem == GetDlgItem(hwndDlg, IDC_CONTACTPIC) && (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown) && dat->showPic) || (dis->hwndItem == hwndDlg && dat->Panel->isActive() && (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown))) {
+ HBRUSH hOldBrush;
+ BITMAP bminfo;
+ double dAspect = 0, dNewWidth = 0, dNewHeight = 0;
+ DWORD iMaxHeight = 0, top, cx, cy;
+ RECT rc, rcClient, rcFrame;
+ HDC hdcDraw;
+ HBITMAP hbmDraw, hbmOld;
+ BOOL bPanelPic = dis->hwndItem == hwndDlg;
+ DWORD aceFlags = 0;
+ HPEN hPenBorder = 0, hPenOld = 0;
+ HRGN clipRgn = 0;
+ int iRad = PluginConfig.m_WinVerMajor >= 5 ? 4 : 6;
+ BOOL flashAvatar = FALSE;
+ bool fInfoPanel = dat->Panel->isActive();
+
+ if (PluginConfig.g_FlashAvatarAvail && (!bPanelPic || (bPanelPic && dat->showInfoPic == 1))) {
+ FLASHAVATAR fa = {0};
+
+ fa.id = 25367;
+ fa.cProto = dat->szProto;
+ if (!bPanelPic && fInfoPanel) {
+ fa.hParentWindow = GetDlgItem(hwndDlg, IDC_CONTACTPIC);
+ CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0);
+ Utils::enableDlgControl(hwndDlg, IDC_CONTACTPIC, fa.hWindow != 0);
+ } else {
+ fa.hContact = dat->hContact;
+ fa.hParentWindow = fInfoPanel ? dat->hwndPanelPicParent : GetDlgItem(hwndDlg, IDC_CONTACTPIC);
+ CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0);
+ if (fInfoPanel) {
+ if (fa.hWindow != NULL&&dat->hwndPanelPic) {
+ DestroyWindow(dat->hwndPanelPic);
+ dat->hwndPanelPic = NULL;
+ }
+ if (!PluginConfig.g_bDisableAniAvatars && fa.hWindow == 0 && dat->hwndPanelPic == 0) {
+ dat->hwndPanelPic = CreateWindowEx(WS_EX_TOPMOST, AVATAR_CONTROL_CLASS, _T(""), WS_VISIBLE | WS_CHILD, 1, 1, 1, 1, dat->hwndPanelPicParent, (HMENU)7000, NULL, NULL);
+ SendMessage(dat->hwndPanelPic, AVATAR_SETCONTACT, (WPARAM)0, (LPARAM)dat->hContact);
+ }
+ } else {
+ if (fa.hWindow != NULL && dat->hwndContactPic) {
+ DestroyWindow(dat->hwndContactPic);
+ dat->hwndContactPic = NULL;
+ }
+ if(!PluginConfig.g_bDisableAniAvatars && fa.hWindow == 0 && dat->hwndContactPic == 0) {
+ dat->hwndContactPic =CreateWindowEx(WS_EX_TOPMOST, AVATAR_CONTROL_CLASS, _T(""), WS_VISIBLE | WS_CHILD, 1, 1, 1, 1, GetDlgItem(hwndDlg, IDC_CONTACTPIC), (HMENU)0, NULL, NULL);
+ SendMessage(dat->hwndContactPic, AVATAR_SETCONTACT, (WPARAM)0, (LPARAM)dat->hContact);
+ }
+ }
+ dat->hwndFlash = fa.hWindow;
+ }
+ if (fa.hWindow != 0) {
+ bminfo.bmHeight = FAVATAR_HEIGHT;
+ bminfo.bmWidth = FAVATAR_WIDTH;
+ CallService(MS_FAVATAR_SETBKCOLOR, (WPARAM)&fa, (LPARAM)GetSysColor(COLOR_3DFACE));
+ flashAvatar = TRUE;
+ }
+ }
+
+ if (bPanelPic) {
+ if (!flashAvatar) {
+ GetObject(dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown, sizeof(bminfo), &bminfo);
+ }
+ if ((dat->ace && dat->showInfoPic && !(dat->ace->dwFlags & AVS_HIDEONCLIST)) || dat->showInfoPic)
+ aceFlags = dat->ace ? dat->ace->dwFlags : 0;
+ else {
+ if (dat->panelWidth) {
+ dat->panelWidth = -1;
+ if(!CSkin::m_skinEnabled)
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ }
+ return TRUE;
+ }
+ } else {
+ if (!fInfoPanel || dat->pContainer->avatarMode == 3) {
+ if (dat->ace)
+ aceFlags = dat->ace->dwFlags;
+ } else if (dat->ownAce)
+ aceFlags = dat->ownAce->dwFlags;
+
+ GetObject((fInfoPanel && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown), sizeof(bminfo), &bminfo);
+ }
+
+ GetClientRect(hwndDlg, &rc);
+ if(bPanelPic) {
+ rcClient = dis->rcItem;
+ cx = (rcClient.right - rcClient.left);
+ cy = (rcClient.bottom - rcClient.top) + 1;
+ } else {
+ GetClientRect(dis->hwndItem, &rcClient);
+ cx = rcClient.right;
+ cy = rcClient.bottom;
+ }
+
+ if (cx < 5 || cy < 5)
+ return TRUE;
+
+ if (bPanelPic) {
+ if (bminfo.bmHeight > bminfo.bmWidth) {
+ if (bminfo.bmHeight > 0)
+ dAspect = (double)(cy /*- 2*/) / (double)bminfo.bmHeight;
+ else
+ dAspect = 1.0;
+ dNewWidth = (double)bminfo.bmWidth * dAspect;
+ dNewHeight = cy;// - 2;
+ } else {
+ if (bminfo.bmWidth > 0)
+ dAspect = (double)(cy /*- 2*/) / (double)bminfo.bmWidth;
+ else
+ dAspect = 1.0;
+ dNewHeight = (double)bminfo.bmHeight * dAspect;
+ dNewWidth = cy;// - 2;
+ }
+ if (dat->panelWidth == -1) {
+ dat->panelWidth = (int)dNewWidth;
+ return(0);
+ }
+ } else {
+
+ if (bminfo.bmHeight > 0)
+ dAspect = (double)dat->iRealAvatarHeight / (double)bminfo.bmHeight;
+ else
+ dAspect = 1.0;
+ dNewWidth = (double)bminfo.bmWidth * dAspect;
+ if (dNewWidth > (double)(rc.right) * 0.8)
+ dNewWidth = (double)(rc.right) * 0.8;
+ iMaxHeight = dat->iRealAvatarHeight;
+ }
+
+ if (flashAvatar) {
+ SetWindowPos(dat->hwndPanelPicParent, HWND_TOP, rcClient.left, rcClient.top,
+ (int)dNewWidth, (int)dNewHeight, SWP_SHOWWINDOW | SWP_NOCOPYBITS);
+ return TRUE;
+ }
+
+ hdcDraw = CreateCompatibleDC(dis->hDC);
+ hbmDraw = CreateCompatibleBitmap(dis->hDC, cx, cy);
+ hbmOld = (HBITMAP)SelectObject(hdcDraw, hbmDraw);
+
+ bool fAero = M->isAero();
+
+ hOldBrush = (HBRUSH)SelectObject(hdcDraw, fAero ? (HBRUSH)GetStockObject(HOLLOW_BRUSH) : GetSysColorBrush(COLOR_3DFACE));
+ rcFrame = rcClient;
+
+ if (!bPanelPic) {
+ top = (cy - dat->pic.cy) / 2;
+ RECT rcEdge = {0, top, dat->pic.cx, top + dat->pic.cy};
+ if (CSkin::m_skinEnabled)
+ CSkin::SkinDrawBG(dis->hwndItem, dat->pContainer->hwnd, dat->pContainer, &dis->rcItem, hdcDraw);
+ else if (PluginConfig.m_fillColor) {
+ HBRUSH br = CreateSolidBrush(PluginConfig.m_fillColor);
+ FillRect(hdcDraw, &rcFrame, br);
+ DeleteObject(br);
+ }
+ else {
+ if(fAero && CSkin::m_pCurrentAeroEffect) {
+ COLORREF clr = PluginConfig.m_tbBackgroundHigh ? PluginConfig.m_tbBackgroundHigh :
+ (CSkin::m_pCurrentAeroEffect ? CSkin::m_pCurrentAeroEffect->m_clrToolbar : 0xf0f0f0);
+
+ HBRUSH br = CreateSolidBrush(clr);
+ FillRect(hdcDraw, &rcFrame, br);
+ DeleteObject(br);
+ }
+ else
+ FillRect(hdcDraw, &rcFrame, GetSysColorBrush(COLOR_3DFACE));
+ }
+
+ hPenBorder = CreatePen(PS_SOLID, 1, CSkin::m_avatarBorderClr);
+ hPenOld = (HPEN)SelectObject(hdcDraw, hPenBorder);
+
+ if (CSkin::m_bAvatarBorderType == 1)
+ Rectangle(hdcDraw, rcEdge.left, rcEdge.top, rcEdge.right, rcEdge.bottom);
+ else if (CSkin::m_bAvatarBorderType == 2) {
+ clipRgn = CreateRoundRectRgn(rcEdge.left, rcEdge.top, rcEdge.right + 1, rcEdge.bottom + 1, iRad, iRad);
+ SelectClipRgn(hdcDraw, clipRgn);
+ }
+ }
+
+ if ((((fInfoPanel && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown)) && dat->showPic) || bPanelPic) {
+ HDC hdcMem = CreateCompatibleDC(dis->hDC);
+ HBITMAP hbmAvatar = bPanelPic ? (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown) : ((fInfoPanel && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown));
+ HBITMAP hbmMem = 0;
+ if (bPanelPic) {
+ bool bBorder = (CSkin::m_bAvatarBorderType ? true : false);
+
+ LONG height_off = 0;
+ LONG border_off = bBorder ? 1 : 0;
+
+ ResizeBitmap rb;
+ rb.size = sizeof(rb);
+ rb.fit = RESIZEBITMAP_STRETCH;
+ rb.max_height = (int)(dNewHeight - (bBorder ? 2 : 0));
+ rb.max_width = (int)(dNewWidth - (bBorder ? 2 : 0));
+ rb.hBmp = hbmAvatar;
+
+ HBITMAP hbmNew = (HBITMAP)CallService("IMG/ResizeBitmap", (WPARAM)&rb, 0);
+ hbmMem = (HBITMAP)SelectObject(hdcMem, hbmNew);
+
+ rcFrame.left = rcFrame.top = 0;
+ rcFrame.right = (rcClient.right - rcClient.left);
+ rcFrame.bottom = (rcClient.bottom - rcClient.top);
+
+ rcFrame.left = rcFrame.right - (LONG)dNewWidth;
+ rcFrame.bottom = (LONG)dNewHeight;
+
+ height_off = ((cy) - (rb.max_height + (bBorder ? 2 : 0))) / 2;
+ rcFrame.top += height_off;
+ rcFrame.bottom += height_off;
+
+ /*
+ * prepare border drawing (if avatar is rendered by ACC, the parent control will be responsible for
+ * the border, so skip it here)
+ */
+ if(dat->hwndPanelPic == 0) {
+ OffsetRect(&rcClient, -2, 0);
+ if (CSkin::m_bAvatarBorderType == 1)
+ clipRgn = CreateRectRgn(rcClient.left + rcFrame.left, rcClient.top + rcFrame.top, rcClient.left + rcFrame.right,
+ rcClient.top + rcFrame.bottom);
+ else if (CSkin::m_bAvatarBorderType == 2) {
+ clipRgn = CreateRoundRectRgn(rcClient.left + rcFrame.left, rcClient.top + rcFrame.top, rcClient.left + rcFrame.right + 1,
+ rcClient.top + rcFrame.bottom + 1, iRad, iRad);
+ SelectClipRgn(dis->hDC, clipRgn);
+ }
+ }
+
+ if(dat->hwndPanelPic) {
+ /*
+ * paint avatar using ACC
+ */
+ SendMessage(dat->hwndPanelPic, AVATAR_SETAEROCOMPATDRAWING, 0, fAero ? TRUE : FALSE);
+ SetWindowPos(dat->hwndPanelPic, HWND_TOP, rcFrame.left + border_off, rcFrame.top + border_off,
+ rb.max_width, rb.max_height, SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS | SWP_DEFERERASE | SWP_NOSENDCHANGING);
+ }
+ else {
+ if(CMimAPI::m_MyAlphaBlend) {
+ CMimAPI::m_MyAlphaBlend(dis->hDC, rcClient.left + rcFrame.left + border_off, rcClient.top + rcFrame.top + border_off,
+ rb.max_width, rb.max_height, hdcMem, 0, 0,
+ rb.max_width, rb.max_height, CSkin::m_default_bf);
+ }
+ else
+ CSkin::MY_AlphaBlend(dis->hDC, rcClient.left + rcFrame.left + border_off, rcClient.top + rcFrame.top + border_off,
+ rb.max_width, rb.max_height, rb.max_width, rb.max_height, hdcMem);
+ }
+ SelectObject(hdcMem, hbmMem);
+ //DeleteObject(hbmMem);
+ DeleteDC(hdcMem);
+ if(hbmNew != hbmAvatar)
+ DeleteObject(hbmNew);
+ } else {
+ hbmMem = (HBITMAP)SelectObject(hdcMem, hbmAvatar);
+ LONG xy_off = 1; //CSkin::m_bAvatarBorderType ? 1 : 0;
+ LONG width_off = 0; //= CSkin::m_bAvatarBorderType ? 0 : 2;
+
+ SetStretchBltMode(hdcDraw, HALFTONE);
+ if (aceFlags & AVS_PREMULTIPLIED)
+ CSkin::MY_AlphaBlend(hdcDraw, xy_off, top + xy_off, (int)dNewWidth + width_off,
+ iMaxHeight + width_off, bminfo.bmWidth, bminfo.bmHeight, hdcMem);
+ else
+ StretchBlt(hdcDraw, xy_off, top + xy_off, (int)dNewWidth + width_off,
+ iMaxHeight + width_off, hdcMem, 0, 0, bminfo.bmWidth, bminfo.bmHeight, SRCCOPY);
+ //_DebugTraceA("metrics: %d, %d %d, %d", (int)dNewWidth + width_off, iMaxHeight + width_off, bminfo.bmWidth, bminfo.bmHeight);
+ SelectObject(hdcMem, hbmMem);
+ DeleteObject(hbmMem);
+ DeleteDC(hdcMem);
+ }
+ if (clipRgn) {
+ HBRUSH hbr = CreateSolidBrush(CSkin::m_avatarBorderClr);
+ if(bPanelPic)
+ FrameRgn(dis->hDC, clipRgn, hbr, 1, 1);
+ else
+ FrameRgn(hdcDraw, clipRgn, hbr, 1, 1);
+ DeleteObject(hbr);
+ DeleteObject(clipRgn);
+ }
+ }
+ SelectObject(hdcDraw, hPenOld);
+ SelectObject(hdcDraw, hOldBrush);
+ DeleteObject(hPenBorder);
+ if(!bPanelPic)
+ BitBlt(dis->hDC, 0, 0, cx, cy, hdcDraw, 0, 0, SRCCOPY);
+ SelectObject(hdcDraw, hbmOld);
+ DeleteObject(hbmDraw);
+ DeleteDC(hdcDraw);
+ return TRUE;
+ } else if (dis->hwndItem == GetDlgItem(hwndDlg, IDC_STATICTEXT) || dis->hwndItem == GetDlgItem(hwndDlg, IDC_LOGFROZENTEXT)) {
+ TCHAR szWindowText[256];
+ if (CSkin::m_skinEnabled) {
+ SetTextColor(dis->hDC, CSkin::m_DefaultFontColor);
+ CSkin::SkinDrawBG(dis->hwndItem, dat->pContainer->hwnd, dat->pContainer, &dis->rcItem, dis->hDC);
+ } else {
+ SetTextColor(dis->hDC, GetSysColor(COLOR_BTNTEXT));
+ CSkin::FillBack(dis->hDC, &dis->rcItem);
+ }
+ GetWindowText(dis->hwndItem, szWindowText, 255);
+ szWindowText[255] = 0;
+ SetBkMode(dis->hDC, TRANSPARENT);
+ DrawText(dis->hDC, szWindowText, -1, &dis->rcItem, DT_SINGLELINE | DT_VCENTER | DT_NOCLIP | DT_END_ELLIPSIS);
+ return TRUE;
+ } else if (dis->hwndItem == GetDlgItem(hwndDlg, IDC_STATICERRORICON)) {
+ if (CSkin::m_skinEnabled)
+ CSkin::SkinDrawBG(dis->hwndItem, dat->pContainer->hwnd, dat->pContainer, &dis->rcItem, dis->hDC);
+ else
+ CSkin::FillBack(dis->hDC, &dis->rcItem);
+ DrawIconEx(dis->hDC, (dis->rcItem.right - dis->rcItem.left) / 2 - 8, (dis->rcItem.bottom - dis->rcItem.top) / 2 - 8,
+ PluginConfig.g_iconErr, 16, 16, 0, 0, DI_NORMAL);
+ return TRUE;
+ }
+ else if (dis->CtlType == ODT_MENU && dat->Panel->isHovered()) {
+ DrawMenuItem(dis, (HICON)dis->itemData, 0);
+ return(TRUE);
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+}
+
+void TSAPI LoadThemeDefaults(TContainerData *pContainer)
+{
+ int i;
+ char szTemp[40];
+ COLORREF colour;
+ ZeroMemory(&pContainer->theme, sizeof(TLogTheme));
+
+ pContainer->theme.bg = M->GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR, GetSysColor(COLOR_WINDOW));
+ pContainer->theme.statbg = PluginConfig.crStatus;
+ pContainer->theme.oldinbg = PluginConfig.crOldIncoming;
+ pContainer->theme.oldoutbg = PluginConfig.crOldOutgoing;
+ pContainer->theme.inbg = PluginConfig.crIncoming;
+ pContainer->theme.outbg = PluginConfig.crOutgoing;
+ pContainer->theme.hgrid = M->GetDword(FONTMODULE, "hgrid", RGB(224, 224, 224));
+ pContainer->theme.left_indent = M->GetDword("IndentAmount", 20) * 15;
+ pContainer->theme.right_indent = M->GetDword("RightIndent", 20) * 15;
+ pContainer->theme.inputbg = M->GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR);
+
+ for (i = 1; i <= 5; i++) {
+ _snprintf(szTemp, 10, "cc%d", i);
+ colour = M->GetDword(szTemp, RGB(224, 224, 224));
+ if (colour == 0)
+ colour = RGB(1, 1, 1);
+ pContainer->theme.custom_colors[i - 1] = colour;
+ }
+ pContainer->theme.logFonts = logfonts;
+ pContainer->theme.fontColors = fontcolors;
+ pContainer->theme.rtfFonts = NULL;
+ pContainer->ltr_templates = &LTR_Active;
+ pContainer->rtl_templates = &RTL_Active;
+ pContainer->theme.dwFlags = (M->GetDword("mwflags", MWF_LOG_DEFAULT) & MWF_LOG_ALL);
+ pContainer->theme.isPrivate = false;
+}
+
+void TSAPI LoadOverrideTheme(TContainerData *pContainer)
+{
+ ZeroMemory(&pContainer->theme, sizeof(TLogTheme));
+
+ BOOL bReadTemplates = TRUE; //((pContainer->ltr_templates == NULL) || (pContainer->rtl_templates == NULL) ||
+ //(pContainer->logFonts == NULL) || (pContainer->fontColors == NULL));
+
+ if (lstrlen(pContainer->szAbsThemeFile) > 1) {
+ if (PathFileExists(pContainer->szAbsThemeFile)) {
+ if (CheckThemeVersion(pContainer->szAbsThemeFile) == 0) {
+ LoadThemeDefaults(pContainer);
+ return;
+ }
+ if (pContainer->ltr_templates == NULL) {
+ pContainer->ltr_templates = (TTemplateSet *)malloc(sizeof(TTemplateSet));
+ CopyMemory(pContainer->ltr_templates, &LTR_Active, sizeof(TTemplateSet));
+ }
+ if (pContainer->rtl_templates == NULL) {
+ pContainer->rtl_templates = (TTemplateSet *)malloc(sizeof(TTemplateSet));
+ CopyMemory(pContainer->rtl_templates, &RTL_Active, sizeof(TTemplateSet));
+ }
+
+ pContainer->theme.logFonts = (LOGFONTA *)malloc(sizeof(LOGFONTA) * (MSGDLGFONTCOUNT + 2));
+ pContainer->theme.fontColors = (COLORREF *)malloc(sizeof(COLORREF) * (MSGDLGFONTCOUNT + 2));
+ pContainer->theme.rtfFonts = (char *)malloc((MSGDLGFONTCOUNT + 2) * RTFCACHELINESIZE);
+
+ ReadThemeFromINI(pContainer->szAbsThemeFile, pContainer, bReadTemplates ? 0 : 1, THEME_READ_ALL);
+ pContainer->theme.left_indent *= 15;
+ pContainer->theme.right_indent *= 15;
+ pContainer->theme.isPrivate = true;
+ if(CSkin::m_skinEnabled)
+ pContainer->theme.bg = SkinItems[ID_EXTBKCONTAINER].COLOR;
+ else
+ pContainer->theme.bg = PluginConfig.m_fillColor ? PluginConfig.m_fillColor : GetSysColor(COLOR_WINDOW);
+ return;
+ }
+ }
+ LoadThemeDefaults(pContainer);
+}
+
+void TSAPI ConfigureSmileyButton(TWindowData *dat)
+{
+ HWND hwndDlg = dat->hwnd;
+ int nrSmileys = 0;
+ int showToolbar = dat->pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1;
+ int iItemID = IDC_SMILEYBTN;
+
+ if (PluginConfig.g_SmileyAddAvail) {
+ nrSmileys = CheckValidSmileyPack(dat->cache->getActiveProto(), dat->cache->getActiveContact());
+ dat->doSmileys = 1;
+ }
+
+ if (nrSmileys == 0 || dat->hContact == 0)
+ dat->doSmileys = 0;
+
+ Utils::showDlgControl(hwndDlg, iItemID, (dat->doSmileys && showToolbar) ? SW_SHOW : SW_HIDE);
+ Utils::enableDlgControl(hwndDlg, iItemID, dat->doSmileys ? TRUE : FALSE);
+}
+
+HICON TSAPI GetXStatusIcon(const TWindowData *dat)
+{
+ char szServiceName[128];
+ BYTE xStatus = dat->cache->getXStatusId();
+
+ mir_snprintf(szServiceName, 128, "%s/GetXStatusIcon", dat->cache->getActiveProto());
+
+ if (ServiceExists(szServiceName) && xStatus > 0 && xStatus <= 32)
+ return (HICON)(CallProtoService(dat->cache->getActiveProto(), "/GetXStatusIcon", xStatus, 0));
+ return 0;
+}
+
+LRESULT TSAPI GetSendButtonState(HWND hwnd)
+{
+ HWND hwndIDok=GetDlgItem(hwnd, IDOK);
+
+ if(hwndIDok)
+ return(SendMessage(hwndIDok, BUTTONSETASFLATBTN + 15, 0, 0));
+ else
+ return 0;
+}
+
+void TSAPI EnableSendButton(const TWindowData *dat, int iMode)
+{
+ HWND hwndOK;
+ SendMessage(GetDlgItem(dat->hwnd, IDOK), BUTTONSETASFLATBTN + 14, iMode, 0);
+ SendMessage(GetDlgItem(dat->hwnd, IDC_PIC), BUTTONSETASFLATBTN + 14, dat->fEditNotesActive ? TRUE : (!iMode && dat->iOpenJobs == 0) ? TRUE : FALSE, 0);
+
+ hwndOK = GetDlgItem(GetParent(GetParent(dat->hwnd)), IDOK);
+
+ if (IsWindow(hwndOK))
+ SendMessage(hwndOK, BUTTONSETASFLATBTN + 14, iMode, 0);
+}
+
+void TSAPI SendNudge(const TWindowData *dat)
+{
+ char szServiceName[128];
+
+ mir_snprintf(szServiceName, 128, "%s/SendNudge", dat->cache->getActiveProto());
+ if (ServiceExists(szServiceName) && ServiceExists(MS_NUDGE_SEND))
+ CallService(MS_NUDGE_SEND, (WPARAM)dat->cache->getActiveContact(), 0);
+ else
+ SendMessage(dat->hwnd, DM_ACTIVATETOOLTIP, IDC_MESSAGE,
+ (LPARAM)CTranslator::get(CTranslator::GEN_WARNING_NUDGE_DISABLED));
+}
+
+void TSAPI GetClientIcon(TWindowData *dat)
+{
+ DBVARIANT dbv = {0};
+
+ if(dat->hClientIcon)
+ DestroyIcon(dat->hClientIcon);
+
+ dat->hClientIcon = 0;
+ if (ServiceExists(MS_FP_GETCLIENTICON)) {
+ if (!DBGetContactSettingString(dat->cache->getActiveContact(), dat->cache->getActiveProto(), "MirVer", &dbv)) {
+ dat->hClientIcon = (HICON)CallService(MS_FP_GETCLIENTICON, (WPARAM)dbv.pszVal, 1);
+ DBFreeVariant(&dbv);
+ }
+ }
+}
+
+void TSAPI GetMyNick(TWindowData *dat)
+{
+ CONTACTINFO ci;
+
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(ci);
+ ci.hContact = NULL;
+ ci.szProto = const_cast<char *>(dat->cache->getActiveProto());
+ ci.dwFlag = CNF_TCHAR | CNF_NICK;
+
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci)) {
+ if (ci.type == CNFT_ASCIIZ) {
+ if (lstrlen(reinterpret_cast<TCHAR *>(ci.pszVal)) < 1 || !_tcscmp(reinterpret_cast<TCHAR *>(ci.pszVal),
+ CTranslator::get(CTranslator::GEN_UNKNOWN_CONTACT))) {
+ mir_sntprintf(dat->szMyNickname, safe_sizeof(dat->szMyNickname), _T("%s"), dat->myUin[0] ? dat->myUin : CTranslator::get(CTranslator::GEN_UNKNOWN_CONTACT));
+ if (ci.pszVal) {
+ mir_free(ci.pszVal);
+ ci.pszVal = NULL;
+ }
+ } else {
+ _tcsncpy(dat->szMyNickname, reinterpret_cast<TCHAR *>(ci.pszVal), 110);
+ dat->szMyNickname[109] = 0;
+ if (ci.pszVal) {
+ mir_free(ci.pszVal);
+ ci.pszVal = NULL;
+ }
+ }
+ } else if (ci.type == CNFT_DWORD)
+ _ltot(ci.dVal, dat->szMyNickname, 10);
+ else
+ _tcsncpy(dat->szMyNickname, _T("<undef>"), 110); // that really should *never* happen
+ } else
+ _tcsncpy(dat->szMyNickname, _T("<undef>"), 110); // same here
+ if (ci.pszVal)
+ mir_free(ci.pszVal);
+}
+
+HICON TSAPI MY_GetContactIcon(const TWindowData *dat)
+{
+ return(LoadSkinnedProtoIcon(dat->cache->getActiveProto(), dat->cache->getActiveStatus()));
+ //return(LoadSkinnedProtoIcon(dat->cache->getActiveProto(), dat->cache->getStatus()));
+}
+
+static void TSAPI MTH_updatePreview(const TWindowData *dat)
+{
+ TMathWindowInfo mathWndInfo;
+ HWND hwndEdit = GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE);
+ int len = GetWindowTextLengthA(hwndEdit);
+ RECT windRect;
+ char * thestr = (char *)malloc(len + 5);
+
+ GetWindowTextA(hwndEdit, thestr, len + 1);
+ GetWindowRect(dat->pContainer->hwnd, &windRect);
+ mathWndInfo.top = windRect.top;
+ mathWndInfo.left = windRect.left;
+ mathWndInfo.right = windRect.right;
+ mathWndInfo.bottom = windRect.bottom;
+
+ CallService(MTH_SETFORMULA, 0, (LPARAM) thestr);
+ CallService(MTH_RESIZE, 0, (LPARAM) &mathWndInfo);
+ free(thestr);
+}
+
+void TSAPI MTH_updateMathWindow(const TWindowData *dat)
+{
+ WINDOWPLACEMENT cWinPlace;
+
+ if (!PluginConfig.m_MathModAvail)
+ return;
+
+ MTH_updatePreview(dat);
+ CallService(MTH_SHOW, 0, 0);
+ cWinPlace.length = sizeof(WINDOWPLACEMENT);
+ GetWindowPlacement(dat->pContainer->hwnd, &cWinPlace);
+ return;
+}
+
+/**
+ * read keyboard state and return the state of the modifier keys
+ */
+void TSAPI KbdState(TWindowData *dat, BOOL& isShift, BOOL& isControl, BOOL& isAlt)
+{
+ GetKeyboardState(dat->kstate);
+ isShift = (dat->kstate[VK_SHIFT] & 0x80);
+ isControl = (dat->kstate[VK_CONTROL] & 0x80);
+ isAlt = (dat->kstate[VK_MENU] & 0x80);
+}
+
+/**
+ * clear the message log
+ * code needs to distuingish between IM and MUC sessions.
+ */
+void TSAPI ClearLog(TWindowData *dat)
+{
+ if(dat && dat->bType == SESSIONTYPE_IM) {
+ if (dat->hwndIEView || dat->hwndHPP) {
+ IEVIEWEVENT event;
+ event.cbSize = sizeof(IEVIEWEVENT);
+ event.iType = IEE_CLEAR_LOG;
+ event.dwFlags = (dat->dwFlags & MWF_LOG_RTL) ? IEEF_RTL : 0;
+ event.hContact = dat->hContact;
+ if (dat->hwndIEView) {
+ event.hwnd = dat->hwndIEView;
+ CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event);
+ } else {
+ event.hwnd = dat->hwndHPP;
+ CallService(MS_HPP_EG_EVENT, 0, (LPARAM)&event);
+ }
+ }
+ SetDlgItemText(dat->hwnd, IDC_LOG, _T(""));
+ dat->hDbEventFirst = NULL;
+ }
+ else if(dat && dat->bType == SESSIONTYPE_CHAT && dat->si) {
+ SESSION_INFO* si = reinterpret_cast<SESSION_INFO *>(dat->si);
+ SESSION_INFO* s = SM_FindSession(si->ptszID, si->pszModule);
+ if (s) {
+ SetDlgItemText(dat->hwnd, IDC_CHAT_LOG, _T(""));
+ LM_RemoveAll(&s->pLog, &s->pLogEnd);
+ s->iEventCount = 0;
+ s->LastTime = 0;
+ si->iEventCount = 0;
+ si->LastTime = 0;
+ si->pLog = s->pLog;
+ si->pLogEnd = s->pLogEnd;
+ PostMessage(dat->hwnd, WM_MOUSEACTIVATE, 0, 0);
+ }
+ }
+}
+
+/**
+ * calculate the minimum required client height for the given message
+ * window layout
+
+ * the container will use this in its WM_GETMINMAXINFO handler to set
+ * minimum tracking height.
+ */
+void TSAPI DetermineMinHeight(TWindowData* dat)
+{
+ if(dat) {
+ RECT rc;
+
+ LONG height = (dat->Panel->isActive() ? dat->Panel->getHeight() + 2 : 0);
+ if(!(dat->pContainer->dwFlags & CNT_HIDETOOLBAR))
+ height += DPISCALEY_S(24); // toolbar
+ GetClientRect(GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE), &rc);
+ height += rc.bottom; // input area
+ height += 40; // min space for log area and some padding
+
+ dat->pContainer->uChildMinHeight = height;
+ }
+}
+
+bool TSAPI IsAutoSplitEnabled(const TWindowData* dat)
+{
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+ return((dat && (dat->pContainer->dwFlags & CNT_AUTOSPLITTER) && !(dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE)) ? true : false);
+#else
+ return(false);
+#endif
+}
+
+#if defined(__FEAT_EXP_AUTOSPLITTER)
+LONG TSAPI GetDefaultMinimumInputHeight(const TWindowData* dat)
+{
+ LONG height = MINSPLITTERY;
+
+ if(dat) {
+ if(dat->bType == SESSIONTYPE_IM)
+ height = ((dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR) ? DPISCALEY_S(46 + 22) : DPISCALEY_S(46));
+ else
+ height = ((dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR) ? DPISCALEY_S(22 + 46) : DPISCALEY_S(46)) - DPISCALEY_S(23);
+
+ if(CSkin::m_skinEnabled && !SkinItems[ID_EXTBKINPUTAREA].IGNORED)
+ height += (SkinItems[ID_EXTBKINPUTAREA].MARGIN_BOTTOM + SkinItems[ID_EXTBKINPUTAREA].MARGIN_TOP - 2);
+ }
+ return(height);
+}
+#endif
+
+static std::vector<TCHAR *> vTempFilenames;
+
+/**
+ * send a pasted bitmap by file transfer.
+ */
+void TSAPI SendHBitmapAsFile(const TWindowData* dat, HBITMAP hbmp)
+{
+ const wchar_t* mirandatempdir = L"Miranda";
+ const wchar_t* filenametemplate = L"\\clp-%Y%m%d-%H%M%S0.jpg";
+ TCHAR filename[MAX_PATH];
+ size_t tempdirlen = GetTempPath(MAX_PATH, filename);
+ bool fSend = true;
+
+ const char* szProto = dat->cache->getActiveProto();
+ WORD wMyStatus = (WORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+
+ DWORD protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ DWORD typeCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0);
+
+ /*
+ * check protocol capabilities, status modes and visibility lists (privacy)
+ * to determine whether the file can be sent. Throw a warning if any of
+ * these checks fails.
+ */
+ if(!(protoCaps & PF1_FILESEND))
+ fSend = false;
+
+ if((ID_STATUS_OFFLINE == wMyStatus) || (ID_STATUS_OFFLINE == dat->cache->getActiveStatus() && !(typeCaps & PF4_OFFLINEFILES)))
+ fSend = false;
+
+ if (protoCaps & PF1_VISLIST && DBGetContactSettingWord(dat->cache->getActiveContact(), szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE)
+ fSend = false;
+
+ if (protoCaps & PF1_INVISLIST && wMyStatus == ID_STATUS_INVISIBLE && DBGetContactSettingWord(dat->cache->getActiveContact(), szProto, "ApparentMode", 0) != ID_STATUS_ONLINE)
+ fSend = false;
+
+ if(!fSend) {
+ CWarning::show(CWarning::WARN_SENDFILE, MB_OK|MB_ICONEXCLAMATION|CWarning::CWF_NOALLOWHIDE);
+ return;
+ }
+ if (tempdirlen <=0 || tempdirlen >= MAX_PATH-_tcslen(mirandatempdir)-_tcslen(filenametemplate)-2) // -2 is because %Y takes 4 symbols
+ filename[0] = 0; // prompt for a new name
+ else {
+ _tcscpy(filename+tempdirlen, mirandatempdir);
+ if ((GetFileAttributes(filename) == INVALID_FILE_ATTRIBUTES || ((GetFileAttributes(filename) & FILE_ATTRIBUTE_DIRECTORY) == 0)) && CreateDirectory(filename, NULL)==0)
+ filename[0] = 0;
+ else {
+ tempdirlen = _tcslen(filename);
+
+ time_t rawtime;
+ time(&rawtime);
+ const tm* timeinfo;
+ timeinfo = _localtime32((__time32_t *)&rawtime);
+ _tcsftime(filename + tempdirlen, MAX_PATH-tempdirlen, filenametemplate, timeinfo);
+ size_t firstnumberpos = tempdirlen+14;
+ size_t lastnumberpos = tempdirlen+20;
+ while (GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES) { // while it exists
+ for (size_t pos = lastnumberpos; pos >= firstnumberpos; pos--)
+ if (filename[pos]++ != '9')
+ break;
+ else
+ if (pos == firstnumberpos)
+ filename[0] = 0; // all filenames exist => prompt for a new name
+ else
+ filename[pos] = '0';
+ }
+ }
+ }
+ if (filename[0] == 0) { // prompting to save
+ OPENFILENAME dlg;
+ dlg.lStructSize = sizeof(dlg);
+ dlg.hwndOwner = NULL; //dat->hwnd;
+ TCHAR filter[MAX_PATH];
+ mir_sntprintf(filter, SIZEOF(filter), _T("%s%c*.jpg%c%c"), TranslateT("JPEG-compressed images"), 0, 0, 0);
+ dlg.lpstrFilter = filter;
+ dlg.nFilterIndex = 1;
+ dlg.lpstrFile = filename;
+ dlg.nMaxFile = MAX_PATH;
+ dlg.Flags = OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
+ dlg.lpstrDefExt = _T("jpg");
+ if (!GetSaveFileName(&dlg))
+ return;
+ }
+ IMGSRVC_INFO ii;
+ ii.cbSize = sizeof(ii);
+ ii.hbm = hbmp;
+ ii.wszName = filename;
+ ii.dwMask = IMGI_HBITMAP;
+ ii.fif = FIF_JPEG;
+ CallService(MS_IMG_SAVE, (WPARAM)&ii, IMGL_TCHAR);
+
+ int fileCount = 1, totalCount = 0;
+ TCHAR** ppFiles = NULL;
+ Utils::AddToFileList(&ppFiles, &totalCount, filename);
+
+ wchar_t* _t = mir_tstrdup(filename);
+ vTempFilenames.push_back(_t);
+
+ CallService(MS_FILE_SENDSPECIFICFILEST, (WPARAM)dat->cache->getActiveContact(), (LPARAM)ppFiles);
+
+ mir_free(ppFiles[0]);
+ mir_free(ppFiles);
+}
+
+/**
+ * remove all temporary files created by the "send clipboard as file" feature.
+ */
+void TSAPI CleanTempFiles()
+{
+ std::vector<wchar_t *>::iterator it = vTempFilenames.begin();
+
+ while(it != vTempFilenames.end()) {
+ DeleteFileW(*it);
+ mir_free(*it++);
+ }
+}
diff --git a/plugins/TabSRMM/src/msglog.cpp b/plugins/TabSRMM/src/msglog.cpp
new file mode 100644
index 0000000000..eb030bba9d
--- /dev/null
+++ b/plugins/TabSRMM/src/msglog.cpp
@@ -0,0 +1,1621 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: msglog.cpp 13642 2011-05-27 10:26:12Z silvercircle $
+ *
+ * implements the richedit based message log and the template parser
+ *
+ */
+
+#include "commonheaders.h"
+#include <mbstring.h>
+
+#pragma hdrstop
+
+extern void ReleaseRichEditOle(IRichEditOle *ole);
+extern void ImageDataInsertBitmap(IRichEditOle *ole, HBITMAP hBm);
+extern int CacheIconToBMP(struct TLogIcon *theIcon, HICON hIcon, COLORREF backgroundColor, int sizeX, int sizeY);
+extern void DeleteCachedIcon(struct TLogIcon *theIcon);
+
+struct TCpTable cpTable[] = {
+ { 874, _T("Thai") },
+ { 932, _T("Japanese") },
+ { 936, _T("Simplified Chinese") },
+ { 949, _T("Korean") },
+ { 950, _T("Traditional Chinese") },
+ { 1250, _T("Central European") },
+ { 1251, _T("Cyrillic") },
+ { 20866, _T("Cyrillic KOI8-R") },
+ { 1252, _T("Latin I") },
+ { 1253, _T("Greek") },
+ { 1254, _T("Turkish") },
+ { 1255, _T("Hebrew") },
+ { 1256, _T("Arabic") },
+ { 1257, _T("Baltic") },
+ { 1258, _T("Vietnamese") },
+ { 1361, _T("Korean (Johab)") },
+ { -1, NULL}
+};
+
+static TCHAR *Template_MakeRelativeDate(struct TWindowData *dat, HANDLE hTimeZone, time_t check, int groupBreak, TCHAR code);
+static void ReplaceIcons(HWND hwndDlg, struct TWindowData *dat, LONG startAt, int fAppend, BOOL isSent);
+
+static time_t today;
+
+int g_groupBreak = TRUE;
+static TCHAR *szMyName = NULL;
+static TCHAR *szYourName = NULL;
+
+static int logPixelSY;
+static TCHAR szToday[22], szYesterday[22];
+char rtfFontsGlobal[MSGDLGFONTCOUNT + 2][RTFCACHELINESIZE];
+char *rtfFonts;
+
+LOGFONTA logfonts[MSGDLGFONTCOUNT + 2];
+COLORREF fontcolors[MSGDLGFONTCOUNT + 2];
+
+#define LOGICON_MSG 0
+#define LOGICON_URL 1
+#define LOGICON_FILE 2
+#define LOGICON_OUT 3
+#define LOGICON_IN 4
+#define LOGICON_STATUS 5
+#define LOGICON_ERROR 6
+
+static HICON Logicons[NR_LOGICONS];
+
+#define STREAMSTAGE_HEADER 0
+#define STREAMSTAGE_EVENTS 1
+#define STREAMSTAGE_TAIL 2
+#define STREAMSTAGE_STOP 3
+struct LogStreamData {
+ int stage;
+ HANDLE hContact;
+ HANDLE hDbEvent, hDbEventLast;
+ char *buffer;
+ int bufferOffset, bufferLen;
+ int eventsToInsert;
+ int isEmpty;
+ int isAppend;
+ struct TWindowData *dlgDat;
+ DBEVENTINFO *dbei;
+};
+
+__forceinline char *GetRTFFont(DWORD dwIndex)
+{
+ return rtfFonts + (dwIndex * RTFCACHELINESIZE);
+}
+
+/*
+ * remove any empty line at the end of a message to avoid some RichEdit "issues" with
+ * the highlight code (individual background colors).
+ * Doesn't touch the message for sure, but empty lines at the end are ugly anyway.
+ */
+
+static void TrimMessage(TCHAR *msg)
+{
+ size_t iLen = lstrlen(msg) - 1;
+ size_t i = iLen;
+
+ while (i && (msg[i] == '\r' || msg[i] == '\n')) {
+ i--;
+ }
+ if (i < iLen)
+ msg[i+1] = '\0';
+}
+
+void TSAPI CacheLogFonts()
+{
+ int i;
+ HDC hdc = GetDC(NULL);
+ logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
+ ReleaseDC(NULL, hdc);
+
+ ZeroMemory((void *)logfonts, sizeof(LOGFONTA) * MSGDLGFONTCOUNT + 2);
+ for (i = 0; i < MSGDLGFONTCOUNT; i++) {
+ LoadLogfont(i, &logfonts[i], &fontcolors[i], FONTMODULE);
+ wsprintfA(rtfFontsGlobal[i], "\\f%u\\cf%u\\b%d\\i%d\\ul%d\\fs%u", i, i, logfonts[i].lfWeight >= FW_BOLD ? 1 : 0, logfonts[i].lfItalic,logfonts[i].lfUnderline, 2 * abs(logfonts[i].lfHeight) * 74 / logPixelSY);
+ }
+ wsprintfA(rtfFontsGlobal[MSGDLGFONTCOUNT], "\\f%u\\cf%u\\b%d\\i%d\\fs%u", MSGDLGFONTCOUNT, MSGDLGFONTCOUNT, 0, 0, 0);
+
+ _tcsncpy(szToday, CTranslator::get(CTranslator::GEN_LOG_TODAY), 20);
+ _tcsncpy(szYesterday, CTranslator::get(CTranslator::GEN_LOG_YESTERDAY), 20);
+ szToday[19] = szYesterday[19] = 0;
+
+ /*
+ * cache/create the info panel fonts
+ */
+
+ COLORREF clr;
+ LOGFONTA lf;
+
+ for (i = 0; i < IPFONTCOUNT; i++) {
+ if (CInfoPanel::m_ipConfig.hFonts[i])
+ DeleteObject(CInfoPanel::m_ipConfig.hFonts[i]);
+ LoadLogfont(i + 100, &lf, &clr, FONTMODULE);
+ //lf.lfHeight =-MulDiv(lf.lfHeight, logPixelSY, 72);
+ lf.lfUnderline = 0;
+ CInfoPanel::m_ipConfig.hFonts[i] = CreateFontIndirectA(&lf);
+ CInfoPanel::m_ipConfig.clrs[i] = clr;
+ }
+
+ hdc = GetDC(PluginConfig.g_hwndHotkeyHandler);
+
+ HFONT hOldFont = (HFONT)SelectObject(hdc, CInfoPanel::m_ipConfig.hFonts[IPFONTID_NICK]);
+ SIZE sz;
+
+ GetTextExtentPoint32(hdc, _T("WMA"), 3, &sz);
+ CInfoPanel::m_ipConfig.height1 = sz.cy;
+ SelectObject(hdc, CInfoPanel::m_ipConfig.hFonts[IPFONTID_UIN]);
+ GetTextExtentPoint32(hdc, _T("WMA"), 3, &sz);
+ CInfoPanel::m_ipConfig.height2 = sz.cy;
+
+ SelectObject(hdc, hOldFont);
+ ReleaseDC(PluginConfig.g_hwndHotkeyHandler, hdc);
+ PluginConfig.hFontCaption = CInfoPanel::m_ipConfig.hFonts[IPFONTCOUNT - 1];
+
+ PluginConfig.crIncoming = M->GetDword(FONTMODULE, "inbg", SRMSGDEFSET_BKGINCOLOUR);
+ PluginConfig.crOutgoing = M->GetDword(FONTMODULE, "outbg", SRMSGDEFSET_BKGOUTCOLOUR);
+ PluginConfig.crStatus = M->GetDword(FONTMODULE, "statbg", SRMSGDEFSET_BKGCOLOUR);
+ PluginConfig.crOldIncoming = M->GetDword(FONTMODULE, "oldinbg", SRMSGDEFSET_BKGINCOLOUR);
+ PluginConfig.crOldOutgoing = M->GetDword(FONTMODULE, "oldoutbg", SRMSGDEFSET_BKGOUTCOLOUR);
+}
+
+void FreeLogFonts()
+{
+ int i;
+
+ for (i = 0; i < IPFONTCOUNT; i++)
+ if (CInfoPanel::m_ipConfig.hFonts[i])
+ DeleteObject(CInfoPanel::m_ipConfig.hFonts[i]);
+
+}
+
+void TSAPI CacheMsgLogIcons()
+{
+ Logicons[0] = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ Logicons[1] = LoadSkinnedIcon(SKINICON_EVENT_URL);
+ Logicons[2] = LoadSkinnedIcon(SKINICON_EVENT_FILE);
+ Logicons[3] = PluginConfig.g_iconOut;
+ Logicons[4] = PluginConfig.g_iconIn;
+ Logicons[5] = PluginConfig.g_iconStatus;
+ Logicons[6] = PluginConfig.g_iconErr;
+}
+
+static int TSAPI GetColorIndex(char *rtffont)
+{
+ char *p;
+
+ if ((p = strstr(rtffont, "\\cf")) != NULL)
+ return atoi(p + 3);
+ return 0;
+}
+
+static void AppendToBuffer(char **buffer, int *cbBufferEnd, int *cbBufferAlloced, const char *fmt, ...)
+{
+ va_list va;
+ int charsDone;
+
+ va_start(va, fmt);
+ for (;;) {
+ charsDone = mir_vsnprintf(*buffer + *cbBufferEnd, *cbBufferAlloced - *cbBufferEnd, fmt, va);
+ if (charsDone >= 0)
+ break;
+ *cbBufferAlloced += 1024;
+ *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
+ }
+ va_end(va);
+ *cbBufferEnd += charsDone;
+}
+
+static int AppendUnicodeToBuffer(char **buffer, int *cbBufferEnd, int *cbBufferAlloced, TCHAR * line, int mode)
+{
+ DWORD textCharsCount = 0;
+ char *d;
+
+ int lineLen = (int)(wcslen(line)) * 9 + 8;
+ if (*cbBufferEnd + lineLen > *cbBufferAlloced) {
+ cbBufferAlloced[0] += (lineLen + 1024UL - lineLen % 1024UL);
+ *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
+ }
+
+ d = *buffer + *cbBufferEnd;
+ strcpy(d, "{\\uc1 ");
+ d += 6;
+
+ for (; *line; line++, textCharsCount++) {
+
+ if (1) {
+ if (*line == 127 && line[1] != 0) {
+ TCHAR code = line[2];
+ if (((code == '0' || code == '1') && line[3] == ' ') || (line[1] == 'c' && code == 'x')) {
+ int begin = (code == '1');
+ switch (line[1]) {
+ case 'b':
+ CopyMemory(d, begin ? "\\b " : "\\b0 ", begin ? 3 : 4);
+ d += (begin ? 3 : 4);
+ line += 3;
+ continue;
+ case 'i':
+ CopyMemory(d, begin ? "\\i " : "\\i0 ", begin ? 3 : 4);
+ d += (begin ? 3 : 4);
+ line += 3;
+ continue;
+ case 'u':
+ CopyMemory(d, begin ? "\\ul " : "\\ul0 ", begin ? 4 : 5);
+ d += (begin ? 4 : 5);
+ line += 3;
+ continue;
+ case 's':
+ CopyMemory(d, begin ? "\\strike " : "\\strike0 ", begin ? 8 : 9);
+ d += (begin ? 8 : 9);
+ line += 3;
+ continue;
+ case 'c':
+ begin = (code == 'x');
+ CopyMemory(d, "\\cf", 3);
+ if (begin) {
+ d[3] = (char)line[3];
+ d[4] = (char)line[4];
+ d[5] = ' ';
+ } else {
+ char szTemp[10];
+ int colindex = GetColorIndex(GetRTFFont(LOWORD(mode) ? (MSGFONTID_MYMSG + (HIWORD(mode) ? 8 : 0)) : (MSGFONTID_YOURMSG + (HIWORD(mode) ? 8 : 0))));
+ _snprintf(szTemp, 4, "%02d", colindex);
+ d[3] = szTemp[0];
+ d[4] = szTemp[1];
+ d[5] = ' ';
+ }
+ d += 6;
+ line += (begin ? 6 : 3);
+ continue;
+ }
+ }
+ }
+ }
+ if (*line == '\r' && line[1] == '\n') {
+ CopyMemory(d, "\\line ", 6);
+ line++;
+ d += 6;
+ } else if (*line == '\n') {
+ CopyMemory(d, "\\line ", 6);
+ d += 6;
+ } else if (*line == '\t') {
+ CopyMemory(d, "\\tab ", 5);
+ d += 5;
+ } else if (*line == '\\' || *line == '{' || *line == '}') {
+ *d++ = '\\';
+ *d++ = (char) * line;
+ } else if (*line < 128) {
+ *d++ = (char) * line;
+ } else
+ d += sprintf(d, "\\u%d ?", *line);
+ }
+
+ strcpy(d, "}");
+ d++;
+
+ *cbBufferEnd = (int)(d - *buffer);
+ return textCharsCount;
+}
+
+/*
+ * same as above but does "\r\n"->"\\par " and "\t"->"\\tab " too
+ */
+
+static int AppendToBufferWithRTF(int mode, char **buffer, int *cbBufferEnd, int *cbBufferAlloced, const char *fmt, ...)
+{
+ va_list va;
+ int charsDone, i;
+
+ va_start(va, fmt);
+ for (;;) {
+ charsDone = mir_vsnprintf(*buffer + *cbBufferEnd, *cbBufferAlloced - *cbBufferEnd, fmt, va);
+ if (charsDone >= 0)
+ break;
+ *cbBufferAlloced += 1024;
+ *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
+ }
+ va_end(va);
+ *cbBufferEnd += charsDone;
+ for (i = *cbBufferEnd - charsDone; (*buffer)[i]; i++) {
+
+ if (1) {
+ if ((*buffer)[i] == '' && (*buffer)[i + 1] != 0) {
+ char code = (*buffer)[i + 2];
+ char tag = (*buffer)[i + 1];
+
+ if (((code == '0' || code == '1') && (*buffer)[i + 3] == ' ') || (tag == 'c' && (code == 'x' || code == '0'))) {
+ int begin = (code == '1');
+
+ if (*cbBufferEnd + 5 > *cbBufferAlloced) {
+ *cbBufferAlloced += 1024;
+ *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
+ }
+ switch (tag) {
+ case 'b':
+ CopyMemory(*buffer + i, begin ? "\\b1 " : "\\b0 ", 4);
+ continue;
+ case 'i':
+ CopyMemory(*buffer + i, begin ? "\\i1 " : "\\i0 ", 4);
+ continue;
+ case 'u':
+ MoveMemory(*buffer + i + 2, *buffer + i + 1, *cbBufferEnd - i);
+ CopyMemory(*buffer + i, begin ? "\\ul1 " : "\\ul0 ", 5);
+ *cbBufferEnd += 1;
+ continue;
+ case 's':
+ *cbBufferAlloced += 20;
+ *buffer = (char *)realloc(*buffer, *cbBufferAlloced);
+ MoveMemory(*buffer + i + 6, *buffer + i + 1, (*cbBufferEnd - i) + 1);
+ CopyMemory(*buffer + i, begin ? "\\strike1 " : "\\strike0 ", begin ? 9 : 9);
+ *cbBufferEnd += 5;
+ continue;
+ case 'c':
+ begin = (code == 'x');
+ CopyMemory(*buffer + i, "\\cf", 3);
+ if (begin) {
+ } else {
+ char szTemp[10];
+ int colindex = GetColorIndex(GetRTFFont(LOWORD(mode) ? (MSGFONTID_MYMSG + (HIWORD(mode) ? 8 : 0)) : (MSGFONTID_YOURMSG + (HIWORD(mode) ? 8 : 0))));
+ _snprintf(szTemp, 4, "%02d", colindex);
+ (*buffer)[i + 3] = szTemp[0];
+ (*buffer)[i + 4] = szTemp[1];
+ }
+ continue;
+ }
+ }
+ }
+ }
+
+ if ((*buffer)[i] == '\r' && (*buffer)[i + 1] == '\n') {
+ if (*cbBufferEnd + 5 > *cbBufferAlloced) {
+ *cbBufferAlloced += 1024;
+ *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
+ }
+ MoveMemory(*buffer + i + 6, *buffer + i + 2, *cbBufferEnd - i - 1);
+ CopyMemory(*buffer + i, "\\line ", 6);
+ *cbBufferEnd += 4;
+ } else if ((*buffer)[i] == '\n') {
+ if (*cbBufferEnd + 6 > *cbBufferAlloced) {
+ *cbBufferAlloced += 1024;
+ *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
+ }
+ MoveMemory(*buffer + i + 6, *buffer + i + 1, *cbBufferEnd - i);
+ CopyMemory(*buffer + i, "\\line ", 6);
+ *cbBufferEnd += 5;
+ } else if ((*buffer)[i] == '\t') {
+ if (*cbBufferEnd + 5 > *cbBufferAlloced) {
+ *cbBufferAlloced += 1024;
+ *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
+ }
+ MoveMemory(*buffer + i + 5, *buffer + i + 1, *cbBufferEnd - i);
+ CopyMemory(*buffer + i, "\\tab ", 5);
+ *cbBufferEnd += 4;
+ } else if ((*buffer)[i] == '\\' || (*buffer)[i] == '{' || (*buffer)[i] == '}') {
+ if (*cbBufferEnd + 2 > *cbBufferAlloced) {
+ *cbBufferAlloced += 1024;
+ *buffer = (char *) realloc(*buffer, *cbBufferAlloced);
+ }
+ MoveMemory(*buffer + i + 1, *buffer + i, *cbBufferEnd - i + 1);
+ (*buffer)[i] = '\\';
+ ++*cbBufferEnd;
+ i++;
+ }
+ }
+ return (int)(_mbslen((unsigned char *)*buffer + *cbBufferEnd));
+}
+
+static void Build_RTF_Header(char **buffer, int *bufferEnd, int *bufferAlloced, struct TWindowData *dat)
+{
+ COLORREF colour;
+ int i;
+ char szTemp[30];
+ LOGFONTA* logFonts = dat->pContainer->theme.logFonts;
+ COLORREF* fontColors = dat->pContainer->theme.fontColors;
+ TLogTheme *theme = &dat->pContainer->theme;
+
+ // rtl
+ if (dat->dwFlags & MWF_LOG_RTL)
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "{\\rtf1\\ansi\\deff0{\\fonttbl");
+ else
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "{\\rtf1\\ansi\\deff0{\\fonttbl");
+
+ for (i = 0; i < MSGDLGFONTCOUNT; i++)
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "{\\f%u\\fnil\\fcharset%u %s;}", i, logFonts[i].lfCharSet, logFonts[i].lfFaceName);
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "{\\f%u\\fnil\\fcharset%u %s;}", MSGDLGFONTCOUNT, logFonts[i].lfCharSet, "Arial");
+
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "}{\\colortbl ");
+ for (i = 0; i < MSGDLGFONTCOUNT; i++)
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(fontColors[i]), GetGValue(fontColors[i]), GetBValue(fontColors[i]));
+ if (GetSysColorBrush(COLOR_HOTLIGHT) == NULL)
+ colour = RGB(0, 0, 255);
+ else
+ colour = GetSysColor(COLOR_HOTLIGHT);
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+
+ /* OnO: Create incoming and outcoming colours */
+ colour = theme->inbg;
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+ colour = theme->outbg;
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+ colour = theme->bg;
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+ colour = theme->hgrid;
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+ colour = theme->oldinbg;
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+ colour = theme->oldoutbg;
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+ colour = theme->statbg;
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+
+ // custom template colors...
+
+ for (i = 1; i <= 5; i++) {
+ _snprintf(szTemp, 10, "cc%d", i);
+ colour = theme->custom_colors[i - 1];
+ if (colour == 0)
+ colour = RGB(1, 1, 1);
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(colour), GetGValue(colour), GetBValue(colour));
+ }
+
+ // bbcode colors...
+
+ for (i = 0; i < Utils::rtf_ctable_size; i++)
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(Utils::rtf_ctable[i].clr), GetGValue(Utils::rtf_ctable[i].clr), GetBValue(Utils::rtf_ctable[i].clr));
+
+ /*
+ * paragraph header
+ */
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "}");
+
+ /*
+ * indent:
+ * real indent is set in msgdialog.c (DM_OPTIONSAPPLIED)
+ */
+
+ if (!(dat->dwFlags & MWF_LOG_INDENT))
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "\\li%u\\ri%u\\fi%u\\tx%u", 2*15, 2*15, 0, 70 * 15);
+}
+
+
+//free() the return value
+static char *CreateRTFHeader(struct TWindowData *dat)
+{
+ char *buffer;
+ int bufferAlloced, bufferEnd;
+
+ bufferEnd = 0;
+ bufferAlloced = 1024;
+ buffer = (char *) malloc(bufferAlloced);
+ buffer[0] = '\0';
+
+ Build_RTF_Header(&buffer, &bufferEnd, &bufferAlloced, dat);
+ return buffer;
+}
+
+static void AppendTimeStamp(TCHAR *szFinalTimestamp, int isSent, char **buffer, int *bufferEnd, int *bufferAlloced, int skipFont,
+ struct TWindowData *dat, int iFontIDOffset)
+{
+ if (skipFont)
+ AppendUnicodeToBuffer(buffer, bufferEnd, bufferAlloced, szFinalTimestamp, MAKELONG(isSent, dat->isHistory));
+ else {
+ AppendToBuffer(buffer, bufferEnd, bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset));
+ AppendUnicodeToBuffer(buffer, bufferEnd, bufferAlloced, szFinalTimestamp, MAKELONG(isSent, dat->isHistory));
+ }
+}
+
+//free() the return value
+static char *CreateRTFTail(struct TWindowData *dat)
+{
+ char *buffer;
+ int bufferAlloced, bufferEnd;
+
+ bufferEnd = 0;
+ bufferAlloced = 1024;
+ buffer = (char *) malloc(bufferAlloced);
+ buffer[0] = '\0';
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}");
+ return buffer;
+}
+
+int TSAPI DbEventIsShown(struct TWindowData *dat, DBEVENTINFO * dbei)
+{
+ int heFlags;
+
+ switch (dbei->eventType) {
+ case EVENTTYPE_MESSAGE:
+ return 1;
+ case EVENTTYPE_FILE:
+ return(dat->dwFlagsEx & MWF_SHOW_FILEEVENTS);
+ }
+ if (IsStatusEvent(dbei->eventType))
+ return 1;
+
+ heFlags = HistoryEvents_GetFlags(dbei->eventType);
+ if (heFlags != -1)
+ return (heFlags & HISTORYEVENTS_FLAG_SHOW_IM_SRMM) == HISTORYEVENTS_FLAG_SHOW_IM_SRMM;
+
+ return 0;
+}
+
+static int DbEventIsForMsgWindow(DBEVENTINFO *dbei)
+{
+ DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )CallService( MS_DB_EVENT_GETTYPE, ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType );
+ return et && ( et->flags & DETF_MSGWINDOW );
+}
+
+static char *Template_CreateRTFFromDbEvent(struct TWindowData *dat, HANDLE hContact, HANDLE hDbEvent, int prefixParaBreak, struct LogStreamData *streamData)
+{
+ char *buffer, c;
+ TCHAR ci, cc;
+ TCHAR *szFinalTimestamp;
+ int bufferAlloced, bufferEnd;
+ size_t iTemplateLen, i = 0;
+ DBEVENTINFO dbei = { 0 };
+ int isSent = 0;
+ int iFontIDOffset = 0;
+ TCHAR *szTemplate;
+ HANDLE hTimeZone;
+ BOOL skipToNext = FALSE, showTime = TRUE, showDate = TRUE, skipFont = FALSE;
+ struct tm event_time;
+ TTemplateSet *this_templateset;
+ BOOL isBold = FALSE, isItalic = FALSE, isUnderline = FALSE;
+ DWORD dwEffectiveFlags;
+ DWORD dwFormattingParams = MAKELONG(PluginConfig.m_FormatWholeWordsOnly, 0);
+ BOOL fIsStatusChangeEvent = FALSE;
+ TCHAR *msg, *formatted = NULL;
+ int heFlags = -1;
+ char *rtfMessage = NULL;
+
+ bufferEnd = 0;
+ bufferAlloced = 1024;
+ buffer = (char *) malloc(bufferAlloced);
+ buffer[0] = '\0';
+
+ if (streamData->dbei != 0)
+ dbei = *(streamData->dbei);
+ else {
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM) hDbEvent, 0);
+ if (dbei.cbBlob == -1) {
+ free(buffer);
+ return NULL;
+ }
+ dbei.pBlob = (PBYTE) malloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET, (WPARAM) hDbEvent, (LPARAM) & dbei);
+ if (!DbEventIsShown(dat, &dbei)) {
+ free(dbei.pBlob);
+ free(buffer);
+ return NULL;
+ }
+ }
+
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT | DBEF_READ)))
+ dat->cache->updateStats(TSessionStats::SET_LAST_RCV, lstrlenA((char *) dbei.pBlob));
+
+ if (dbei.eventType != EVENTTYPE_MESSAGE && dbei.eventType != EVENTTYPE_FILE && !IsStatusEvent(dbei.eventType))
+ heFlags = HistoryEvents_GetFlags(dbei.eventType);
+ if (heFlags & HISTORYEVENTS_FLAG_DEFAULT)
+ heFlags = -1;
+
+ if (heFlags != -1)
+ rtfMessage = HistoryEvents_GetRichText(hDbEvent, &dbei);
+ if (rtfMessage == NULL) {
+ msg = DbGetEventTextT(&dbei, dat->codePage);
+ if (!msg) {
+ free(dbei.pBlob);
+ free(buffer);
+ return NULL;
+ }
+ TrimMessage(msg);
+ formatted = const_cast<TCHAR *>(Utils::FormatRaw(dat, msg, dwFormattingParams, isSent));
+ mir_free(msg);
+ }
+
+ fIsStatusChangeEvent = (heFlags != -1 || IsStatusEvent(dbei.eventType));
+
+ if (dat->isAutoRTL & 2) { // means: last \\par was deleted to avoid new line at end of log
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par");
+ dat->isAutoRTL &= ~2;
+ }
+
+ if (dat->dwFlags & MWF_LOG_RTL)
+ dbei.flags |= DBEF_RTL;
+
+ if (dbei.flags & DBEF_RTL)
+ dat->isAutoRTL |= 1;
+
+ dwEffectiveFlags = dat->dwFlags;
+
+ dat->isHistory = (dbei.timestamp < dat->cache->getSessionStart() && (dbei.flags & DBEF_READ || dbei.flags & DBEF_SENT));
+ iFontIDOffset = dat->isHistory ? 8 : 0; // offset into the font table for either history (old) or new events... (# of fonts per configuration set)
+ isSent = (dbei.flags & DBEF_SENT);
+
+ if (!isSent && (fIsStatusChangeEvent || dbei.eventType == EVENTTYPE_MESSAGE || DbEventIsForMsgWindow(&dbei))) {
+ CallService(MS_DB_EVENT_MARKREAD, (WPARAM)hContact, (LPARAM)hDbEvent);
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM)hContact, (LPARAM)hDbEvent);
+ }
+
+ g_groupBreak = TRUE;
+
+ if (dwEffectiveFlags & MWF_DIVIDERWANTED) {
+ static char szStyle_div[128] = "\0";
+ if (szStyle_div[0] == 0)
+ mir_snprintf(szStyle_div, 128, "\\f%u\\cf%u\\ul0\\b%d\\i%d\\fs%u", H_MSGFONTID_DIVIDERS, H_MSGFONTID_DIVIDERS, 0, 0, 5);
+
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\sl-1\\slmult0\\highlight%d\\cf%d\\-\\par\\sl0", H_MSGFONTID_DIVIDERS, H_MSGFONTID_DIVIDERS);
+ dat->dwFlags &= ~MWF_DIVIDERWANTED;
+ }
+ if (dwEffectiveFlags & MWF_LOG_GROUPMODE && ((dbei.flags & (DBEF_SENT | DBEF_READ | DBEF_RTL)) == LOWORD(dat->iLastEventType)) && dbei.eventType == EVENTTYPE_MESSAGE && HIWORD(dat->iLastEventType) == EVENTTYPE_MESSAGE && (dbei.timestamp - dat->lastEventTime) < 86400) {
+ g_groupBreak = FALSE;
+ if ((time_t)dbei.timestamp > today && dat->lastEventTime < today) {
+ g_groupBreak = TRUE;
+ }
+ }
+ if (!streamData->isEmpty && g_groupBreak && (dwEffectiveFlags & MWF_LOG_GRID))
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\sl-1\\slmult0\\highlight%d\\cf%d\\-\\par\\sl0", MSGDLGFONTCOUNT + 4, MSGDLGFONTCOUNT + 4);
+
+ if (dbei.flags & DBEF_RTL)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\rtlpar");
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ltrpar");
+
+ /* OnO: highlight start */
+ if(fIsStatusChangeEvent)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\highlight%d\\cf%d", MSGDLGFONTCOUNT + 7, MSGDLGFONTCOUNT + 7);
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\highlight%d\\cf%d", MSGDLGFONTCOUNT + (dat->isHistory?5:1) + ((isSent) ? 1 : 0), MSGDLGFONTCOUNT + (dat->isHistory?5:1) + ((isSent) ? 1 : 0));
+
+ streamData->isEmpty = FALSE;
+
+ if (dat->isAutoRTL & 1) {
+ if (dbei.flags & DBEF_RTL) {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ltrch\\rtlch");
+ } else {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\rtlch\\ltrch");
+ }
+ }
+
+ /*
+ * templated code starts here
+ */
+ if (dwEffectiveFlags & MWF_LOG_SHOWTIME) {
+ hTimeZone = ((dat->dwFlags & MWF_LOG_LOCALTIME) && !isSent) ? dat->hTimeZone : NULL;
+ time_t local_time = tmi.timeStampToTimeZoneTimeStamp(hTimeZone, dbei.timestamp);
+ event_time = *gmtime(&local_time);
+ }
+ this_templateset = dbei.flags & DBEF_RTL ? dat->pContainer->rtl_templates : dat->pContainer->ltr_templates;
+
+ if (fIsStatusChangeEvent)
+ szTemplate = this_templateset->szTemplates[TMPL_STATUSCHG];
+ else if (dbei.eventType == EVENTTYPE_ERRMSG)
+ szTemplate = this_templateset->szTemplates[TMPL_ERRMSG];
+ else {
+ if (dwEffectiveFlags & MWF_LOG_GROUPMODE)
+ szTemplate = isSent ? (g_groupBreak ? this_templateset->szTemplates[TMPL_GRPSTARTOUT] : this_templateset->szTemplates[TMPL_GRPINNEROUT]) :
+ (g_groupBreak ? this_templateset->szTemplates[TMPL_GRPSTARTIN] : this_templateset->szTemplates[TMPL_GRPINNERIN]);
+ else
+ szTemplate = isSent ? this_templateset->szTemplates[TMPL_MSGOUT] : this_templateset->szTemplates[TMPL_MSGIN];
+ }
+
+ iTemplateLen = lstrlen(szTemplate);
+ showTime = dwEffectiveFlags & MWF_LOG_SHOWTIME;
+ showDate = dwEffectiveFlags & MWF_LOG_SHOWDATES;
+
+ if (dat->hHistoryEvents) {
+ if (dat->curHistory == dat->maxHistory) {
+ MoveMemory(dat->hHistoryEvents, &dat->hHistoryEvents[1], sizeof(HANDLE) * (dat->maxHistory - 1));
+ dat->curHistory--;
+ }
+ dat->hHistoryEvents[dat->curHistory++] = hDbEvent;
+ }
+
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ul0\\b0\\i0 ");
+
+ while (i < iTemplateLen) {
+ ci = szTemplate[i];
+ if (ci == '%') {
+ cc = szTemplate[i + 1];
+ skipToNext = FALSE;
+ skipFont = FALSE;
+ /*
+ * handle modifiers
+ */
+ while (cc == '#' || cc == '$' || cc == '&' || cc == '?' || cc == '\\') {
+ switch (cc) {
+ case '#':
+ if (!dat->isHistory) {
+ skipToNext = TRUE;
+ goto skip;
+ } else {
+ i++;
+ cc = szTemplate[i + 1];
+ continue;
+ }
+ case '$':
+ if (dat->isHistory) {
+ skipToNext = TRUE;
+ goto skip;
+ } else {
+ i++;
+ cc = szTemplate[i + 1];
+ continue;
+ }
+ case '&':
+ i++;
+ cc = szTemplate[i + 1];
+ skipFont = TRUE;
+ break;
+ case '?':
+ if (dwEffectiveFlags & MWF_LOG_NORMALTEMPLATES) {
+ i++;
+ cc = szTemplate[i + 1];
+ continue;
+ } else {
+ i++;
+ skipToNext = TRUE;
+ goto skip;
+ }
+ case '\\':
+ if (!(dwEffectiveFlags & MWF_LOG_NORMALTEMPLATES)) {
+ i++;
+ cc = szTemplate[i + 1];
+ continue;
+ } else {
+ i++;
+ skipToNext = TRUE;
+ goto skip;
+ }
+ }
+ }
+ switch (cc) {
+ case 'V':
+ //AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\fs0\\\expnd-40 ~-%d-~", hDbEvent);
+ break;
+ case 'I': {
+ if (dwEffectiveFlags & MWF_LOG_SHOWICONS) {
+ int icon;
+ if ((dwEffectiveFlags & MWF_LOG_INOUTICONS) && dbei.eventType == EVENTTYPE_MESSAGE)
+ icon = isSent ? LOGICON_OUT : LOGICON_IN;
+ else {
+ switch (dbei.eventType) {
+ case EVENTTYPE_FILE:
+ icon = LOGICON_FILE;
+ break;
+ case EVENTTYPE_ERRMSG:
+ icon = LOGICON_ERROR;
+ break;
+ default:
+ icon = LOGICON_MSG;
+ break;
+ }
+ if (fIsStatusChangeEvent)
+ icon = LOGICON_STATUS;
+ }
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s\\fs1 #~#%01d%c%s ", GetRTFFont(MSGFONTID_SYMBOLS_IN), icon, isSent ? '>' : '<', GetRTFFont(isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset));
+ } else
+ skipToNext = TRUE;
+ break;
+ }
+ case 'D': // long date
+ if (showTime && showDate) {
+ szFinalTimestamp = Template_MakeRelativeDate(dat, hTimeZone, dbei.timestamp, g_groupBreak, (TCHAR)'D');
+ AppendTimeStamp(szFinalTimestamp, isSent, &buffer, &bufferEnd, &bufferAlloced, skipFont, dat, iFontIDOffset);
+ } else
+ skipToNext = TRUE;
+ break;
+ case 'E': // short date...
+ if (showTime && showDate) {
+ szFinalTimestamp = Template_MakeRelativeDate(dat, hTimeZone, dbei.timestamp, g_groupBreak, (TCHAR)'E');
+ AppendTimeStamp(szFinalTimestamp, isSent, &buffer, &bufferEnd, &bufferAlloced, skipFont, dat, iFontIDOffset);
+ } else
+ skipToNext = TRUE;
+ break;
+ case 'a': // 12 hour
+ case 'h': // 24 hour
+ if (showTime) {
+ if (skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, cc == 'h' ? "%02d" : "%2d", cc == 'h' ? event_time.tm_hour : (event_time.tm_hour > 12 ? event_time.tm_hour - 12 : event_time.tm_hour));
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, cc == 'h' ? "%s %02d" : "%s %2d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), cc == 'h' ? event_time.tm_hour : (event_time.tm_hour > 12 ? event_time.tm_hour - 12 : event_time.tm_hour));
+ } else
+ skipToNext = TRUE;
+ break;
+ case 'm': // minute
+ if (showTime) {
+ if (skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%02d", event_time.tm_min);
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %02d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_min);
+ } else
+ skipToNext = TRUE;
+ break;
+ case 's': //second
+ if (showTime && dwEffectiveFlags & MWF_LOG_SHOWSECONDS) {
+ if (skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%02d", event_time.tm_sec);
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %02d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_sec);
+ } else
+ skipToNext = TRUE;
+ break;
+ case 'p': // am/pm symbol
+ if (showTime) {
+ if (skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s", event_time.tm_hour > 11 ? "PM" : "AM");
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %s", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_hour > 11 ? "PM" : "AM");
+ } else
+ skipToNext = TRUE;
+ break;
+ case 'o': // month
+ if (showTime && showDate) {
+ if (skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%02d", event_time.tm_mon + 1);
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %02d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_mon + 1);
+ } else
+ skipToNext = TRUE;
+ break;
+ case'O': // month (name)
+ if (showTime && showDate) {
+ if (skipFont)
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, const_cast<TCHAR *>(CTranslator::getMonth(event_time.tm_mon)),
+ MAKELONG(isSent, dat->isHistory));
+ else {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset));
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, const_cast<TCHAR *>(CTranslator::getMonth(event_time.tm_mon)),
+ MAKELONG(isSent, dat->isHistory));
+ }
+ } else
+ skipToNext = TRUE;
+ break;
+ case 'd': // day of month
+ if (showTime && showDate) {
+ if (skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%02d", event_time.tm_mday);
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %02d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_mday);
+ } else
+ skipToNext = TRUE;
+ break;
+ case 'w': // day of week
+ if (showTime && showDate) {
+ if (skipFont)
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, const_cast<TCHAR *>(CTranslator::getWeekday(event_time.tm_wday)), MAKELONG(isSent, dat->isHistory));
+ else {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset));
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, const_cast<TCHAR *>(CTranslator::getWeekday(event_time.tm_wday)), MAKELONG(isSent, dat->isHistory));
+ }
+ } else
+ skipToNext = TRUE;
+ break;
+ case 'y': // year
+ if (showTime && showDate) {
+ if (skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%04d", event_time.tm_year + 1900);
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %04d", GetRTFFont(isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset), event_time.tm_year + 1900);
+ } else
+ skipToNext = TRUE;
+ break;
+ case 'R':
+ case 'r': // long date
+ if (showTime && showDate) {
+ szFinalTimestamp = Template_MakeRelativeDate(dat, hTimeZone, dbei.timestamp, g_groupBreak, cc);
+ AppendTimeStamp(szFinalTimestamp, isSent, &buffer, &bufferEnd, &bufferAlloced, skipFont, dat, iFontIDOffset);
+ } else
+ skipToNext = TRUE;
+ break;
+ case 't':
+ case 'T':
+ if (showTime) {
+ szFinalTimestamp = Template_MakeRelativeDate(dat, hTimeZone, dbei.timestamp, g_groupBreak, (TCHAR)((dwEffectiveFlags & MWF_LOG_SHOWSECONDS) ? cc : (TCHAR)'t'));
+ AppendTimeStamp(szFinalTimestamp, isSent, &buffer, &bufferEnd, &bufferAlloced, skipFont, dat, iFontIDOffset);
+ } else
+ skipToNext = TRUE;
+ break;
+ case 'S': { // symbol
+ if (dwEffectiveFlags & MWF_LOG_SYMBOLS) {
+ if ((dwEffectiveFlags & MWF_LOG_INOUTICONS) && dbei.eventType == EVENTTYPE_MESSAGE)
+ c = isSent ? 0x37 : 0x38;
+ else {
+ switch (dbei.eventType) {
+ case EVENTTYPE_MESSAGE:
+ c = (char)0xaa;
+ break;
+ case EVENTTYPE_FILE:
+ c = (char)0xcd;
+ break;
+ case EVENTTYPE_ERRMSG:
+ c = (char)0x72;;
+ break;
+ default:
+ c = (char)0xaa;
+ break;
+ }
+ if (fIsStatusChangeEvent)
+ c = 0x4e;
+ }
+ if (skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%c%s ", c, GetRTFFont(isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset));
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s %c%s ", isSent ? GetRTFFont(MSGFONTID_SYMBOLS_OUT) : GetRTFFont(MSGFONTID_SYMBOLS_IN), c, GetRTFFont(isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset));
+ } else
+ skipToNext = TRUE;
+ break;
+ }
+ case 'n': // hard line break
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, dbei.flags & DBEF_RTL ? "\\rtlpar\\par\\rtlpar" : "\\par\\ltrpar");
+ break;
+ case 'l': // soft line break
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\line");
+ break;
+ case 'N': { // nickname
+ if (heFlags != -1 && !(heFlags & HISTORYEVENTS_FLAG_EXPECT_CONTACT_NAME_BEFORE))
+ break;
+
+ if (!skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYNAME + iFontIDOffset : MSGFONTID_YOURNAME + iFontIDOffset));
+ if (isSent)
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, szMyName, MAKELONG(isSent, dat->isHistory));
+ else
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, szYourName, MAKELONG(isSent, dat->isHistory));
+ break;
+ }
+ case 'U': // UIN
+ if (!skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYNAME + iFontIDOffset : MSGFONTID_YOURNAME + iFontIDOffset));
+ if(!isSent)
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, (wchar_t *)dat->cache->getUIN(), MAKELONG(isSent, dat->isHistory));
+ else
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, (wchar_t *)dat->myUin, MAKELONG(isSent, dat->isHistory));
+ break;
+ case 'e': // error message
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(MSGFONTID_ERROR));
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, (wchar_t *)dbei.szModule, MAKELONG(isSent, dat->isHistory));
+ break;
+ case 'M': { // message
+ if (fIsStatusChangeEvent)
+ dbei.eventType = EVENTTYPE_STATUSCHANGE;
+ switch (dbei.eventType) {
+ case EVENTTYPE_MESSAGE:
+ case EVENTTYPE_ERRMSG:
+ case EVENTTYPE_STATUSCHANGE: {
+ if (fIsStatusChangeEvent || dbei.eventType == EVENTTYPE_ERRMSG) {
+ if (dbei.eventType == EVENTTYPE_ERRMSG && dbei.cbBlob == 0)
+ break;
+ if (dbei.eventType == EVENTTYPE_ERRMSG) {
+ if (!skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\line%s ", GetRTFFont(fIsStatusChangeEvent ? H_MSGFONTID_STATUSCHANGES : MSGFONTID_MYMSG));
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\line ");
+ } else {
+ if (!skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(fIsStatusChangeEvent ? H_MSGFONTID_STATUSCHANGES : MSGFONTID_MYMSG));
+ }
+ } else {
+ if (!skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset));
+ }
+
+ if (rtfMessage != NULL) {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s", rtfMessage);
+ } else {
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, formatted, MAKELONG(isSent, dat->isHistory));
+ }
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s", "\\b0\\ul0\\i0 ");
+ break;
+ }
+ case EVENTTYPE_FILE:
+ if (!skipFont)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(isSent ? MSGFONTID_MYMISC + iFontIDOffset : MSGFONTID_YOURMISC + iFontIDOffset));
+ {
+ char* szFileName = (char *)dbei.pBlob + sizeof(DWORD);
+ char* szDescr = szFileName + lstrlenA(szFileName) + 1;
+ TCHAR* tszFileName = DbGetEventStringT( &dbei, szFileName );
+ if ( *szDescr != 0 ) {
+ TCHAR* tszDescr = DbGetEventStringT( &dbei, szDescr );
+ TCHAR buf[1000];
+ mir_sntprintf( buf, SIZEOF(buf), _T("%s (%s)"), tszFileName, tszDescr );
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, buf, 0 );
+ mir_free( tszDescr );
+ }
+ else {
+ AppendUnicodeToBuffer(&buffer, &bufferEnd, &bufferAlloced, tszFileName, 0 );
+ }
+ mir_free( tszFileName );
+ }
+ break;
+ }
+ break;
+ }
+ case '*': // bold
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, isBold ? "\\b0 " : "\\b ");
+ isBold = !isBold;
+ break;
+ case '/': // italic
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, isItalic ? "\\i0 " : "\\i ");
+ isItalic = !isItalic;
+ break;
+ case '_': // italic
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, isUnderline ? "\\ul0 " : "\\ul ");
+ isUnderline = !isUnderline;
+ break;
+ case '-': { // grid line
+ TCHAR color = szTemplate[i + 2];
+ if (color >= '0' && color <= '4') {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par\\sl-1\\slmult0\\highlight%d\\cf%d\\-\\par\\sl0", MSGDLGFONTCOUNT + 8 + (color - '0'), MSGDLGFONTCOUNT + 7 + (color - '0'));
+ i++;
+ } else {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par\\sl-1\\slmult0\\highlight%d\\cf%d\\-\\par\\sl0", MSGDLGFONTCOUNT + 4, MSGDLGFONTCOUNT + 4);
+ }
+ break;
+ }
+ case '~': // font break (switch to default font...)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, GetRTFFont(isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset));
+ break;
+ case 'H': { // highlight
+ TCHAR color = szTemplate[i + 2];
+
+ if (color >= '0' && color <= '4') {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\highlight%d", MSGDLGFONTCOUNT + 8 + (color - '0'));
+ i++;
+ } else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\highlight%d", (MSGDLGFONTCOUNT + (dat->isHistory?5:1) + ((isSent) ? 1 : 0)));
+ break;
+ }
+ case '|': // tab
+ if (dwEffectiveFlags & MWF_LOG_INDENT)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\tab");
+ else
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " ");
+ break;
+ case 'f': { // font tag...
+ TCHAR code = szTemplate[i + 2];
+ int fontindex = -1;
+ switch (code) {
+ case 'd':
+ fontindex = isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset;
+ break;
+ case 'n':
+ fontindex = isSent ? MSGFONTID_MYNAME + iFontIDOffset : MSGFONTID_YOURNAME + iFontIDOffset;
+ break;
+ case 'm':
+ fontindex = isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset;
+ break;
+ case 'M':
+ fontindex = isSent ? MSGFONTID_MYMISC + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset;
+ break;
+ case 's':
+ fontindex = isSent ? MSGFONTID_SYMBOLS_OUT : MSGFONTID_SYMBOLS_IN;
+ break;
+ }
+ if (fontindex != -1) {
+ i++;
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", GetRTFFont(fontindex));
+ } else
+ skipToNext = TRUE;
+ break;
+ }
+ case 'c': { // font color (using one of the predefined 5 colors) or one of the standard font colors (m = message, d = date/time, n = nick)
+ TCHAR color = szTemplate[i + 2];
+ if (color >= '0' && color <= '4') {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\cf%d ", MSGDLGFONTCOUNT + 8 + (color - '0'));
+ i++;
+ } else if (color == (TCHAR)'d') {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\cf%d ", isSent ? MSGFONTID_MYTIME + iFontIDOffset : MSGFONTID_YOURTIME + iFontIDOffset);
+ i++;
+ } else if (color == (TCHAR)'m') {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\cf%d ", isSent ? MSGFONTID_MYMSG + iFontIDOffset : MSGFONTID_YOURMSG + iFontIDOffset);
+ i++;
+ } else if (color == (TCHAR)'n') {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\cf%d ", isSent ? MSGFONTID_MYNAME + iFontIDOffset : MSGFONTID_YOURNAME + iFontIDOffset);
+ i++;
+ } else if (color == (TCHAR)'s') {
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\cf%d ", isSent ? MSGFONTID_SYMBOLS_OUT : MSGFONTID_SYMBOLS_IN);
+ i++;
+ } else
+ skipToNext = TRUE;
+ break;
+ }
+ case '<': // bidi tag
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\rtlmark\\rtlch ");
+ break;
+ case '>': // bidi tag
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\ltrmark\\ltrch ");
+ break;
+ }
+ skip:
+ if (skipToNext) {
+ i++;
+ while (szTemplate[i] != '%' && i < iTemplateLen) i++;
+ } else
+ i += 2;
+ } else {
+ char temp[24];
+ mir_snprintf(temp, 24, "{\\uc1\\u%d?}", (int)ci);
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, temp);
+ i++;
+ }
+ }
+
+ if (dat->hHistoryEvents)
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, dat->szMicroLf, MSGDLGFONTCOUNT + 1 + ((isSent) ? 1 : 0), hDbEvent);
+
+ AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par");
+
+ if (streamData->dbei == 0)
+ free(dbei.pBlob);
+ HistoryEvents_ReleaseText(rtfMessage);
+
+ dat->iLastEventType = MAKELONG((dbei.flags & (DBEF_SENT | DBEF_READ | DBEF_RTL)), dbei.eventType);
+ dat->lastEventTime = dbei.timestamp;
+ return buffer;
+}
+
+static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb)
+{
+ struct LogStreamData *dat = (struct LogStreamData *) dwCookie;
+
+ if (dat->buffer == NULL) {
+ dat->bufferOffset = 0;
+ switch (dat->stage) {
+ case STREAMSTAGE_HEADER:
+ if (dat->buffer) free(dat->buffer);
+ dat->buffer = CreateRTFHeader(dat->dlgDat);
+ dat->stage = STREAMSTAGE_EVENTS;
+ break;
+ case STREAMSTAGE_EVENTS:
+ if (dat->eventsToInsert) {
+ do {
+ if (dat->buffer) free(dat->buffer);
+ dat->buffer = Template_CreateRTFFromDbEvent(dat->dlgDat, dat->hContact, dat->hDbEvent, !dat->isEmpty, dat);
+ if (dat->buffer)
+ dat->hDbEventLast = dat->hDbEvent;
+ dat->hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, (WPARAM) dat->hDbEvent, 0);
+ if (--dat->eventsToInsert == 0)
+ break;
+ } while (dat->buffer == NULL && dat->hDbEvent);
+ if (dat->buffer) {
+ //dat->isEmpty = 0;
+ break;
+ }
+ }
+ dat->stage = STREAMSTAGE_TAIL;
+ //fall through
+ case STREAMSTAGE_TAIL: {
+ if (dat->buffer) free(dat->buffer);
+ dat->buffer = CreateRTFTail(dat->dlgDat);
+ dat->stage = STREAMSTAGE_STOP;
+ break;
+ }
+ case STREAMSTAGE_STOP:
+ *pcb = 0;
+ return 0;
+ }
+ dat->bufferLen = lstrlenA(dat->buffer);
+ }
+ *pcb = min(cb, dat->bufferLen - dat->bufferOffset);
+ CopyMemory(pbBuff, dat->buffer + dat->bufferOffset, *pcb);
+ dat->bufferOffset += *pcb;
+ if (dat->bufferOffset == dat->bufferLen) {
+ free(dat->buffer);
+ dat->buffer = NULL;
+ }
+ return 0;
+}
+
+static void SetupLogFormatting(struct TWindowData *dat)
+{
+ if (dat->hHistoryEvents) {
+ mir_snprintf(dat->szMicroLf, sizeof(dat->szMicroLf), "%s", "\\v\\cf%d \\ ~-+%d+-~\\v0 ");
+ } else {
+ mir_snprintf(dat->szMicroLf, sizeof(dat->szMicroLf), "%s\\par\\ltrpar\\sl-1%s ", GetRTFFont(MSGDLGFONTCOUNT), GetRTFFont(MSGDLGFONTCOUNT));
+ }
+}
+
+void TSAPI StreamInEvents(HWND hwndDlg, HANDLE hDbEventFirst, int count, int fAppend, DBEVENTINFO *dbei_s)
+{
+ EDITSTREAM stream = { 0 };
+ struct LogStreamData streamData = { 0 };
+ struct TWindowData *dat = (struct TWindowData *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ CHARRANGE oldSel, sel;
+ HWND hwndrtf;
+ LONG startAt = 0;
+ FINDTEXTEXA fi;
+ struct tm tm_now, tm_today;
+ time_t now;
+ SCROLLINFO si = {0}, *psi = &si;
+ POINT pt = {0};
+ BOOL wasFirstAppend = (dat->isAutoRTL & 2) ? TRUE : FALSE;
+ BOOL isSent;
+
+
+ /*
+ * calc time limit for grouping
+ */
+
+ hwndrtf = dat->hwndIEView ? dat->hwndIWebBrowserControl : GetDlgItem(hwndDlg, IDC_LOG);
+
+ si.cbSize = sizeof(si);
+ /*
+ if (IsWindow(hwndrtf)) {
+ si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;;
+ GetScrollInfo(hwndrtf, SB_VERT, &si);
+ SendMessage(hwndrtf, EM_GETSCROLLPOS, 0, (LPARAM) &pt);
+
+ if (GetWindowLongPtr(hwndrtf, GWL_STYLE) & WS_VSCROLL)
+ psi = &si;
+ else
+ psi = NULL;
+ }
+ */
+
+ rtfFonts = dat->pContainer->theme.rtfFonts ? dat->pContainer->theme.rtfFonts : &(rtfFontsGlobal[0][0]);
+ now = time(NULL);
+
+ tm_now = *localtime(&now);
+ tm_today = tm_now;
+ tm_today.tm_hour = tm_today.tm_min = tm_today.tm_sec = 0;
+ today = mktime(&tm_today);
+
+ if (dat->hwndIEView != 0) {
+ IEVIEWEVENT event;
+
+ ZeroMemory(&event, sizeof(event));
+ event.cbSize = sizeof(IEVIEWEVENT);
+ event.hwnd = dat->hwndIEView;
+ event.hContact = dat->hContact;
+ event.dwFlags = (dat->dwFlags & MWF_LOG_RTL) ? IEEF_RTL : 0;
+ if (dat->sendMode & SMODE_FORCEANSI) {
+ event.dwFlags |= IEEF_NO_UNICODE;
+ event.codepage = dat->codePage;
+ } else
+ event.codepage = 0;
+ if (!fAppend) {
+ event.iType = IEE_CLEAR_LOG;
+ CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event);
+ }
+ event.iType = IEE_LOG_DB_EVENTS;
+ event.hDbEventFirst = hDbEventFirst;
+ event.count = count;
+ event.pszProto = dat->szProto;
+ CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event);
+ DM_ScrollToBottom(dat, 0, 0);
+ if (fAppend)
+ dat->hDbEventLast = hDbEventFirst;
+ else
+ dat->hDbEventLast = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)dat->hContact, 0);
+ return;
+ }
+ if (dat->hwndHPP != 0) {
+ IEVIEWEVENT event;
+
+ event.cbSize = sizeof(IEVIEWEVENT);
+ event.hwnd = dat->hwndHPP;
+ event.hContact = dat->hContact;
+ event.dwFlags = (dat->dwFlags & MWF_LOG_RTL) ? IEEF_RTL : 0;
+ if (dat->sendMode & SMODE_FORCEANSI) {
+ event.dwFlags |= IEEF_NO_UNICODE;
+ event.codepage = dat->codePage;
+ } else
+ event.codepage = 0;
+ if (!fAppend) {
+ event.iType = IEE_CLEAR_LOG;
+ CallService(MS_HPP_EG_EVENT, 0, (LPARAM)&event);
+ }
+ event.iType = IEE_LOG_DB_EVENTS;
+ event.hDbEventFirst = hDbEventFirst;
+ event.count = count;
+ CallService(MS_HPP_EG_EVENT, 0, (LPARAM)&event);
+ //SendMessage(hwndDlg, DM_FORCESCROLL, (WPARAM)&pt, (LPARAM)&si);
+ DM_ScrollToBottom(dat, 0, 0);
+ if (fAppend)
+ dat->hDbEventLast = hDbEventFirst;
+ else
+ dat->hDbEventLast = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)dat->hContact, 0);
+ return;
+ }
+
+ // separator strings used for grid lines, message separation and so on...
+
+ dat->clr_added = FALSE;
+
+ if (dat->szMicroLf[0] == 0)
+ SetupLogFormatting(dat);
+
+ szYourName = const_cast<TCHAR *>(dat->cache->getNick());
+ szMyName = dat->szMyNickname;
+
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_HIDESELECTION, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXGETSEL, 0, (LPARAM) & oldSel);
+ streamData.hContact = dat->hContact;
+ streamData.hDbEvent = hDbEventFirst;
+ streamData.dlgDat = dat;
+ streamData.eventsToInsert = count;
+ streamData.isEmpty = fAppend ? GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOG)) == 0 : 1;
+ streamData.dbei = dbei_s;
+ stream.pfnCallback = LogStreamInEvents;
+ stream.dwCookie = (DWORD_PTR) & streamData;
+ streamData.isAppend = fAppend;
+
+ if (fAppend) {
+ GETTEXTLENGTHEX gtxl = {0};
+ gtxl.codepage = 1200;
+ gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMCHARS;
+ fi.chrg.cpMin = SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETTEXTLENGTHEX, (WPARAM) & gtxl, 0);
+ sel.cpMin = sel.cpMax = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOG));
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM) & sel);
+ } else {
+ SetDlgItemText(hwndDlg, IDC_LOG, _T(""));
+ sel.cpMin = 0;
+ sel.cpMax = GetWindowTextLength(hwndrtf);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM) &sel);
+ fi.chrg.cpMin = 0;
+ dat->isAutoRTL = 0;
+ }
+ startAt = fi.chrg.cpMin;
+
+ SendMessage(hwndrtf, WM_SETREDRAW, FALSE, 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_STREAMIN, fAppend ? SFF_SELECTION | SF_RTF : SFF_SELECTION | SF_RTF, (LPARAM) & stream);
+ //SendDlgItemMessage(hwndDlg, IDC_LOG, EM_STREAMIN, fAppend ? SFF_SELECTION | SF_RTF : SF_RTF, (LPARAM) & stream);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM) & oldSel);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_HIDESELECTION, FALSE, 0);
+ dat->hDbEventLast = streamData.hDbEventLast;
+
+ if (dat->isAutoRTL & 1) {
+ SendMessage(hwndrtf, EM_SETBKGNDCOLOR, 0, LOWORD(dat->iLastEventType) & DBEF_SENT ? (fAppend?dat->pContainer->theme.outbg : dat->pContainer->theme.oldoutbg) :
+ (fAppend?dat->pContainer->theme.inbg : dat->pContainer->theme.oldinbg));
+ }
+
+ if (!(dat->isAutoRTL & 1)) {
+ GETTEXTLENGTHEX gtxl = {0};
+ PARAFORMAT2 pf2;
+
+ gtxl.codepage = 1200;
+ gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMCHARS;
+ ZeroMemory(&pf2, sizeof(PARAFORMAT2));
+ sel.cpMax = SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETTEXTLENGTHEX, (WPARAM) & gtxl, 0);
+ sel.cpMin = sel.cpMax - 1;
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM) & sel);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, EM_REPLACESEL, FALSE, (LPARAM)_T(""));
+ dat->isAutoRTL |= 2;
+ }
+
+ if (streamData.dbei != 0)
+ isSent = (streamData.dbei->flags & DBEF_SENT) != 0;
+ else {
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ CallService(MS_DB_EVENT_GET, (WPARAM) hDbEventFirst, (LPARAM)&dbei);
+ isSent = (dbei.flags & DBEF_SENT) != 0;
+ }
+
+ ReplaceIcons(hwndDlg, dat, startAt, fAppend, isSent);
+ dat->clr_added = FALSE;
+
+ SendMessage(hwndDlg, DM_FORCESCROLL, (WPARAM)&pt, (LPARAM)psi);
+ SendDlgItemMessage(hwndDlg, IDC_LOG, WM_SETREDRAW, TRUE, 0);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_LOG), NULL, FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_QUOTE), dat->hDbEventLast != NULL);
+ if (streamData.buffer) free(streamData.buffer);
+}
+
+static void ReplaceIcons(HWND hwndDlg, struct TWindowData *dat, LONG startAt, int fAppend, BOOL isSent)
+{
+ FINDTEXTEXA fi;
+ CHARFORMAT2 cf2;
+ HWND hwndrtf;
+ IRichEditOle *ole;
+ TEXTRANGEA tr;
+ COLORREF crDefault;
+ struct TLogIcon theIcon;
+ char trbuffer[40];
+ DWORD dwScale = M->GetDword("iconscale", 0);
+ tr.lpstrText = trbuffer;
+
+ hwndrtf = GetDlgItem(hwndDlg, IDC_LOG);
+ fi.chrg.cpMin = startAt;
+ if (dat->clr_added) {
+ unsigned int length;
+ int index;
+ CHARRANGE cr;
+ fi.lpstrText = "##col##";
+ fi.chrg.cpMax = -1;
+ ZeroMemory((void *)&cf2, sizeof(cf2));
+ cf2.cbSize = sizeof(cf2);
+ cf2.dwMask = CFM_COLOR;
+ while (SendMessageA(hwndrtf, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) > -1) {
+ tr.chrg.cpMin = fi.chrgText.cpMin;
+ tr.chrg.cpMax = tr.chrg.cpMin + 18;
+ trbuffer[0] = 0;
+ SendMessageA(hwndrtf, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
+ trbuffer[18] = 0;
+ cr.cpMin = fi.chrgText.cpMin;
+ cr.cpMax = cr.cpMin + 18;
+ SendMessage(hwndrtf, EM_EXSETSEL, 0, (LPARAM)&cr);
+ SendMessageA(hwndrtf, EM_REPLACESEL, FALSE, (LPARAM)"");
+ length = (unsigned int)atol(&trbuffer[7]);
+ index = atol(&trbuffer[14]);
+ if (length > 0 && length < 20000 && index >= RTF_CTABLE_DEFSIZE && index < Utils::rtf_ctable_size) {
+ cf2.crTextColor = Utils::rtf_ctable[index].clr;
+ cr.cpMin = fi.chrgText.cpMin;
+ cr.cpMax = cr.cpMin + length;
+ SendMessage(hwndrtf, EM_EXSETSEL, 0, (LPARAM)&cr);
+ SendMessage(hwndrtf, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
+ }
+ }
+ }
+ fi.chrg.cpMin = startAt;
+ if (dat->dwFlags & MWF_LOG_SHOWICONS) {
+ BYTE bIconIndex = 0;
+ char bDirection = 0;
+ CHARRANGE cr;
+ fi.lpstrText = "#~#";
+ fi.chrg.cpMax = -1;
+ ZeroMemory((void *)&cf2, sizeof(cf2));
+ cf2.cbSize = sizeof(cf2);
+ cf2.dwMask = CFM_BACKCOLOR;
+
+ SendMessage(hwndrtf, EM_GETOLEINTERFACE, 0, (LPARAM)&ole);
+ while (SendMessageA(hwndrtf, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) > -1) {
+ cr.cpMin = fi.chrgText.cpMin;
+ cr.cpMax = fi.chrgText.cpMax + 2;
+ SendMessage(hwndrtf, EM_EXSETSEL, 0, (LPARAM)&cr);
+
+ tr.chrg.cpMin = fi.chrgText.cpMin + 3;
+ tr.chrg.cpMax = fi.chrgText.cpMin + 5;
+ SendMessageA(hwndrtf, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
+ bIconIndex = ((BYTE)trbuffer[0] - (BYTE)'0');
+ if (bIconIndex >= NR_LOGICONS) {
+ fi.chrg.cpMin = fi.chrgText.cpMax + 6;
+ continue;
+ }
+ bDirection = trbuffer[1];
+ SendMessage(hwndrtf, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
+ crDefault = cf2.crBackColor == 0 ? (true ? (bDirection == '>' ? (fAppend ? dat->pContainer->theme.outbg : dat->pContainer->theme.oldoutbg) :
+ (fAppend ? dat->pContainer->theme.inbg : dat->pContainer->theme.oldinbg)) : dat->pContainer->theme.bg) : cf2.crBackColor;
+ CacheIconToBMP(&theIcon, Logicons[bIconIndex], crDefault, dwScale, dwScale);
+ ImageDataInsertBitmap(ole, theIcon.hBmp);
+ DeleteCachedIcon(&theIcon);
+ fi.chrg.cpMin = cr.cpMax + 6;
+ }
+ ReleaseRichEditOle(ole);
+ }
+ /*
+ * do smiley replacing, using the service
+ */
+
+ if (PluginConfig.g_SmileyAddAvail) {
+ CHARRANGE sel;
+ SMADD_RICHEDIT3 smadd;
+
+ sel.cpMin = startAt;
+ sel.cpMax = -1;
+
+ ZeroMemory(&smadd, sizeof(smadd));
+
+ smadd.cbSize = sizeof(smadd);
+ smadd.hwndRichEditControl = GetDlgItem(hwndDlg, IDC_LOG);
+ smadd.Protocolname = const_cast<char *>(dat->cache->getActiveProto());
+ smadd.hContact = dat->cache->getActiveContact();
+ smadd.flags = isSent ? SAFLRE_OUTGOING : 0;
+
+ if (startAt > 0)
+ smadd.rangeToReplace = &sel;
+ else
+ smadd.rangeToReplace = NULL;
+ smadd.disableRedraw = TRUE;
+ if (dat->doSmileys)
+ CallService(MS_SMILEYADD_REPLACESMILEYS, TABSRMM_SMILEYADD_BKGCOLORMODE, (LPARAM)&smadd);
+ }
+
+ if (PluginConfig.m_MathModAvail) {
+ TMathRicheditInfo mathReplaceInfo;
+ CHARRANGE mathNewSel;
+ mathNewSel.cpMin = startAt;
+ mathNewSel.cpMax = -1;
+ mathReplaceInfo.hwndRichEditControl = GetDlgItem(hwndDlg, IDC_LOG);
+ if (startAt > 0) mathReplaceInfo.sel = & mathNewSel;
+ else mathReplaceInfo.sel = 0;
+ mathReplaceInfo.disableredraw = TRUE;
+ CallService(MATH_RTF_REPLACE_FORMULAE, 0, (LPARAM)&mathReplaceInfo);
+ }
+
+ if (dat->hHistoryEvents && dat->curHistory == dat->maxHistory) {
+ char szPattern[50];
+ FINDTEXTEXA fi;
+
+ _snprintf(szPattern, 40, "~-+%d+-~", (INT_PTR)dat->hHistoryEvents[0]);
+ fi.lpstrText = szPattern;
+ fi.chrg.cpMin = 0;
+ fi.chrg.cpMax = -1;
+ if (SendMessageA(hwndrtf, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) != 0) {
+ CHARRANGE sel;
+ sel.cpMin = 0;
+ sel.cpMax = 20;
+ SendMessage(hwndrtf, EM_SETSEL, 0, fi.chrgText.cpMax + 1);
+ SendMessageA(hwndrtf, EM_REPLACESEL, TRUE, (LPARAM)"");
+ }
+ }
+}
+
+/*
+ * NLS functions (for unicode version only) encoding stuff..
+ */
+
+static BOOL CALLBACK LangAddCallback(LPTSTR str)
+{
+ int i, count;
+ UINT cp;
+
+ cp = _ttoi(str);
+ count = sizeof(cpTable) / sizeof(cpTable[0]);
+ for (i = 0; i < count && cpTable[i].cpId != cp; i++);
+ if (i < count) {
+ AppendMenu(PluginConfig.g_hMenuEncoding, MF_STRING, cp, TranslateTS(cpTable[i].cpName));
+ }
+ return TRUE;
+}
+
+void TSAPI BuildCodePageList()
+{
+ PluginConfig.g_hMenuEncoding = CreateMenu();
+ AppendMenu(PluginConfig.g_hMenuEncoding, MF_STRING, 500, CTranslator::get(CTranslator::GEN_LOG_USEDEFAULTCP));
+ AppendMenuA(PluginConfig.g_hMenuEncoding, MF_SEPARATOR, 0, 0);
+ EnumSystemCodePages(LangAddCallback, CP_INSTALLED);
+}
+
+static TCHAR *Template_MakeRelativeDate(struct TWindowData *dat, HANDLE hTimeZone, time_t check, int groupBreak, TCHAR code)
+{
+ static TCHAR szResult[100];
+ const TCHAR *szFormat;
+
+ if ((code == (TCHAR)'R' || code == (TCHAR)'r') && check >= today) {
+ _tcscpy(szResult, szToday);
+ } else if ((code == (TCHAR)'R' || code == (TCHAR)'r') && check > (today - 86400)) {
+ _tcscpy(szResult, szYesterday);
+ } else {
+ if (code == 'D' || code == 'R')
+ szFormat = _T("D");
+ else if (code == 'T')
+ szFormat = _T("s");
+ else if (code == 't')
+ szFormat = _T("t");
+ else
+ szFormat = _T("d");
+
+ tmi.printTimeStamp(hTimeZone, check, szFormat, szResult, safe_sizeof(szResult), 0);
+ }
+ return szResult;
+}
+
diff --git a/plugins/TabSRMM/src/msgoptions.cpp b/plugins/TabSRMM/src/msgoptions.cpp
new file mode 100644
index 0000000000..7438925df1
--- /dev/null
+++ b/plugins/TabSRMM/src/msgoptions.cpp
@@ -0,0 +1,1787 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: msgoptions.cpp 13750 2011-08-03 20:10:43Z george.hazan $
+ *
+ * Implementation of the option pages
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+#include <m_modernopt.h>
+
+#define DM_GETSTATUSMASK (WM_USER + 10)
+
+extern INT_PTR CALLBACK DlgProcPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+extern INT_PTR CALLBACK DlgProcTabConfig(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+extern INT_PTR CALLBACK DlgProcTemplateEditor(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+extern INT_PTR CALLBACK DlgProcToolBar(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+extern INT_PTR CALLBACK PlusOptionsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+extern INT_PTR CALLBACK DlgProcOptions1(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+extern INT_PTR CALLBACK DlgProcOptions2(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+extern INT_PTR CALLBACK DlgProcOptions3(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+INT_PTR CALLBACK DlgProcSetupStatusModes(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+struct FontOptionsList {
+ COLORREF defColour;
+ char *szDefFace;
+ BYTE defStyle;
+ char defSize;
+}
+
+static fontOptionsList[] = {
+ {RGB(0, 0, 0), "Tahoma", 0, -10}
+};
+
+
+static HIMAGELIST g_himlStates = 0;
+HIMAGELIST CreateStateImageList()
+{
+ if (g_himlStates == 0) {
+ g_himlStates = ImageList_Create(16, 16, PluginConfig.m_bIsXP ? ILC_COLOR32 | ILC_MASK : ILC_COLOR8 | ILC_MASK, 4, 0);
+ ImageList_AddIcon(g_himlStates, PluginConfig.g_IconFolder);
+ ImageList_AddIcon(g_himlStates, PluginConfig.g_IconFolder);
+ ImageList_AddIcon(g_himlStates, PluginConfig.g_IconUnchecked);
+ ImageList_AddIcon(g_himlStates, PluginConfig.g_IconChecked);
+ }
+ return g_himlStates;
+}
+
+
+static BYTE MsgDlgGetFontDefaultCharset(const char* szFont)
+{
+ return DEFAULT_CHARSET;
+}
+
+void TSAPI LoadLogfont(int i, LOGFONTA * lf, COLORREF * colour, char *szModule)
+{
+ LOGFONT lfResult;
+ LoadMsgDlgFont((i < 100) ? FONTSECTION_IM : FONTSECTION_IP, i, &lfResult, colour, szModule);
+ if (lf)
+ {
+ lf->lfHeight = lfResult.lfHeight;
+ lf->lfWidth = lfResult.lfWidth;
+ lf->lfEscapement = lfResult.lfEscapement;
+ lf->lfOrientation = lfResult.lfOrientation;
+ lf->lfWeight = lfResult.lfWeight;
+ lf->lfItalic = lfResult.lfItalic;
+ lf->lfUnderline = lfResult.lfUnderline;
+ lf->lfStrikeOut = lfResult.lfStrikeOut;
+ lf->lfCharSet = lfResult.lfCharSet;
+ lf->lfOutPrecision = lfResult.lfOutPrecision;
+ lf->lfClipPrecision = lfResult.lfClipPrecision;
+ lf->lfQuality = lfResult.lfQuality;
+ lf->lfPitchAndFamily = lfResult.lfPitchAndFamily;
+ wsprintfA(lf->lfFaceName, "%S", lfResult.lfFaceName);
+ }
+}
+
+HIMAGELIST g_himlOptions;
+
+static HWND hwndTabConfig = 0;
+
+/**
+ * scan a single skin directory and find the .TSK file. Fill the combobox and set the
+ * relative path name as item extra data.
+ *
+ * If available, read the Name property from the [Global] section and use it in the
+ * combo box. If such property is not found, the base filename (without .tsk extension)
+ * will be used as the name of the skin.
+ *
+ * [Global]/Name property is new in TabSRMM version 3.
+ */
+static int TSAPI ScanSkinDir(const TCHAR* tszFolder, HWND hwndCombobox)
+{
+ WIN32_FIND_DATA fd = {0};
+ bool fValid = false;
+ TCHAR tszMask[MAX_PATH];
+
+ mir_sntprintf(tszMask, MAX_PATH, _T("%s*.*"), tszFolder);
+
+ HANDLE h = FindFirstFile(tszMask, &fd);
+
+ while(h != INVALID_HANDLE_VALUE) {
+ if(lstrlen(fd.cFileName) >= 5 && !_tcsnicmp(fd.cFileName + lstrlen(fd.cFileName) - 4, _T(".tsk"), 4)) {
+ fValid = true;
+ break;
+ }
+ if(FindNextFile(h, &fd) == 0)
+ break;
+ }
+ if(h != INVALID_HANDLE_VALUE)
+ FindClose(h);
+
+ if(fValid) {
+ TCHAR tszFinalName[MAX_PATH], tszRel[MAX_PATH];
+ LRESULT lr;
+ TCHAR szBuf[255];
+
+ mir_sntprintf(tszFinalName, MAX_PATH, _T("%s%s"), tszFolder, fd.cFileName);
+
+ GetPrivateProfileString(_T("Global"), _T("Name"), _T("None"), szBuf, 500, tszFinalName);
+ if(!_tcscmp(szBuf, _T("None"))) {
+ fd.cFileName[lstrlen(fd.cFileName) - 4] = 0;
+ mir_sntprintf(szBuf, 255, _T("%s"), fd.cFileName);
+ }
+
+ M->pathToRelative(tszFinalName, tszRel, M->getSkinPath());
+ if((lr = SendMessage(hwndCombobox, CB_INSERTSTRING, -1, (LPARAM)szBuf)) != CB_ERR) {
+ TCHAR *idata = (TCHAR *)malloc((lstrlen(tszRel) + 1) * sizeof(TCHAR));
+
+ _tcscpy(idata, tszRel);
+ SendMessage(hwndCombobox, CB_SETITEMDATA, lr, (LPARAM)idata);
+ }
+ }
+ return(0);
+}
+
+/**
+ * scan the skin root folder for subfolder(s). Each folder is supposed to contain a single
+ * skin. This function won't dive deeper into the folder structure, so the folder
+ * structure for any VALID skin should be:
+ * $SKINS_ROOT/skin_folder/skin_name.tsk
+ *
+ * By default, $SKINS_ROOT is set to %miranda_userdata% or custom folder
+ * selected by the folders plugin.
+ */
+static int TSAPI RescanSkins(HWND hwndCombobox)
+{
+ WIN32_FIND_DATA fd = {0};
+ TCHAR tszSkinRoot[MAX_PATH], tszFindMask[MAX_PATH];
+ DBVARIANT dbv = {0};
+
+
+ mir_sntprintf(tszSkinRoot, MAX_PATH, _T("%s"), M->getSkinPath());
+
+ SetDlgItemText(GetParent(hwndCombobox), IDC_SKINROOTFOLDER, tszSkinRoot);
+ mir_sntprintf(tszFindMask, MAX_PATH, _T("%s*.*"), tszSkinRoot);
+
+ SendMessage(hwndCombobox, CB_RESETCONTENT, 0, 0);
+ SendMessage(hwndCombobox, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_SKIN_NOSKINSELECT));
+
+ HANDLE h = FindFirstFile(tszFindMask, &fd);
+ while (h != INVALID_HANDLE_VALUE) {
+ if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && fd.cFileName[0] != '.') {
+ TCHAR tszSubDir[MAX_PATH];
+ mir_sntprintf(tszSubDir, MAX_PATH, _T("%s%s\\"), tszSkinRoot, fd.cFileName);
+ ScanSkinDir(tszSubDir, hwndCombobox);
+ }
+ if(FindNextFile(h, &fd) == 0)
+ break;
+ }
+ if(h != INVALID_HANDLE_VALUE)
+ FindClose(h);
+
+
+ SendMessage(hwndCombobox, CB_SETCURSEL, 0, 0);
+ if(0 == M->GetTString(0, SRMSGMOD_T, "ContainerSkin", &dbv)) {
+ LRESULT lr = SendMessage(hwndCombobox, CB_GETCOUNT, 0, 0);
+ for(int i = 1; i < lr; i++) {
+
+ TCHAR* idata = (TCHAR *)SendMessage(hwndCombobox, CB_GETITEMDATA, i, 0);
+ if(idata && idata != (TCHAR *)CB_ERR) {
+ if(!_tcsicmp(dbv.ptszVal, idata)) {
+ SendMessage(hwndCombobox, CB_SETCURSEL, i, 0);
+ break;
+ }
+ }
+ }
+ DBFreeVariant(&dbv);
+ }
+ return(0);
+}
+
+/**
+ * free the item extra data (used to store the skin filenames for
+ * each entry).
+ */
+static void TSAPI FreeComboData(HWND hwndCombobox)
+{
+ LRESULT lr = SendMessage(hwndCombobox, CB_GETCOUNT, 0, 0);
+
+ for(int i = 1; i < lr; i++) {
+ void *idata = (void *)SendMessage(hwndCombobox, CB_GETITEMDATA, i, 0);
+
+ if(idata && idata != (void *)CB_ERR)
+ free(idata);
+ }
+}
+
+/*
+ * controls to disable when loading or unloading a skin is not possible (because
+ * of at least one message window being open).
+ */
+static UINT _ctrls[] = { IDC_SKINNAME, IDC_RESCANSKIN, IDC_RESCANSKIN, IDC_RELOADSKIN, 0 };
+
+static INT_PTR CALLBACK DlgProcSkinOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG: {
+ RescanSkins(GetDlgItem(hwndDlg, IDC_SKINNAME));
+ BYTE loadMode = M->GetByte("skin_loadmode", 0);
+ TranslateDialogDefault(hwndDlg);
+
+ CheckDlgButton(hwndDlg, IDC_USESKIN, M->GetByte("useskin", 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SKIN_LOADFONTS, loadMode & THEME_READ_FONTS);
+ CheckDlgButton(hwndDlg, IDC_SKIN_LOADTEMPLATES, loadMode & THEME_READ_TEMPLATES);
+
+ SendMessage(hwndDlg, WM_USER + 100, 0, 0);
+ SetTimer(hwndDlg, 1000, 100, 0);
+ return TRUE;
+ }
+
+ case WM_CTLCOLORSTATIC:
+ if((HWND)lParam == GetDlgItem(hwndDlg, IDC_SKIN_WARN)) {
+ SetTextColor((HDC)wParam, RGB(255, 50, 50));
+ return(0);
+ }
+ break;
+
+ /*
+ * self - configure the dialog, don't let the user load or unload
+ * a skin while a message window is open. Show the warning that all
+ * windows must be closed.
+ */
+ case WM_USER + 100: {
+ bool fWindowsOpen = (pFirstContainer != 0 ? true : false);
+ UINT i = 0;
+
+ while(_ctrls[i]) {
+ Utils::enableDlgControl(hwndDlg, _ctrls[i], fWindowsOpen ? FALSE : TRUE);
+ i++;
+ }
+ Utils::showDlgControl(hwndDlg, IDC_SKIN_WARN, fWindowsOpen ? SW_SHOW : SW_HIDE);
+ Utils::showDlgControl(hwndDlg, IDC_SKIN_CLOSENOW, fWindowsOpen ? SW_SHOW : SW_HIDE);
+ return(0);
+ }
+
+ case WM_TIMER:
+ if(wParam == 1000)
+ SendMessage(hwndDlg, WM_USER + 100, 0, 0);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_USESKIN:
+ M->WriteByte(SRMSGMOD_T, "useskin", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_USESKIN) ? 1 : 0));
+ break;
+
+ case IDC_SKIN_LOADFONTS: {
+ BYTE loadMode = M->GetByte("skin_loadmode", 0);
+ loadMode = IsDlgButtonChecked(hwndDlg, IDC_SKIN_LOADFONTS) ? loadMode | THEME_READ_FONTS : loadMode & ~THEME_READ_FONTS;
+ M->WriteByte(SRMSGMOD_T, "skin_loadmode", loadMode);
+ break;
+ }
+
+ case IDC_SKIN_LOADTEMPLATES: {
+ BYTE loadMode = M->GetByte("skin_loadmode", 0);
+ loadMode = IsDlgButtonChecked(hwndDlg, IDC_SKIN_LOADTEMPLATES) ? loadMode | THEME_READ_TEMPLATES : loadMode & ~THEME_READ_TEMPLATES;
+ M->WriteByte(SRMSGMOD_T, "skin_loadmode", loadMode);
+ break;
+ }
+
+ case IDC_UNLOAD:
+ Skin->Unload();
+ SendMessage(hwndTabConfig, WM_USER + 100, 0, 0);
+ break;
+
+ case IDC_RELOADSKIN:
+ Skin->setFileName();
+ Skin->Load();
+ SendMessage(hwndTabConfig, WM_USER + 100, 0, 0);
+ break;
+
+ case IDC_RESCANSKIN:
+ FreeComboData(GetDlgItem(hwndDlg, IDC_SKINNAME));
+ RescanSkins(GetDlgItem(hwndDlg, IDC_SKINNAME));
+ break;
+
+ case IDC_THEMEEXPORT: {
+ const TCHAR *szFilename = GetThemeFileName(1);
+ if (szFilename != NULL)
+ WriteThemeToINI(szFilename, 0);
+ break;
+ }
+
+ case IDC_THEMEIMPORT: {
+ LRESULT r;
+
+ if(CSkin::m_skinEnabled) {
+ r = CWarning::show(CWarning::WARN_THEME_OVERWRITE, MB_YESNOCANCEL|MB_ICONQUESTION);
+ if(r == IDNO || r == IDCANCEL)
+ return(0);
+ }
+
+ r = CWarning::show(CWarning::WARN_OPTION_CLOSE, MB_YESNOCANCEL|MB_ICONQUESTION);
+ if(r == IDNO || r == IDCANCEL)
+ return(0);
+
+ const wchar_t* szFilename = GetThemeFileName(0);
+ DWORD dwFlags = THEME_READ_FONTS;
+ int result;
+
+ if (szFilename != NULL) {
+ result = MessageBox(0, CTranslator::get(CTranslator::GEN_WARNING_LOADTEMPLATES),
+ CTranslator::get(CTranslator::GEN_TITLE_LOADTHEME), MB_YESNOCANCEL);
+ if (result == IDCANCEL)
+ return 1;
+ else if (result == IDYES)
+ dwFlags |= THEME_READ_TEMPLATES;
+ ReadThemeFromINI(szFilename, 0, 0, dwFlags);
+ CacheLogFonts();
+ CacheMsgLogIcons();
+ PluginConfig.reloadSettings();
+ CSkin::setAeroEffect(-1);
+ M->BroadcastMessage(DM_OPTIONSAPPLIED, 1, 0);
+ M->BroadcastMessage(DM_FORCEDREMAKELOG, 0, 0);
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, IDCANCEL, 0);
+ }
+ break;
+ }
+
+ case IDC_HELP_GENERAL:
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://blog.miranda.or.at/tabsrmm/skin-selection-changes/");
+ break;
+
+ case IDC_SKIN_CLOSENOW: {
+ BOOL fOldHideSetting = PluginConfig.m_HideOnClose;
+
+ PluginConfig.m_HideOnClose = FALSE;
+
+ while(pFirstContainer) {
+ if(pFirstContainer->hwnd)
+ SendMessage(pFirstContainer->hwnd, WM_CLOSE, 0, 1);
+ }
+
+ PluginConfig.m_HideOnClose = fOldHideSetting;
+ break;
+ }
+ case IDC_SKINNAME: {
+ if(HIWORD(wParam) == CBN_SELCHANGE) {
+ LRESULT lr = SendDlgItemMessage(hwndDlg, IDC_SKINNAME, CB_GETCURSEL, 0 ,0);
+ if(lr != CB_ERR && lr > 0) {
+ TCHAR *tszRelPath = (TCHAR *)SendDlgItemMessage(hwndDlg, IDC_SKINNAME, CB_GETITEMDATA, lr, 0);
+ if(tszRelPath && tszRelPath != (TCHAR *)CB_ERR)
+ M->WriteTString(0, SRMSGMOD_T, "ContainerSkin", tszRelPath);
+ SendMessage(hwndDlg, WM_COMMAND, IDC_RELOADSKIN, 0);
+ }
+ else if(lr == 0) { // selected the <no skin> entry
+ DBDeleteContactSetting(0, SRMSGMOD_T, "ContainerSkin");
+ Skin->Unload();
+ SendMessage(hwndTabConfig, WM_USER + 100, 0, 0);
+ }
+ return(0);
+ }
+ break;
+ }
+ }
+ if ((LOWORD(wParam) == IDC_SKINNAME)
+ && (HIWORD(wParam) != CBN_SELCHANGE || (HWND) lParam != GetFocus()))
+ return 0;
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ return TRUE;
+ }
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+ KillTimer(hwndDlg, 1000);
+ FreeComboData(GetDlgItem(hwndDlg, IDC_SKINNAME));
+ break;
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK DlgProcOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG: {
+ BOOL translated;
+ TVINSERTSTRUCT tvi = {0};
+ int i = 0;
+
+ DWORD dwFlags = DBGetContactSettingDword(NULL, SRMSGMOD_T, "mwflags", MWF_LOG_DEFAULT);
+
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_WINDOWOPTIONS), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_WINDOWOPTIONS), GWL_STYLE) | (TVS_NOHSCROLL | TVS_CHECKBOXES));
+
+
+ g_himlOptions = (HIMAGELIST)SendDlgItemMessage(hwndDlg, IDC_WINDOWOPTIONS, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)CreateStateImageList());
+ ImageList_Destroy(g_himlOptions);
+
+ /*
+ * fill the list box, create groups first, then add items
+ */
+
+ TOptionListGroup *defaultGroups = CTranslator::getGroupTree(CTranslator::TREE_MSG);
+
+ while (defaultGroups[i].szName != NULL) {
+ tvi.hParent = 0;
+ tvi.hInsertAfter = TVI_LAST;
+ tvi.item.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.item.pszText = defaultGroups[i].szName;
+ tvi.item.stateMask = TVIS_STATEIMAGEMASK | TVIS_EXPANDED | TVIS_BOLD;
+ tvi.item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_EXPANDED | TVIS_BOLD;
+ defaultGroups[i++].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_WINDOWOPTIONS), &tvi);
+ }
+
+ i = 0;
+
+ TOptionListItem *defaultItems = CTranslator::getTree(CTranslator::TREE_MSG);
+
+ while (defaultItems[i].szName != 0) {
+ tvi.hParent = (HTREEITEM)defaultGroups[defaultItems[i].uGroup].handle;
+ tvi.hInsertAfter = TVI_LAST;
+ tvi.item.pszText = defaultItems[i].szName;
+ tvi.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvi.item.lParam = i;
+ tvi.item.stateMask = TVIS_STATEIMAGEMASK;
+ if (defaultItems[i].uType == LOI_TYPE_SETTING)
+ tvi.item.state = INDEXTOSTATEIMAGEMASK(M->GetByte((char *)defaultItems[i].lParam, (BYTE)defaultItems[i].id) ? 3 : 2);
+ defaultItems[i].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_WINDOWOPTIONS), &tvi);
+ i++;
+ }
+
+ SetDlgItemInt(hwndDlg, IDC_MAXAVATARHEIGHT, M->GetDword("avatarheight", 100), FALSE);
+ CheckDlgButton(hwndDlg, IDC_PRESERVEAVATARSIZE, M->GetByte("dontscaleavatars", 0) ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_AVATARSPIN, UDM_SETRANGE, 0, MAKELONG(150, 0));
+ SendDlgItemMessage(hwndDlg, IDC_AVATARSPIN, UDM_SETPOS, 0, GetDlgItemInt(hwndDlg, IDC_MAXAVATARHEIGHT, &translated, FALSE));
+ return TRUE;
+ }
+ case WM_DESTROY:
+ //ImageList_Destroy((HIMAGELIST)SendDlgItemMessage(hwndDlg, IDC_WINDOWOPTIONS, TVM_GETIMAGELIST, 0, 0));
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_MAXAVATARHEIGHT: {
+
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return TRUE;
+ break;
+ }
+ case IDC_HELP_GENERAL:
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://wiki.miranda.or.at/TabSRMM/GeneralSettings");
+ break;
+ case IDC_RESETWARNINGS:
+ M->WriteDword(SRMSGMOD_T, "cWarningsL", 0);
+ M->WriteDword(SRMSGMOD_T, "cWarningsH", 0);
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case IDC_WINDOWOPTIONS:
+ if (((LPNMHDR)lParam)->code == NM_CLICK || (((LPNMHDR)lParam)->code == TVN_KEYDOWN && ((LPNMTVKEYDOWN)lParam)->wVKey == VK_SPACE)) {
+ TVHITTESTINFO hti;
+ TVITEM item = {0};
+
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ item.stateMask = TVIS_STATEIMAGEMASK | TVIS_BOLD;
+ hti.pt.x = (short)LOWORD(GetMessagePos());
+ hti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt);
+ if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti) || ((LPNMHDR)lParam)->code == TVN_KEYDOWN) {
+ if (((LPNMHDR)lParam)->code == TVN_KEYDOWN) {
+ hti.flags |= TVHT_ONITEMSTATEICON;
+ item.hItem = TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom);
+ } else
+ item.hItem = (HTREEITEM)hti.hItem;
+ SendDlgItemMessageA(hwndDlg, IDC_WINDOWOPTIONS, TVM_GETITEMA, 0, (LPARAM)&item);
+ if (item.state & TVIS_BOLD && hti.flags & TVHT_ONITEMSTATEICON) {
+ item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_BOLD;
+ SendDlgItemMessageA(hwndDlg, IDC_WINDOWOPTIONS, TVM_SETITEMA, 0, (LPARAM)&item);
+ } else if (hti.flags & TVHT_ONITEMSTATEICON) {
+
+ if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 3) {
+ item.state = INDEXTOSTATEIMAGEMASK(1);
+ SendDlgItemMessageA(hwndDlg, IDC_WINDOWOPTIONS, TVM_SETITEMA, 0, (LPARAM)&item);
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ }
+ break;
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ BOOL translated;
+ TVITEM item = {0};
+ int i = 0;
+
+ M->WriteDword(SRMSGMOD_T, "avatarheight", GetDlgItemInt(hwndDlg, IDC_MAXAVATARHEIGHT, &translated, FALSE));
+
+ M->WriteByte(SRMSGMOD_T, "dontscaleavatars", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_PRESERVEAVATARSIZE) ? 1 : 0));
+
+ /*
+ * scan the tree view and obtain the options...
+ */
+
+ TOptionListItem *defaultItems = CTranslator::getTree(CTranslator::TREE_MSG);
+
+ while (defaultItems[i].szName != NULL) {
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ item.hItem = (HTREEITEM)defaultItems[i].handle;
+ item.stateMask = TVIS_STATEIMAGEMASK;
+
+ SendDlgItemMessageA(hwndDlg, IDC_WINDOWOPTIONS, TVM_GETITEMA, 0, (LPARAM)&item);
+ if (defaultItems[i].uType == LOI_TYPE_SETTING)
+ M->WriteByte(SRMSGMOD_T, (char *)defaultItems[i].lParam, (BYTE)((item.state >> 12) == 3 ? 1 : 0));
+ //pMim->WriteByte(SRMSGMOD_T, (char *)defaultItems[i].lParam, (BYTE)((item.state >> 12) == 2 ? 1 : 0));
+ i++;
+ }
+ PluginConfig.reloadSettings();
+ M->BroadcastMessage(DM_OPTIONSAPPLIED, 1, 0);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+static int have_ieview = 0, have_hpp = 0;
+
+static UINT __ctrls[] = { IDC_INDENTSPIN, IDC_RINDENTSPIN, IDC_INDENTAMOUNT, IDC_RIGHTINDENT,
+ IDC_MODIFY, IDC_RTLMODIFY };
+
+static INT_PTR CALLBACK DlgProcLogOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL translated;
+ DWORD dwFlags = M->GetDword("mwflags", MWF_LOG_DEFAULT);
+
+ switch (msg) {
+ case WM_INITDIALOG: {
+ TVINSERTSTRUCT tvi = {0};
+ int i = 0;
+ DWORD maxhist = M->GetDword("maxhist", 0);
+
+ TranslateDialogDefault(hwndDlg);
+ switch (M->GetByte(SRMSGMOD, SRMSGSET_LOADHISTORY, SRMSGDEFSET_LOADHISTORY)) {
+ case LOADHISTORY_UNREAD:
+ CheckDlgButton(hwndDlg, IDC_LOADUNREAD, BST_CHECKED);
+ break;
+ case LOADHISTORY_COUNT:
+ CheckDlgButton(hwndDlg, IDC_LOADCOUNT, BST_CHECKED);
+ Utils::enableDlgControl(hwndDlg, IDC_LOADCOUNTN, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_LOADCOUNTSPIN, TRUE);
+ break;
+ case LOADHISTORY_TIME:
+ CheckDlgButton(hwndDlg, IDC_LOADTIME, BST_CHECKED);
+ Utils::enableDlgControl(hwndDlg, IDC_LOADTIMEN, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_LOADTIMESPIN, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_STMINSOLD, TRUE);
+ break;
+ }
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOGOPTIONS), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOGOPTIONS), GWL_STYLE) | (TVS_NOHSCROLL | TVS_CHECKBOXES));
+
+ g_himlOptions = (HIMAGELIST)SendDlgItemMessage(hwndDlg, IDC_LOGOPTIONS, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)CreateStateImageList());
+ ImageList_Destroy(g_himlOptions);
+
+ /*
+ * fill the list box, create groups first, then add items
+ */
+
+ TOptionListGroup *lvGroups = CTranslator::getGroupTree(CTranslator::TREE_LOG);
+
+ while (lvGroups[i].szName != NULL) {
+ tvi.hParent = 0;
+ tvi.hInsertAfter = TVI_LAST;
+ tvi.item.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.item.pszText = lvGroups[i].szName;
+ tvi.item.stateMask = TVIS_STATEIMAGEMASK | TVIS_EXPANDED | TVIS_BOLD;
+ tvi.item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_EXPANDED | TVIS_BOLD;
+ lvGroups[i++].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_LOGOPTIONS), &tvi);
+ }
+
+ i = 0;
+
+ TOptionListItem *lvItems = CTranslator::getTree(CTranslator::TREE_LOG);
+
+ while (lvItems[i].szName != 0) {
+ tvi.hParent = (HTREEITEM)lvGroups[lvItems[i].uGroup].handle;
+ tvi.hInsertAfter = TVI_LAST;
+ tvi.item.pszText = lvItems[i].szName;
+ tvi.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvi.item.lParam = i;
+ tvi.item.stateMask = TVIS_STATEIMAGEMASK;
+ if (lvItems[i].uType == LOI_TYPE_FLAG)
+ tvi.item.state = INDEXTOSTATEIMAGEMASK((dwFlags & (UINT)lvItems[i].lParam) ? 3 : 2);
+ else if (lvItems[i].uType == LOI_TYPE_SETTING)
+ tvi.item.state = INDEXTOSTATEIMAGEMASK(M->GetByte((char *)lvItems[i].lParam, lvItems[i].id) ? 3 : 2); // NOTE: was 2 : 1 without state image mask
+ lvItems[i].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_LOGOPTIONS), &tvi);
+ i++;
+ }
+ SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_SETRANGE, 0, MAKELONG(100, 0));
+ SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_SETPOS, 0, DBGetContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADCOUNT, SRMSGDEFSET_LOADCOUNT));
+ SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_SETRANGE, 0, MAKELONG(24 * 60, 0));
+ SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_SETPOS, 0, DBGetContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADTIME, SRMSGDEFSET_LOADTIME));
+
+ SetDlgItemInt(hwndDlg, IDC_INDENTAMOUNT, M->GetDword("IndentAmount", 20), FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_INDENTSPIN, UDM_SETRANGE, 0, MAKELONG(1000, 0));
+ SendDlgItemMessage(hwndDlg, IDC_INDENTSPIN, UDM_SETPOS, 0, GetDlgItemInt(hwndDlg, IDC_INDENTAMOUNT, &translated, FALSE));
+
+ SetDlgItemInt(hwndDlg, IDC_RIGHTINDENT, M->GetDword("RightIndent", 20), FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_RINDENTSPIN, UDM_SETRANGE, 0, MAKELONG(1000, 0));
+ SendDlgItemMessage(hwndDlg, IDC_RINDENTSPIN, UDM_SETPOS, 0, GetDlgItemInt(hwndDlg, IDC_RIGHTINDENT, &translated, FALSE));
+ SendMessage(hwndDlg, WM_COMMAND, MAKELONG(IDC_INDENT, 0), 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_TRIMSPIN, UDM_SETRANGE, 0, MAKELONG(1000, 5));
+ SendDlgItemMessage(hwndDlg, IDC_TRIMSPIN, UDM_SETPOS, 0, maxhist);
+ Utils::enableDlgControl(hwndDlg, IDC_TRIMSPIN, maxhist != 0);
+ Utils::enableDlgControl(hwndDlg, IDC_TRIM, maxhist != 0);
+ CheckDlgButton(hwndDlg, IDC_ALWAYSTRIM, maxhist != 0);
+
+ have_ieview = ServiceExists(MS_IEVIEW_WINDOW);
+ have_hpp = ServiceExists("History++/ExtGrid/NewWindow");
+
+ SendDlgItemMessage(hwndDlg, IDC_MSGLOGDIDSPLAY, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_LOG_DEFAULT));
+ SendDlgItemMessage(hwndDlg, IDC_MSGLOGDIDSPLAY, CB_SETCURSEL, 0, 0);
+
+ if (have_ieview) {
+ SendDlgItemMessage(hwndDlg, IDC_MSGLOGDIDSPLAY, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_LOG_IEVIEW));
+ if (M->GetByte("default_ieview", 0))
+ SendDlgItemMessage(hwndDlg, IDC_MSGLOGDIDSPLAY, CB_SETCURSEL, 1, 0);
+ }
+ if (have_hpp) {
+ SendDlgItemMessage(hwndDlg, IDC_MSGLOGDIDSPLAY, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_LOG_HPP));
+ if (M->GetByte("default_ieview", 0))
+ SendDlgItemMessage(hwndDlg, IDC_MSGLOGDIDSPLAY, CB_SETCURSEL, 1, 0);
+ else if (M->GetByte("default_hpp", 0))
+ SendDlgItemMessage(hwndDlg, IDC_MSGLOGDIDSPLAY, CB_SETCURSEL, have_ieview ? 2 : 1, 0);
+ }
+ SetDlgItemText(hwndDlg, IDC_EXPLAINMSGLOGSETTINGS, CTranslator::getOpt(CTranslator::OPT_MSGLOG_EXPLAINSETTINGS));
+ SendMessage(hwndDlg, WM_USER + 100, 0, 0);
+ return TRUE;
+ }
+ /*
+ * configure the option page - hide most of the settings here when either IEView
+ * or H++ is set as the global message log viewer. Showing these options may confuse
+ * the user, because they are not working and the user needs to configure the 3rd
+ * party plugin.
+ */
+ case WM_USER + 100: {
+ int i;
+
+ LRESULT r = SendDlgItemMessage(hwndDlg, IDC_MSGLOGDIDSPLAY, CB_GETCURSEL, 0, 0);
+ Utils::showDlgControl(hwndDlg, IDC_EXPLAINMSGLOGSETTINGS, r == 0 ? SW_HIDE : SW_SHOW);
+ Utils::showDlgControl(hwndDlg, IDC_LOGOPTIONS, r == 0 ? SW_SHOW : SW_HIDE);
+ for(i = 0; i < safe_sizeof(__ctrls); i++)
+ Utils::enableDlgControl(hwndDlg, __ctrls[i], r == 0 ? TRUE : FALSE);
+ return(0);
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_ALWAYSTRIM:
+ Utils::enableDlgControl(hwndDlg, IDC_TRIMSPIN, IsDlgButtonChecked(hwndDlg, IDC_ALWAYSTRIM));
+ Utils::enableDlgControl(hwndDlg, IDC_TRIM, IsDlgButtonChecked(hwndDlg, IDC_ALWAYSTRIM));
+ break;
+ case IDC_LOADUNREAD:
+ case IDC_LOADCOUNT:
+ case IDC_LOADTIME:
+ Utils::enableDlgControl(hwndDlg, IDC_LOADCOUNTN, IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT));
+ Utils::enableDlgControl(hwndDlg, IDC_LOADCOUNTSPIN, IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT));
+ Utils::enableDlgControl(hwndDlg, IDC_LOADTIMEN, IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
+ Utils::enableDlgControl(hwndDlg, IDC_LOADTIMESPIN, IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
+ Utils::enableDlgControl(hwndDlg, IDC_STMINSOLD, IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
+ break;
+ case IDC_INDENTAMOUNT:
+ case IDC_LOADCOUNTN:
+ case IDC_LOADTIMEN:
+ case IDC_RIGHTINDENT:
+ case IDC_TRIM:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return TRUE;
+ break;
+ case IDC_MODIFY: {
+ TemplateEditorNew teNew = {0, 0, hwndDlg};
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_TEMPLATEEDIT), hwndDlg, DlgProcTemplateEditor, (LPARAM)&teNew);
+ break;
+ }
+ case IDC_RTLMODIFY: {
+ TemplateEditorNew teNew = {0, TRUE, hwndDlg};
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_TEMPLATEEDIT), hwndDlg, DlgProcTemplateEditor, (LPARAM)&teNew);
+ break;
+ }
+ case IDC_MSGLOGDIDSPLAY:
+ SendMessage(hwndDlg, WM_USER + 100, 0, 0);
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case IDC_LOGOPTIONS:
+ if (((LPNMHDR)lParam)->code == NM_CLICK || (((LPNMHDR)lParam)->code == TVN_KEYDOWN && ((LPNMTVKEYDOWN)lParam)->wVKey == VK_SPACE)) {
+ TVHITTESTINFO hti;
+ TVITEM item = {0};
+
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ item.stateMask = TVIS_STATEIMAGEMASK | TVIS_BOLD;
+ hti.pt.x = (short)LOWORD(GetMessagePos());
+ hti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt);
+ if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti) || ((LPNMHDR)lParam)->code == TVN_KEYDOWN) {
+ if (((LPNMHDR)lParam)->code == TVN_KEYDOWN) {
+ hti.flags |= TVHT_ONITEMSTATEICON;
+ item.hItem = TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom);
+ } else
+ item.hItem = (HTREEITEM)hti.hItem;
+ SendDlgItemMessageA(hwndDlg, IDC_LOGOPTIONS, TVM_GETITEMA, 0, (LPARAM)&item);
+ if (item.state & TVIS_BOLD && hti.flags & TVHT_ONITEMSTATEICON) {
+ item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_BOLD;
+ SendDlgItemMessageA(hwndDlg, IDC_LOGOPTIONS, TVM_SETITEMA, 0, (LPARAM)&item);
+ } else if (hti.flags & TVHT_ONITEMSTATEICON) {
+
+ if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 3) {
+ item.state = INDEXTOSTATEIMAGEMASK(1);
+ SendDlgItemMessageA(hwndDlg, IDC_LOGOPTIONS, TVM_SETITEMA, 0, (LPARAM)&item);
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ }
+ break;
+ default:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ int i = 0;
+ TVITEM item = {0};
+ LRESULT msglogmode = SendDlgItemMessage(hwndDlg, IDC_MSGLOGDIDSPLAY, CB_GETCURSEL, 0, 0);
+
+ dwFlags &= ~(MWF_LOG_ALL);
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT))
+ M->WriteByte(SRMSGMOD, SRMSGSET_LOADHISTORY, LOADHISTORY_COUNT);
+ else if (IsDlgButtonChecked(hwndDlg, IDC_LOADTIME))
+ M->WriteByte(SRMSGMOD, SRMSGSET_LOADHISTORY, LOADHISTORY_TIME);
+ else
+ M->WriteByte(SRMSGMOD, SRMSGSET_LOADHISTORY, LOADHISTORY_UNREAD);
+ DBWriteContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADCOUNT, (WORD) SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_GETPOS, 0, 0));
+ DBWriteContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADTIME, (WORD) SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_GETPOS, 0, 0));
+
+ M->WriteDword(SRMSGMOD_T, "IndentAmount", (DWORD) GetDlgItemInt(hwndDlg, IDC_INDENTAMOUNT, &translated, FALSE));
+ M->WriteDword(SRMSGMOD_T, "RightIndent", (DWORD) GetDlgItemInt(hwndDlg, IDC_RIGHTINDENT, &translated, FALSE));
+
+ M->WriteByte(SRMSGMOD_T, "default_ieview", 0);
+ M->WriteByte(SRMSGMOD_T, "default_hpp", 0);
+ switch(msglogmode) {
+ case 0:
+ break;
+ case 1:
+ if (have_ieview)
+ M->WriteByte(SRMSGMOD_T, "default_ieview", 1);
+ else
+ M->WriteByte(SRMSGMOD_T, "default_hpp", 1);
+ break;
+ case 2:
+ M->WriteByte(SRMSGMOD_T, "default_hpp", 1);
+ break;
+ }
+
+ /*
+ * scan the tree view and obtain the options...
+ */
+ TOptionListItem *lvItems = CTranslator::getTree(CTranslator::TREE_LOG);
+
+ while (lvItems[i].szName != NULL) {
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ item.hItem = (HTREEITEM)lvItems[i].handle;
+ item.stateMask = TVIS_STATEIMAGEMASK;
+
+ SendDlgItemMessageA(hwndDlg, IDC_LOGOPTIONS, TVM_GETITEMA, 0, (LPARAM)&item);
+ if (lvItems[i].uType == LOI_TYPE_FLAG)
+ dwFlags |= (item.state >> 12) == 3/*2*/ ? lvItems[i].lParam : 0;
+ else if (lvItems[i].uType == LOI_TYPE_SETTING)
+ M->WriteByte(SRMSGMOD_T, (char *)lvItems[i].lParam, (BYTE)((item.state >> 12) == 3/*2*/ ? 1 : 0)); // NOTE: state image masks changed
+ i++;
+ }
+
+ M->WriteDword(SRMSGMOD_T, "mwflags", dwFlags);
+ if (IsDlgButtonChecked(hwndDlg, IDC_ALWAYSTRIM))
+ M->WriteDword(SRMSGMOD_T, "maxhist", (DWORD)SendDlgItemMessage(hwndDlg, IDC_TRIMSPIN, UDM_GETPOS, 0, 0));
+ else
+ M->WriteDword(SRMSGMOD_T, "maxhist", 0);
+ PluginConfig.reloadSettings();
+ M->BroadcastMessage(DM_OPTIONSAPPLIED, 1, 0);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static void ResetCList(HWND hwndDlg)
+{
+ int i;
+
+ if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_DISABLEGROUPS && !M->GetByte("CList", "UseGroups", SETTING_USEGROUPS_DEFAULT))
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETUSEGROUPS, (WPARAM) FALSE, 0);
+ else
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETUSEGROUPS, (WPARAM) TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETHIDEEMPTYGROUPS, 1, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETGREYOUTFLAGS, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETLEFTMARGIN, 2, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETBKBITMAP, 0, (LPARAM)(HBITMAP) NULL);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETINDENT, 10, 0);
+ for (i = 0; i <= FONTID_MAX; i++)
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT));
+}
+
+static void RebuildList(HWND hwndDlg, HANDLE hItemNew, HANDLE hItemUnknown)
+{
+ HANDLE hContact, hItem;
+ BYTE defType = M->GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW);
+
+ if (hItemNew && defType) {
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItemNew, 1);
+ }
+ if (hItemUnknown && M->GetByte(SRMSGMOD, SRMSGSET_TYPINGUNKNOWN, SRMSGDEFSET_TYPINGUNKNOWN)) {
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItemUnknown, 1);
+ }
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do {
+ hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0);
+ if (hItem && M->GetByte(hContact, SRMSGMOD, SRMSGSET_TYPING, defType)) {
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItem, 1);
+ }
+ } while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0));
+}
+
+static void SaveList(HWND hwndDlg, HANDLE hItemNew, HANDLE hItemUnknown)
+{
+ HANDLE hContact, hItem;
+
+ if (hItemNew) {
+ M->WriteByte(SRMSGMOD, SRMSGSET_TYPINGNEW, (BYTE)(SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItemNew, 0) ? 1 : 0));
+ }
+ if (hItemUnknown) {
+ M->WriteByte(SRMSGMOD, SRMSGSET_TYPINGUNKNOWN, (BYTE)(SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItemUnknown, 0) ? 1 : 0));
+ }
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do {
+ hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0);
+ if (hItem) {
+ DBWriteContactSettingByte(hContact, SRMSGMOD, SRMSGSET_TYPING, (BYTE)(SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItem, 0) ? 1 : 0));
+ }
+ } while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0));
+}
+
+static INT_PTR CALLBACK DlgProcTypeOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HANDLE hItemNew, hItemUnknown;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ CLCINFOITEM cii = { 0 };
+ cii.cbSize = sizeof(cii);
+ cii.flags = CLCIIF_GROUPFONT | CLCIIF_CHECKBOX;
+ cii.pszText = CTranslator::getOpt(CTranslator::OPT_MTN_NEW);
+ hItemNew = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_ADDINFOITEM, 0, (LPARAM) & cii);
+ cii.pszText = CTranslator::getOpt(CTranslator::OPT_MTN_UNKNOWN);
+ hItemUnknown = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_ADDINFOITEM, 0, (LPARAM) & cii);
+ }
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CLIST), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CLIST), GWL_STYLE) | (CLS_SHOWHIDDEN));
+ ResetCList(hwndDlg);
+ RebuildList(hwndDlg, hItemNew, hItemUnknown);
+
+ CheckDlgButton(hwndDlg, IDC_SHOWNOTIFY, M->GetByte(SRMSGMOD, SRMSGSET_SHOWTYPING, SRMSGDEFSET_SHOWTYPING));
+ CheckDlgButton(hwndDlg, IDC_TYPEFLASHWIN, M->GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINFLASH, SRMSGDEFSET_SHOWTYPINGWINFLASH));
+
+ CheckDlgButton(hwndDlg, IDC_TYPENOWIN, M->GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGNOWINOPEN, 1));
+ CheckDlgButton(hwndDlg, IDC_TYPEWIN, M->GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINOPEN, 1));
+ CheckDlgButton(hwndDlg, IDC_NOTIFYTRAY, M->GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST));
+ CheckDlgButton(hwndDlg, IDC_NOTIFYBALLOON, M->GetByte(SRMSGMOD, "ShowTypingBalloon", 0));
+
+ CheckDlgButton(hwndDlg, IDC_NOTIFYPOPUP, M->GetByte(SRMSGMOD, "ShowTypingPopup", 0));
+
+ Utils::enableDlgControl(hwndDlg, IDC_TYPEWIN, IsDlgButtonChecked(hwndDlg, IDC_NOTIFYTRAY));
+ Utils::enableDlgControl(hwndDlg, IDC_TYPENOWIN, IsDlgButtonChecked(hwndDlg, IDC_NOTIFYTRAY));
+ Utils::enableDlgControl(hwndDlg, IDC_NOTIFYBALLOON, IsDlgButtonChecked(hwndDlg, IDC_NOTIFYTRAY) &&
+ (IsDlgButtonChecked(hwndDlg, IDC_TYPEWIN) || IsDlgButtonChecked(hwndDlg, IDC_TYPENOWIN)));
+
+ Utils::enableDlgControl(hwndDlg, IDC_TYPEFLASHWIN, IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
+ Utils::enableDlgControl(hwndDlg, IDC_MTN_POPUPMODE, IsDlgButtonChecked(hwndDlg, IDC_NOTIFYPOPUP));
+
+ if (!ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
+ Utils::enableDlgControl(hwndDlg, IDC_NOTIFYBALLOON, FALSE);
+ SetWindowText(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), CTranslator::getOpt(CTranslator::OPT_MTN_UNSUPPORTED));
+ }
+
+ SendDlgItemMessage(hwndDlg, IDC_MTN_POPUPMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_GEN_ALWAYS));
+ SendDlgItemMessage(hwndDlg, IDC_MTN_POPUPMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_MTN_NOTFOCUSED));
+ SendDlgItemMessage(hwndDlg, IDC_MTN_POPUPMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_MTN_ONLYCLOSED));
+
+ SendDlgItemMessage(hwndDlg, IDC_MTN_POPUPMODE, CB_SETCURSEL, (WPARAM)M->GetByte("MTN_PopupMode", 0), 0);
+
+ if(!PluginConfig.g_PopupWAvail) {
+ Utils::showDlgControl(hwndDlg, IDC_NOTIFYPOPUP, SW_HIDE);
+ Utils::showDlgControl(hwndDlg, IDC_STATIC111, SW_HIDE);
+ Utils::showDlgControl(hwndDlg, IDC_MTN_POPUPMODE, SW_HIDE);
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_NOTIFYTRAY:
+ Utils::enableDlgControl(hwndDlg, IDC_TYPEWIN, IsDlgButtonChecked(hwndDlg, IDC_NOTIFYTRAY));
+ Utils::enableDlgControl(hwndDlg, IDC_TYPENOWIN, IsDlgButtonChecked(hwndDlg, IDC_NOTIFYTRAY));
+ Utils::enableDlgControl(hwndDlg, IDC_NOTIFYBALLOON, IsDlgButtonChecked(hwndDlg, IDC_NOTIFYTRAY));
+ break;
+ case IDC_SHOWNOTIFY:
+ Utils::enableDlgControl(hwndDlg, IDC_TYPEFLASHWIN, IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
+ break;
+ case IDC_NOTIFYPOPUP:
+ Utils::enableDlgControl(hwndDlg, IDC_MTN_POPUPMODE, IsDlgButtonChecked(hwndDlg, IDC_NOTIFYPOPUP));
+ break;
+ case IDC_TYPEWIN:
+ case IDC_TYPENOWIN:
+ Utils::enableDlgControl(hwndDlg, IDC_NOTIFYBALLOON, IsDlgButtonChecked(hwndDlg, IDC_NOTIFYTRAY) &&
+ (IsDlgButtonChecked(hwndDlg, IDC_TYPEWIN) || IsDlgButtonChecked(hwndDlg, IDC_TYPENOWIN)));
+ break;
+ case IDC_MTN_HELP:
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://wiki.miranda.or.at/TabSRMM/TypingNotifications");
+ return 0;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((NMHDR *) lParam)->idFrom) {
+ case IDC_CLIST:
+ switch (((NMHDR *) lParam)->code) {
+ case CLN_OPTIONSCHANGED:
+ ResetCList(hwndDlg);
+ break;
+ case CLN_CHECKCHANGED:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ break;
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ SaveList(hwndDlg, hItemNew, hItemUnknown);
+ M->WriteByte(SRMSGMOD, SRMSGSET_SHOWTYPING, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
+ M->WriteByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINFLASH, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_TYPEFLASHWIN));
+ M->WriteByte(SRMSGMOD, SRMSGSET_SHOWTYPINGNOWINOPEN, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_TYPENOWIN));
+ M->WriteByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINOPEN, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_TYPEWIN));
+ M->WriteByte(SRMSGMOD, SRMSGSET_SHOWTYPINGCLIST, (BYTE) IsDlgButtonChecked(hwndDlg, IDC_NOTIFYTRAY));
+ M->WriteByte(SRMSGMOD, "ShowTypingBalloon", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_NOTIFYBALLOON));
+ M->WriteByte(SRMSGMOD, "ShowTypingPopup",(BYTE) IsDlgButtonChecked(hwndDlg, IDC_NOTIFYPOPUP));
+ M->WriteByte(SRMSGMOD_T, "MTN_PopupMode", (BYTE)SendDlgItemMessage(hwndDlg, IDC_MTN_POPUPMODE, CB_GETCURSEL, 0, 0));
+ PluginConfig.reloadSettings();
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/*
+ * options for tabbed messaging got their own page.. finally :)
+ */
+
+static INT_PTR CALLBACK DlgProcTabbedOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG: {
+ TVINSERTSTRUCT tvi = {0};
+ int i = 0;
+
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TABMSGOPTIONS), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TABMSGOPTIONS), GWL_STYLE) | (TVS_NOHSCROLL | TVS_CHECKBOXES));
+
+ g_himlOptions = (HIMAGELIST)SendDlgItemMessage(hwndDlg, IDC_TABMSGOPTIONS, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)CreateStateImageList());
+ ImageList_Destroy(g_himlOptions);
+
+ /*
+ * fill the list box, create groups first, then add items
+ */
+
+ TOptionListGroup *tabGroups = CTranslator::getGroupTree(CTranslator::TREE_TAB);
+
+ while (tabGroups[i].szName != NULL) {
+ tvi.hParent = 0;
+ tvi.hInsertAfter = TVI_LAST;
+ tvi.item.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.item.pszText = tabGroups[i].szName;
+ tvi.item.stateMask = TVIS_STATEIMAGEMASK | TVIS_EXPANDED | TVIS_BOLD;
+ tvi.item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_EXPANDED | TVIS_BOLD;
+ tabGroups[i++].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_TABMSGOPTIONS), &tvi);
+ }
+
+ i = 0;
+
+ TOptionListItem *tabItems = CTranslator::getTree(CTranslator::TREE_TAB);
+
+ while (tabItems[i].szName != 0) {
+ tvi.hParent = (HTREEITEM)tabGroups[tabItems[i].uGroup].handle;
+ tvi.hInsertAfter = TVI_LAST;
+ tvi.item.pszText = tabItems[i].szName;
+ tvi.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvi.item.lParam = i;
+ tvi.item.stateMask = TVIS_STATEIMAGEMASK;
+ if (tabItems[i].uType == LOI_TYPE_SETTING)
+ tvi.item.state = INDEXTOSTATEIMAGEMASK(M->GetByte((char *)tabItems[i].lParam, (BYTE)tabItems[i].id) ? 3 : 2/*2 : 1*/);
+ tabItems[i].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_TABMSGOPTIONS), &tvi);
+ i++;
+ }
+ CheckDlgButton(hwndDlg, IDC_CUT_TABTITLE, M->GetByte("cuttitle", 0));
+ SendDlgItemMessage(hwndDlg, IDC_CUT_TITLEMAXSPIN, UDM_SETRANGE, 0, MAKELONG(20, 5));
+ SendDlgItemMessage(hwndDlg, IDC_CUT_TITLEMAXSPIN, UDM_SETPOS, 0, (WPARAM)DBGetContactSettingWord(NULL, SRMSGMOD_T, "cut_at", 15));
+
+ Utils::enableDlgControl(hwndDlg, IDC_CUT_TITLEMAX, IsDlgButtonChecked(hwndDlg, IDC_CUT_TABTITLE));
+ Utils::enableDlgControl(hwndDlg, IDC_CUT_TITLEMAXSPIN, IsDlgButtonChecked(hwndDlg, IDC_CUT_TABTITLE));
+
+ SendDlgItemMessage(hwndDlg, IDC_ESCMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_CNT_ESCNORMAL));
+ SendDlgItemMessage(hwndDlg, IDC_ESCMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_CNT_ESCMINIMIZE));
+ SendDlgItemMessage(hwndDlg, IDC_ESCMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_CNT_ESCCLOS));
+ SendDlgItemMessage(hwndDlg, IDC_ESCMODE, CB_SETCURSEL, (WPARAM)PluginConfig.m_EscapeCloses, 0);
+ break;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_CUT_TITLEMAX:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return TRUE;
+ break;
+ case IDC_SETUPAUTOCREATEMODES: {
+ HWND hwndNew = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CHOOSESTATUSMODES), hwndDlg, DlgProcSetupStatusModes, M->GetDword("autopopupmask", -1));
+ SendMessage(hwndNew, DM_SETPARENTDIALOG, 0, (LPARAM)hwndDlg);
+ break;
+ }
+ case IDC_CUT_TABTITLE:
+ Utils::enableDlgControl(hwndDlg, IDC_CUT_TITLEMAX, IsDlgButtonChecked(hwndDlg, IDC_CUT_TABTITLE));
+ Utils::enableDlgControl(hwndDlg, IDC_CUT_TITLEMAXSPIN, IsDlgButtonChecked(hwndDlg, IDC_CUT_TABTITLE));
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case DM_STATUSMASKSET:
+ M->WriteDword(SRMSGMOD_T, "autopopupmask", (DWORD)lParam);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case IDC_TABMSGOPTIONS:
+ if (((LPNMHDR)lParam)->code == NM_CLICK || (((LPNMHDR)lParam)->code == TVN_KEYDOWN && ((LPNMTVKEYDOWN)lParam)->wVKey == VK_SPACE)) {
+ TVHITTESTINFO hti;
+ TVITEM item = {0};
+
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ item.stateMask = TVIS_STATEIMAGEMASK | TVIS_BOLD;
+ hti.pt.x = (short)LOWORD(GetMessagePos());
+ hti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt);
+ if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti) || ((LPNMHDR)lParam)->code == TVN_KEYDOWN) {
+ if (((LPNMHDR)lParam)->code == TVN_KEYDOWN) {
+ hti.flags |= TVHT_ONITEMSTATEICON;
+ item.hItem = TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom);
+ } else
+ item.hItem = (HTREEITEM)hti.hItem;
+ SendDlgItemMessageA(hwndDlg, IDC_TABMSGOPTIONS, TVM_GETITEMA, 0, (LPARAM)&item);
+ if (item.state & TVIS_BOLD && hti.flags & TVHT_ONITEMSTATEICON) {
+ item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_BOLD;
+ SendDlgItemMessageA(hwndDlg, IDC_TABMSGOPTIONS, TVM_SETITEMA, 0, (LPARAM)&item);
+ } else if (hti.flags & TVHT_ONITEMSTATEICON) {
+
+ if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 3) {
+ item.state = INDEXTOSTATEIMAGEMASK(1);
+ SendDlgItemMessageA(hwndDlg, IDC_TABMSGOPTIONS, TVM_SETITEMA, 0, (LPARAM)&item);
+ }
+
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ }
+ break;
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ TVITEM item = {0};
+ int i = 0;
+ M->WriteByte(SRMSGMOD_T, "cuttitle", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_CUT_TABTITLE));
+ DBWriteContactSettingWord(NULL, SRMSGMOD_T, "cut_at", (WORD)SendDlgItemMessage(hwndDlg, IDC_CUT_TITLEMAXSPIN, UDM_GETPOS, 0, 0));
+
+ /*
+ * scan the tree view and obtain the options...
+ */
+
+ TOptionListItem *tabItems = CTranslator::getTree(CTranslator::TREE_TAB);
+
+ while (tabItems[i].szName != NULL) {
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ item.hItem = (HTREEITEM)tabItems[i].handle;
+ item.stateMask = TVIS_STATEIMAGEMASK;
+
+ SendDlgItemMessageA(hwndDlg, IDC_TABMSGOPTIONS, TVM_GETITEMA, 0, (LPARAM)&item);
+ if (tabItems[i].uType == LOI_TYPE_SETTING)
+ M->WriteByte(SRMSGMOD_T, (char *)tabItems[i].lParam, (BYTE)((item.state >> 12) == 3/*2*/ ? 1 : 0));
+ i++;
+ }
+
+ PluginConfig.m_EscapeCloses = (int)SendDlgItemMessage(hwndDlg, IDC_ESCMODE, CB_GETCURSEL, 0, 0);
+ M->WriteByte(SRMSGMOD_T, "escmode", (BYTE)PluginConfig.m_EscapeCloses);
+ PluginConfig.reloadSettings();
+ M->BroadcastMessage(DM_OPTIONSAPPLIED, 0, 0);
+ return TRUE;
+ }
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK DlgProcContainerSettings(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG: {
+ DBVARIANT dbv = {0};
+
+ TranslateDialogDefault(hwndDlg);
+
+ CheckDlgButton(hwndDlg, IDC_CONTAINERGROUPMODE, M->GetByte("useclistgroups", 0));
+ CheckDlgButton(hwndDlg, IDC_LIMITTABS, M->GetByte("limittabs", 0));
+
+ SendDlgItemMessage(hwndDlg, IDC_TABLIMITSPIN, UDM_SETRANGE, 0, MAKELONG(1000, 1));
+ SendDlgItemMessage(hwndDlg, IDC_TABLIMITSPIN, UDM_SETPOS, 0, (int)M->GetDword("maxtabs", 1));
+ SetDlgItemInt(hwndDlg, IDC_TABLIMIT, (int)M->GetDword("maxtabs", 1), FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_TABLIMIT, IsDlgButtonChecked(hwndDlg, IDC_LIMITTABS));
+ CheckDlgButton(hwndDlg, IDC_SINGLEWINDOWMODE, M->GetByte("singlewinmode", 0));
+ CheckDlgButton(hwndDlg, IDC_DEFAULTCONTAINERMODE, !(IsDlgButtonChecked(hwndDlg, IDC_CONTAINERGROUPMODE) || IsDlgButtonChecked(hwndDlg, IDC_LIMITTABS) || IsDlgButtonChecked(hwndDlg, IDC_SINGLEWINDOWMODE)));
+
+ SetDlgItemInt(hwndDlg, IDC_NRFLASH, M->GetByte("nrflash", 4), FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_NRFLASHSPIN, UDM_SETRANGE, 0, MAKELONG(255, 1));
+ SendDlgItemMessage(hwndDlg, IDC_NRFLASHSPIN, UDM_SETPOS, 0, (int)M->GetByte("nrflash", 4));
+
+ SetDlgItemInt(hwndDlg, IDC_FLASHINTERVAL, M->GetDword("flashinterval", 1000), FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_FLASHINTERVALSPIN, UDM_SETRANGE, 0, MAKELONG(10000, 500));
+ SendDlgItemMessage(hwndDlg, IDC_FLASHINTERVALSPIN, UDM_SETPOS, 0, (int)M->GetDword("flashinterval", 1000));
+ SendDlgItemMessage(hwndDlg, IDC_FLASHINTERVALSPIN, UDM_SETACCEL, 0, (int)M->GetDword("flashinterval", 1000));
+ CheckDlgButton(hwndDlg, IDC_USEAERO, M->GetByte("useAero", 1));
+ CheckDlgButton(hwndDlg, IDC_USEAEROPEEK, M->GetByte("useAeroPeek", 1));
+ for(int i = 0; i < CSkin::AERO_EFFECT_LAST; i++)
+ SendDlgItemMessage(hwndDlg, IDC_AEROEFFECT, CB_INSERTSTRING, -1, (LPARAM)TranslateTS(CSkin::m_aeroEffects[i].tszName));
+
+ SendDlgItemMessage(hwndDlg, IDC_AEROEFFECT, CB_SETCURSEL, (WPARAM)CSkin::m_aeroEffect, 0);
+ Utils::enableDlgControl(hwndDlg, IDC_AEROEFFECT, PluginConfig.m_bIsVista ? TRUE : FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_USEAERO, PluginConfig.m_bIsVista ? TRUE : FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_USEAEROPEEK, PluginConfig.m_bIsWin7 ? TRUE : FALSE);
+ if(PluginConfig.m_bIsVista)
+ Utils::enableDlgControl(hwndDlg, IDC_AEROEFFECT, IsDlgButtonChecked(hwndDlg, IDC_USEAERO) ? 1 : 0);
+
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_TABLIMIT:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return TRUE;
+ break;
+ case IDC_USEAERO:
+ Utils::enableDlgControl(hwndDlg, IDC_AEROEFFECT, IsDlgButtonChecked(hwndDlg, IDC_USEAERO) ? 1 : 0);
+ break;
+ case IDC_LIMITTABS:
+ case IDC_SINGLEWINDOWMODE:
+ case IDC_CONTAINERGROUPMODE:
+ case IDC_DEFAULTCONTAINERMODE:
+ Utils::enableDlgControl(hwndDlg, IDC_TABLIMIT, IsDlgButtonChecked(hwndDlg, IDC_LIMITTABS));
+ break;
+ case IDC_HELP_CONTAINERS:
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://wiki.miranda.or.at/TabSRMM/Containers");
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ BOOL translated;
+
+ bool fOldAeroState = M->getAeroState();
+ M->WriteByte(SRMSGMOD_T, "useclistgroups", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_CONTAINERGROUPMODE)));
+ M->WriteByte(SRMSGMOD_T, "limittabs", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_LIMITTABS)));
+ M->WriteDword(SRMSGMOD_T, "maxtabs", GetDlgItemInt(hwndDlg, IDC_TABLIMIT, &translated, FALSE));
+ M->WriteByte(SRMSGMOD_T, "singlewinmode", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_SINGLEWINDOWMODE)));
+ M->WriteDword(SRMSGMOD_T, "flashinterval", GetDlgItemInt(hwndDlg, IDC_FLASHINTERVAL, &translated, FALSE));
+ M->WriteByte(SRMSGMOD_T, "nrflash", (BYTE)(GetDlgItemInt(hwndDlg, IDC_NRFLASH, &translated, FALSE)));
+ M->WriteByte(0, SRMSGMOD_T, "useAero", IsDlgButtonChecked(hwndDlg, IDC_USEAERO) ? 1 : 0);
+ M->WriteByte(0, SRMSGMOD_T, "useAeroPeek", IsDlgButtonChecked(hwndDlg, IDC_USEAEROPEEK) ? 1 : 0);
+ CSkin::setAeroEffect(SendDlgItemMessage(hwndDlg, IDC_AEROEFFECT, CB_GETCURSEL, 0, 0));
+
+ if(M->getAeroState() != fOldAeroState) {
+ SendMessage(PluginConfig.g_hwndHotkeyHandler, WM_DWMCOMPOSITIONCHANGED, 0, 0); // simulate aero state change
+ SendMessage(PluginConfig.g_hwndHotkeyHandler, WM_DWMCOLORIZATIONCOLORCHANGED, 0, 0); // simulate aero state change
+ }
+ BuildContainerMenu();
+ return TRUE;
+ }
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+#define DBFONTF_BOLD 1
+#define DBFONTF_ITALIC 2
+#define DBFONTF_UNDERLINE 4
+
+#define FONTS_TO_CONFIG MSGDLGFONTCOUNT
+
+#define SAMEASF_FACE 1
+#define SAMEASF_SIZE 2
+#define SAMEASF_STYLE 4
+#define SAMEASF_COLOUR 8
+#include <pshpack1.h>
+
+struct {
+ BYTE sameAsFlags, sameAs;
+ COLORREF colour;
+ char size;
+ BYTE style;
+ BYTE charset;
+ char szFace[LF_FACESIZE];
+} static fontSettings[MSGDLGFONTCOUNT + 1];
+
+#include <poppack.h>
+
+#define SRFONTSETTINGMODULE FONTMODULE
+
+static int OptInitialise(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+
+ if(PluginConfig.g_PopupWAvail||PluginConfig.g_PopupAvail)
+ TN_OptionsInitialize(wParam, lParam);
+
+ odp.cbSize = sizeof(odp);
+ odp.position = 910000000;
+ odp.hInstance = g_hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSGDLG);
+ odp.ptszTitle = LPGENT("Message Sessions");
+ odp.pfnDlgProc = DlgProcOptions;
+ odp.ptszGroup = NULL;
+ odp.nIDBottomSimpleControl = 0;
+ odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TABS_GENERAL));
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TABS_TABS));
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_TABBEDMSG);
+ odp.pfnDlgProc = DlgProcTabbedOptions;
+ CallService(MS_OPT_ADDPAGE, wParam,(LPARAM)&odp);
+
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TABS_CONTAINERS));
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CONTAINERS);
+ odp.pfnDlgProc = DlgProcContainerSettings;
+ CallService(MS_OPT_ADDPAGE, wParam,(LPARAM)&odp);
+
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TABS_LOG));
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSGLOG);
+ odp.pfnDlgProc = DlgProcLogOptions;
+ CallService(MS_OPT_ADDPAGE, wParam,(LPARAM)&odp);
+
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TABS_TOOLBAR));
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_TOOLBAR);
+ odp.pfnDlgProc = DlgProcToolBar;
+ CallService(MS_OPT_ADDPAGE, wParam,(LPARAM)&odp);
+
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TABS_ADVANCED));
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS_PLUS);
+ odp.pfnDlgProc = PlusOptionsProc;
+ CallService(MS_OPT_ADDPAGE, wParam,(LPARAM)&odp);
+
+
+ odp.ptszGroup = LPGENT("Message Sessions");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSGTYPE);
+ odp.ptszTitle = LPGENT("Typing Notify");
+ odp.pfnDlgProc = DlgProcTypeOptions;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_POPUP_OPT);
+ odp.ptszTitle = LPGENT("Event notifications");
+ odp.ptszGroup = LPGENT("PopUps");
+ odp.pfnDlgProc = DlgProcPopupOpts;
+ odp.nIDBottomSimpleControl = 0;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) &odp);
+
+
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SKIN);
+ odp.ptszTitle = LPGENT("Message window");
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TAB_SKINLOAD));
+ odp.pfnDlgProc = DlgProcSkinOpts;
+ odp.nIDBottomSimpleControl = 0;
+ odp.ptszGroup = LPGENT("Skins");
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) &odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_TABCONFIG);
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TAB_LAYOUTTWEAKS));
+ odp.pfnDlgProc = DlgProcTabConfig;
+ odp.nIDBottomSimpleControl = 0;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) &odp);
+
+ /* group chats */
+
+ odp.ptszGroup = LPGENT("Message Sessions");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS1);
+ odp.ptszTitle = LPGENT("Group Chats");
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TABS_MUC_SETTINGS));
+ odp.pfnDlgProc = DlgProcOptions1;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS2);
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TABS_MUC_LOG));
+ odp.pfnDlgProc = DlgProcOptions2;
+ odp.nIDBottomSimpleControl = 0;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS3);
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TABS_MUC_EVENTS));
+ odp.pfnDlgProc = DlgProcOptions3;
+ odp.nIDBottomSimpleControl = 0;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS4);
+ odp.ptszTab = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_TABS_MUC_HIGHLIGHT));
+ odp.pfnDlgProc = CMUCHighlight::dlgProc;
+ odp.nIDBottomSimpleControl = 0;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
+ return 0;
+}
+
+enum
+{
+ CBVT_NONE,
+ CBVT_CHAR,
+ CBVT_INT,
+ CBVT_BYTE,
+ CBVT_DWORD,
+ CBVT_BOOL,
+};
+
+struct OptCheckBox
+{
+ UINT idc;
+
+ DWORD defValue; // should be full combined value for masked items!
+ DWORD dwBit;
+
+ BYTE dbType;
+ char *dbModule;
+ char *dbSetting;
+
+ BYTE valueType;
+ union
+ {
+ void *pValue;
+
+ char *charValue;
+ int *intValue;
+ BYTE *byteValue;
+ DWORD *dwordValue;
+ BOOL *boolValue;
+ };
+};
+
+DWORD OptCheckBox_LoadValue(struct OptCheckBox *cb)
+{
+ switch (cb->valueType)
+ {
+ case CBVT_NONE:
+ switch (cb->dbType)
+ {
+ case DBVT_BYTE:
+ return M->GetByte(cb->dbModule, cb->dbSetting, cb->defValue);
+ case DBVT_WORD:
+ return DBGetContactSettingWord(NULL, cb->dbModule, cb->dbSetting, cb->defValue);
+ case DBVT_DWORD:
+ return M->GetDword(cb->dbModule, cb->dbSetting, cb->defValue);
+ }
+ break;
+
+ case CBVT_CHAR:
+ return *cb->charValue;
+ case CBVT_INT:
+ return *cb->intValue;
+ case CBVT_BYTE:
+ return *cb->byteValue;
+ case CBVT_DWORD:
+ return *cb->dwordValue;
+ case CBVT_BOOL:
+ return *cb->boolValue;
+ }
+
+ return cb->defValue;
+}
+
+void OptCheckBox_Load(HWND hwnd, struct OptCheckBox *cb)
+{
+ DWORD value = OptCheckBox_LoadValue(cb);
+ if (cb->dwBit) value &= cb->dwBit;
+ CheckDlgButton(hwnd, cb->idc, value ? BST_CHECKED : BST_UNCHECKED);
+}
+
+void OptCheckBox_Save(HWND hwnd, struct OptCheckBox *cb)
+{
+ DWORD value = IsDlgButtonChecked(hwnd, cb->idc) == BST_CHECKED;
+
+ if (cb->dwBit)
+ {
+ DWORD curValue = OptCheckBox_LoadValue(cb);
+ value = value ? (curValue | cb->dwBit) : (curValue & ~cb->dwBit);
+ }
+
+ switch (cb->dbType)
+ {
+ case DBVT_BYTE:
+ M->WriteByte(cb->dbModule, cb->dbSetting, (BYTE)value);
+ break;
+ case DBVT_WORD:
+ DBWriteContactSettingWord(NULL, cb->dbModule, cb->dbSetting, (WORD)value);
+ break;
+ case DBVT_DWORD:
+ M->WriteDword(cb->dbModule, cb->dbSetting, (DWORD)value);
+ break;
+ }
+
+ switch (cb->valueType)
+ {
+ case CBVT_CHAR:
+ *cb->charValue = (char)value;
+ break;
+ case CBVT_INT:
+ *cb->intValue = (int)value;
+ break;
+ case CBVT_BYTE:
+ *cb->byteValue = (BYTE)value;
+ break;
+ case CBVT_DWORD:
+ *cb->dwordValue = (DWORD)value;
+ break;
+ case CBVT_BOOL:
+ *cb->boolValue = (BOOL)value;
+ break;
+ }
+}
+
+static INT_PTR CALLBACK DlgProcTabSrmmModernOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct OptCheckBox opts[] =
+ {
+ //{IDC_, def, bit, dbtype, dbmodule, dbsetting, valtype, pval},
+ {IDC_CLOSEONESC, FALSE, 0, DBVT_BYTE, SRMSGMOD_T, "escmode"},
+ {IDC_ALWAYSPOPUP, FALSE, 0, DBVT_BYTE, SRMSGMOD_T, SRMSGSET_AUTOPOPUP},
+ {IDC_CREATEMIN, TRUE, 0, DBVT_BYTE, SRMSGMOD_T, "autocontainer"},
+ //{IDC_USETABS, , 0, DBVT_BYTE, SRMSGMOD_T, },
+ {IDC_CREATENOACTIVATE, TRUE, 0, DBVT_BYTE, SRMSGMOD_T, "autotabs"},
+ {IDC_POPUPONCREATE, FALSE, 0, DBVT_BYTE, SRMSGMOD_T, "cpopup"},
+ {IDC_AUTOSWITCHTABS, TRUE, 0, DBVT_BYTE, SRMSGMOD_T, "autoswitchtabs"},
+ //{IDC_SENDCTRLENTER, , 0, DBVT_BYTE, SRMSGMOD_T, },
+ {IDC_SENDSHIFTENTER, FALSE, 0, DBVT_BYTE, SRMSGMOD_T, "sendonshiftenter"},
+ {IDC_SENDENTER, FALSE, 0, DBVT_BYTE, SRMSGMOD_T, SRMSGSET_SENDONENTER},
+ {IDC_SENDDBLENTER, FALSE, 0, DBVT_BYTE, SRMSGMOD_T, "SendOnDblEnter"},
+ {IDC_MINSEND, FALSE, 0, DBVT_BYTE, SRMSGMOD_T, SRMSGSET_AUTOMIN},
+ {IDC_NOOPENNOTIFY, FALSE, 0, DBVT_BYTE, "tabSRMM_NEN", OPT_WINDOWCHECK, CBVT_BOOL, &nen_options.bWindowCheck},
+ };
+
+ static BOOL bInit = TRUE;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ int i = 0;
+ DWORD maxhist = M->GetDword("maxhist", 0);
+
+ bInit = TRUE;
+
+ TranslateDialogDefault(hwndDlg);
+
+ for (i = 0; i < SIZEOF(opts); ++i)
+ OptCheckBox_Load(hwndDlg, opts+i);
+
+ // Always on!
+ CheckDlgButton(hwndDlg, IDC_SENDCTRLENTER, BST_CHECKED);
+
+ switch (M->GetByte(SRMSGMOD, SRMSGSET_LOADHISTORY, SRMSGDEFSET_LOADHISTORY)) {
+ case LOADHISTORY_UNREAD:
+ CheckDlgButton(hwndDlg, IDC_LOADUNREAD, BST_CHECKED);
+ break;
+ case LOADHISTORY_COUNT:
+ CheckDlgButton(hwndDlg, IDC_LOADCOUNT, BST_CHECKED);
+ Utils::enableDlgControl(hwndDlg, IDC_LOADCOUNTN, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_LOADCOUNTSPIN, TRUE);
+ break;
+ case LOADHISTORY_TIME:
+ CheckDlgButton(hwndDlg, IDC_LOADTIME, BST_CHECKED);
+ Utils::enableDlgControl(hwndDlg, IDC_LOADTIMEN, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_LOADTIMESPIN, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_STMINSOLD, TRUE);
+ break;
+ }
+
+ SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_SETRANGE, 0, MAKELONG(100, 0));
+ SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_SETPOS, 0, DBGetContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADCOUNT, SRMSGDEFSET_LOADCOUNT));
+ SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_SETRANGE, 0, MAKELONG(24 * 60, 0));
+ SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_SETPOS, 0, DBGetContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADTIME, SRMSGDEFSET_LOADTIME));
+
+ SendDlgItemMessage(hwndDlg, IDC_TRIMSPIN, UDM_SETRANGE, 0, MAKELONG(1000, 5));
+ SendDlgItemMessage(hwndDlg, IDC_TRIMSPIN, UDM_SETPOS, 0, maxhist);
+ Utils::enableDlgControl(hwndDlg, IDC_TRIMSPIN, maxhist != 0);
+ Utils::enableDlgControl(hwndDlg, IDC_TRIM, maxhist != 0);
+ CheckDlgButton(hwndDlg, IDC_ALWAYSTRIM, maxhist != 0);
+
+ {
+ BOOL bTabOptGroups = M->GetByte("useclistgroups", 0);
+ BOOL bTabOptLimit = M->GetByte("limittabs", 0);
+ BOOL bTabOptSingle = M->GetByte("singlewinmode", 0);
+
+ if (bTabOptSingle && !bTabOptGroups && !bTabOptLimit)
+ CheckDlgButton(hwndDlg, IDC_USETABS, BST_UNCHECKED);
+ else if (!bTabOptSingle && !bTabOptGroups && !bTabOptLimit)
+ CheckDlgButton(hwndDlg, IDC_USETABS, BST_CHECKED);
+ else
+ {
+ LONG s = (GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_USETABS), GWL_STYLE) & ~BS_TYPEMASK) | BS_AUTO3STATE;
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_USETABS), GWL_STYLE, s);
+ CheckDlgButton(hwndDlg, IDC_USETABS, BST_INDETERMINATE);
+ }
+ }
+
+ bInit = FALSE;
+ return TRUE;
+ }
+
+ case WM_DESTROY:
+ bInit = TRUE;
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_LOADUNREAD:
+ case IDC_LOADCOUNT:
+ case IDC_LOADTIME:
+ Utils::enableDlgControl(hwndDlg, IDC_LOADCOUNTN, IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT));
+ Utils::enableDlgControl(hwndDlg, IDC_LOADCOUNTSPIN, IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT));
+ Utils::enableDlgControl(hwndDlg, IDC_LOADTIMEN, IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
+ Utils::enableDlgControl(hwndDlg, IDC_LOADTIMESPIN, IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
+ Utils::enableDlgControl(hwndDlg, IDC_STMINSOLD, IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
+ break;
+ case IDC_ALWAYSTRIM:
+ Utils::enableDlgControl(hwndDlg, IDC_TRIMSPIN, IsDlgButtonChecked(hwndDlg, IDC_ALWAYSTRIM));
+ Utils::enableDlgControl(hwndDlg, IDC_TRIM, IsDlgButtonChecked(hwndDlg, IDC_ALWAYSTRIM));
+ break;
+ case IDC_TRIM:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return TRUE;
+ break;
+ }
+ if (!bInit)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_NOTIFY:
+ {
+ switch (((LPNMHDR) lParam)->idFrom)
+ {
+ case 0:
+ switch (((LPNMHDR) lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ int i;
+ for (i = 0; i < SIZEOF(opts); ++i)
+ OptCheckBox_Save(hwndDlg, opts+i);
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT))
+ M->WriteByte(SRMSGMOD, SRMSGSET_LOADHISTORY, LOADHISTORY_COUNT);
+ else if (IsDlgButtonChecked(hwndDlg, IDC_LOADTIME))
+ M->WriteByte(SRMSGMOD, SRMSGSET_LOADHISTORY, LOADHISTORY_TIME);
+ else
+ M->WriteByte(SRMSGMOD, SRMSGSET_LOADHISTORY, LOADHISTORY_UNREAD);
+ DBWriteContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADCOUNT, (WORD) SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_GETPOS, 0, 0));
+ DBWriteContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADTIME, (WORD) SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_GETPOS, 0, 0));
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_ALWAYSTRIM))
+ M->WriteDword(SRMSGMOD_T, "maxhist", (DWORD)SendDlgItemMessage(hwndDlg, IDC_TRIMSPIN, UDM_GETPOS, 0, 0));
+ else
+ M->WriteDword(SRMSGMOD_T, "maxhist", 0);
+
+ switch (IsDlgButtonChecked(hwndDlg, IDC_USETABS))
+ {
+ case BST_UNCHECKED:
+ M->WriteByte(SRMSGMOD_T, "useclistgroups", 0);
+ M->WriteByte(SRMSGMOD_T, "limittabs", 0);
+ M->WriteByte(SRMSGMOD_T, "singlewinmode", 1);
+ break;
+ case BST_CHECKED:
+ M->WriteByte(SRMSGMOD_T, "useclistgroups", 0);
+ M->WriteByte(SRMSGMOD_T, "limittabs", 0);
+ M->WriteByte(SRMSGMOD_T, "singlewinmode", 0);
+ break;
+ }
+ PluginConfig.reloadSettings();
+ M->BroadcastMessage(DM_OPTIONSAPPLIED, 1, 0);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static int ModernOptInitialise(WPARAM wParam, LPARAM lParam)
+{
+ static int iBoldControls[] =
+ {
+ IDC_TXT_TITLE1, IDC_TXT_TITLE2,
+ IDC_TXT_TITLE3, IDC_TXT_TITLE4,
+ IDC_TXT_TITLE5,
+ MODERNOPT_CTRL_LAST
+ };
+
+ MODERNOPTOBJECT obj = {0};
+
+ obj.cbSize = sizeof(obj);
+ obj.dwFlags = MODEROPT_FLG_TCHAR|MODEROPT_FLG_NORESIZE;
+ obj.hIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ obj.hInstance = g_hInst;
+ obj.iSection = MODERNOPT_PAGE_MSGS;
+ obj.iType = MODERNOPT_TYPE_SECTIONPAGE;
+ obj.iBoldControls = iBoldControls;
+ obj.lpzClassicGroup = NULL;
+ obj.lpzClassicPage = "Message Sessions";
+ obj.lpzHelpUrl = "http://wiki.miranda-im.org/";
+
+ obj.lpzTemplate = MAKEINTRESOURCEA(IDD_MODERNOPTS);
+ obj.pfnDlgProc = DlgProcTabSrmmModernOptions;
+ CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj);
+ return 0;
+}
+
+int TSAPI InitOptions(void)
+{
+ HookEvent(ME_OPT_INITIALISE, OptInitialise);
+ HookEvent(ME_MODERNOPT_INITIALIZE, ModernOptInitialise);
+ return 0;
+}
+
+INT_PTR CALLBACK DlgProcSetupStatusModes(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DWORD dwStatusMask = GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ static DWORD dwNewStatusMask = 0;
+ static HWND hwndParent = 0;
+
+ switch (msg) {
+ case WM_INITDIALOG: {
+ int i;
+
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ dwStatusMask = lParam;
+
+ SetWindowText(hwndDlg, CTranslator::getOpt(CTranslator::OPT_SMODE_CHOOSE));
+ for (i = ID_STATUS_ONLINE; i <= ID_STATUS_OUTTOLUNCH; i++) {
+ SetWindowText(GetDlgItem(hwndDlg, i), (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)i, GSMDF_TCHAR));
+ if (dwStatusMask != -1 && (dwStatusMask & (1 << (i - ID_STATUS_ONLINE))))
+ CheckDlgButton(hwndDlg, i, TRUE);
+ Utils::enableDlgControl(hwndDlg, i, dwStatusMask != -1);
+ }
+ if (dwStatusMask == -1)
+ CheckDlgButton(hwndDlg, IDC_ALWAYS, TRUE);
+ ShowWindow(hwndDlg, SW_SHOWNORMAL);
+ return TRUE;
+ }
+ case DM_SETPARENTDIALOG:
+ hwndParent = (HWND)lParam;
+ break;
+ case DM_GETSTATUSMASK: {
+ if (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS))
+ dwNewStatusMask = -1;
+ else {
+ int i;
+ dwNewStatusMask = 0;
+ for (i = ID_STATUS_ONLINE; i <= ID_STATUS_OUTTOLUNCH; i++)
+ dwNewStatusMask |= (IsDlgButtonChecked(hwndDlg, i) ? (1 << (i - ID_STATUS_ONLINE)) : 0);
+ }
+ break;
+ }
+ case WM_COMMAND: {
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ if (LOWORD(wParam) == IDOK) {
+ SendMessage(hwndDlg, DM_GETSTATUSMASK, 0, 0);
+ SendMessage(hwndParent, DM_STATUSMASKSET, 0, (LPARAM)dwNewStatusMask);
+ }
+ DestroyWindow(hwndDlg);
+ break;
+ case IDC_ALWAYS: {
+ int i;
+ for (i = ID_STATUS_ONLINE; i <= ID_STATUS_OUTTOLUNCH; i++)
+ Utils::enableDlgControl(hwndDlg, i, !IsDlgButtonChecked(hwndDlg, IDC_ALWAYS));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ case WM_DESTROY:
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
diff --git a/plugins/TabSRMM/src/msgs.cpp b/plugins/TabSRMM/src/msgs.cpp
new file mode 100644
index 0000000000..5c67a6a797
--- /dev/null
+++ b/plugins/TabSRMM/src/msgs.cpp
@@ -0,0 +1,1180 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: msgs.cpp 13587 2011-04-12 13:54:26Z george.hazan $
+ *
+ * Load, setup and shutdown the plugin
+ * core plugin messaging services (single IM chats only).
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+#define IDI_CORE_LOAD 132 // icon id for the "connecting" icon
+
+REOLECallback* mREOLECallback;
+NEN_OPTIONS nen_options;
+extern PLUGININFOEX pluginInfo;
+extern HANDLE hHookToolBarLoadedEvt;
+static HANDLE hUserPrefsWindowLis = 0;
+HMODULE g_hIconDLL = 0;
+
+static void UnloadIcons();
+
+extern INT_PTR CALLBACK DlgProcUserPrefsFrame(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+extern struct TLogIcon msgLogIcons[NR_LOGICONS * 3];
+extern int CacheIconToBMP (struct TLogIcon *theIcon, HICON hIcon, COLORREF backgroundColor, int sizeX, int sizeY);
+extern void DeleteCachedIcon(struct TLogIcon *theIcon);
+
+int Chat_IconsChanged(WPARAM wp, LPARAM lp);
+void Chat_AddIcons(void);
+int Chat_PreShutdown(WPARAM wParam, LPARAM lParam);
+
+/*
+ * fired event when user changes IEView plugin options. Apply them to all open tabs
+ */
+
+int IEViewOptionsChanged(WPARAM wParam, LPARAM lParam)
+{
+ M->BroadcastMessage(DM_IEVIEWOPTIONSCHANGED, 0, 0);
+ return 0;
+}
+
+/*
+ * fired event when user changes smileyadd options. Notify all open tabs about the changes
+ */
+
+int SmileyAddOptionsChanged(WPARAM wParam, LPARAM lParam)
+{
+ M->BroadcastMessage(DM_SMILEYOPTIONSCHANGED, 0, 0);
+ if (PluginConfig.m_chat_enabled)
+ SM_BroadcastMessage(NULL, DM_SMILEYOPTIONSCHANGED, 0, 0, FALSE);
+ return 0;
+}
+
+/*
+ * Message API 0.0.0.3 services
+ */
+
+static INT_PTR GetWindowClass(WPARAM wParam, LPARAM lParam)
+
+{
+ char *szBuf = (char*)wParam;
+ int size = (int)lParam;
+ mir_snprintf(szBuf, size, "tabSRMM");
+ return 0;
+}
+
+/*
+ * service function. retrieves the message window data for a given hcontact or window
+ * wParam == hContact of the window to find
+ * lParam == window handle (set it to 0 if you want search for hcontact, otherwise it
+ * is directly used as the handle for the target window
+ */
+
+static INT_PTR GetWindowData(WPARAM wParam, LPARAM lParam)
+{
+ MessageWindowInputData *mwid = (MessageWindowInputData*)wParam;
+ MessageWindowOutputData *mwod = (MessageWindowOutputData*)lParam;
+ HWND hwnd;
+ SESSION_INFO *si = NULL;
+
+ if (mwid == NULL || mwod == NULL)
+ return 1;
+ if (mwid->cbSize != sizeof(MessageWindowInputData) || mwod->cbSize != sizeof(MessageWindowOutputData))
+ return 1;
+ if (mwid->hContact == NULL)
+ return 1;
+ if (mwid->uFlags != MSG_WINDOW_UFLAG_MSG_BOTH)
+ return 1;
+ hwnd = M->FindWindow(mwid->hContact);
+ if (hwnd) {
+ mwod->uFlags = MSG_WINDOW_UFLAG_MSG_BOTH;
+ mwod->hwndWindow = hwnd;
+ mwod->local = GetParent(GetParent(hwnd));
+ SendMessage(hwnd, DM_GETWINDOWSTATE, 0, 0);
+ mwod->uState = (int)GetWindowLongPtr(hwnd, DWLP_MSGRESULT);
+ return 0;
+ }
+ else if ((si = SM_FindSessionByHCONTACT(mwid->hContact)) != NULL && si->hWnd != 0) {
+ mwod->uFlags = MSG_WINDOW_UFLAG_MSG_BOTH;
+ mwod->hwndWindow = si->hWnd;
+ mwod->local = GetParent(GetParent(si->hWnd));
+ SendMessage(si->hWnd, DM_GETWINDOWSTATE, 0, 0);
+ mwod->uState = (int)GetWindowLongPtr(si->hWnd, DWLP_MSGRESULT);
+ return 0;
+ }
+ else {
+ mwod->uState = 0;
+ mwod->hContact = 0;
+ mwod->hwndWindow = 0;
+ mwod->uFlags = 0;
+ }
+ return 1;
+}
+
+/*
+ * service function. Invoke the user preferences dialog for the contact given (by handle) in wParam
+ */
+
+static INT_PTR SetUserPrefs(WPARAM wParam, LPARAM lParam)
+{
+ HWND hWnd = WindowList_Find(PluginConfig.hUserPrefsWindowList, (HANDLE)wParam);
+ if (hWnd) {
+ SetForegroundWindow(hWnd); // already open, bring it to front
+ return 0;
+ }
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_USERPREFS_FRAME), 0, DlgProcUserPrefsFrame, (LPARAM)wParam);
+ return 0;
+}
+
+/*
+ * service function - open the tray menu from the TTB button
+ */
+
+static INT_PTR Service_OpenTrayMenu(WPARAM wParam, LPARAM lParam)
+{
+ SendMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, lParam == 0 ? WM_LBUTTONUP : WM_RBUTTONUP);
+ return 0;
+}
+
+/*
+ * service function. retrieves the message window flags for a given hcontact or window
+ * wParam == hContact of the window to find
+ * lParam == window handle (set it to 0 if you want search for hcontact, otherwise it
+ * is directly used as the handle for the target window
+ */
+
+static INT_PTR GetMessageWindowFlags(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndTarget = (HWND)lParam;
+
+ if (hwndTarget == 0)
+ hwndTarget = M->FindWindow((HANDLE)wParam);
+
+ if (hwndTarget) {
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndTarget, GWLP_USERDATA);
+ if (dat)
+ return (dat->dwFlags);
+ else
+ return 0;
+ } else
+ return 0;
+}
+
+/*
+ * return the version of the window api supported
+ */
+
+static INT_PTR GetWindowAPI(WPARAM wParam, LPARAM lParam)
+{
+ return PLUGIN_MAKE_VERSION(0, 0, 0, 2);
+}
+
+/*
+ * service function finds a message session
+ * wParam = contact handle for which we want the window handle
+ * thanks to bio for the suggestion of this service
+ * if wParam == 0, then lParam is considered to be a valid window handle and
+ * the function tests the popup mode of the target container
+
+ * returns the hwnd if there is an open window or tab for the given hcontact (wParam),
+ * or (if lParam was specified) the hwnd if the window exists.
+ * 0 if there is none (or the popup mode of the target container was configured to "hide"
+ * the window..
+ */
+
+INT_PTR MessageWindowOpened(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwnd = 0;
+ struct TContainerData *pContainer = NULL;
+
+ if (wParam)
+ hwnd = M->FindWindow((HANDLE)wParam);
+ else if (lParam)
+ hwnd = (HWND) lParam;
+ else
+ hwnd = NULL;
+
+ if (hwnd) {
+ SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
+ if (pContainer) {
+ if (pContainer->dwFlags & CNT_DONTREPORT) {
+ if (IsIconic(pContainer->hwnd))
+ return 0;
+ }
+ if (pContainer->dwFlags & CNT_DONTREPORTUNFOCUSED) {
+ if (!IsIconic(pContainer->hwnd) && GetForegroundWindow() != pContainer->hwnd && GetActiveWindow() != pContainer->hwnd)
+ return 0;
+ }
+ if (pContainer->dwFlags & CNT_ALWAYSREPORTINACTIVE) {
+ if (pContainer->dwFlags & CNT_DONTREPORTFOCUSED)
+ return 0;
+
+ if (pContainer->hwndActive == hwnd)
+ return 1;
+ else
+ return 0;
+ }
+ }
+ return 1;
+ } else
+ return 0;
+}
+
+/*
+ * ReadMessageCommand is executed whenever the user wants to manually open a window.
+ * This can happen when double clicking a contact on the clist OR when opening a new
+ * message (clicking on a popup, clicking the flashing tray icon and so on).
+ */
+
+static INT_PTR ReadMessageCommand(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndExisting;
+ HANDLE hContact = ((CLISTEVENT *) lParam)->hContact;
+ struct TContainerData *pContainer = 0;
+
+ hwndExisting = M->FindWindow(hContact);
+
+ if (hwndExisting != 0)
+ SendMessage(hwndExisting, DM_ACTIVATEME, 0, 0);
+ else {
+ TCHAR szName[CONTAINER_NAMELEN + 1];
+ GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN);
+ pContainer = FindContainerByName(szName);
+ if (pContainer == NULL)
+ pContainer = CreateContainer(szName, FALSE, hContact);
+ CreateNewTabForContact(pContainer, hContact, 0, NULL, TRUE, TRUE, FALSE, 0);
+ }
+ return 0;
+}
+
+
+/*
+ * this is the Unicode version of the SendMessageCommand handler. It accepts wchar_t strings
+ * for filling the message input box with a passed message
+ */
+
+INT_PTR SendMessageCommand_W(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwnd;
+ char *szProto;
+ struct TNewWindowData newData = {
+ 0
+ };
+ struct TContainerData *pContainer = 0;
+ int isSplit = 1;
+
+ /*
+ * make sure that only the main UI thread will handle window creation
+ */
+ if (GetCurrentThreadId() != PluginConfig.dwThreadID) {
+ if (lParam) {
+ unsigned iLen = lstrlenW((wchar_t *)lParam);
+ wchar_t *tszText = (wchar_t *)malloc((iLen + 1) * sizeof(wchar_t));
+ wcsncpy(tszText, (wchar_t *)lParam, iLen + 1);
+ tszText[iLen] = 0;
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SENDMESSAGECOMMANDW, wParam, (LPARAM)tszText);
+ } else
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SENDMESSAGECOMMANDW, wParam, 0);
+ return 0;
+ }
+
+ /* does the HCONTACT's protocol support IM messages? */
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto) {
+ if (!CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND)
+ return 0;
+ } else {
+ /* unknown contact */
+ return 0;
+ }
+
+ if (hwnd = M->FindWindow((HANDLE) wParam)) {
+ if (lParam) {
+ HWND hEdit;
+ hEdit = GetDlgItem(hwnd, IDC_MESSAGE);
+ SendMessage(hEdit, EM_SETSEL, -1, SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0));
+ SendMessage(hEdit, EM_REPLACESEL, FALSE, (LPARAM)(TCHAR *) lParam);
+ }
+ SendMessage(hwnd, DM_ACTIVATEME, 0, (LPARAM) 0);
+ } else {
+ TCHAR szName[CONTAINER_NAMELEN + 1];
+
+ GetContainerNameForContact((HANDLE) wParam, szName, CONTAINER_NAMELEN);
+ pContainer = FindContainerByName(szName);
+ if (pContainer == NULL)
+ pContainer = CreateContainer(szName, FALSE, (HANDLE)wParam);
+ CreateNewTabForContact(pContainer, (HANDLE) wParam, 1, (const char *)lParam, TRUE, TRUE, FALSE, 0);
+ }
+ return 0;
+}
+
+/*
+ * the SendMessageCommand() invokes a message session window for the given contact.
+ * e.g. it is called when user double clicks a contact on the contact list
+ * it is implemented as a service, so external plugins can use it to open a message window.
+ * contacts handle must be passed in wParam.
+ */
+
+INT_PTR SendMessageCommand(WPARAM wParam, LPARAM lParam)
+{
+ HWND hwnd;
+ char *szProto;
+ struct TNewWindowData newData = {
+ 0
+ };
+ struct TContainerData *pContainer = 0;
+ int isSplit = 1;
+
+ if (GetCurrentThreadId() != PluginConfig.dwThreadID) {
+ if (lParam) {
+ unsigned iLen = lstrlenA((char *)lParam);
+ char *szText = (char *)malloc(iLen + 1);
+ strncpy(szText, (char *)lParam, iLen + 1);
+ szText[iLen] = 0;
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SENDMESSAGECOMMAND, wParam, (LPARAM)szText);
+ } else
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SENDMESSAGECOMMAND, wParam, 0);
+ return 0;
+ }
+
+ /* does the HCONTACT's protocol support IM messages? */
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto) {
+ if (!CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND)
+ return 0;
+ } else {
+ /* unknown contact */
+ return 0;
+ }
+
+ if (hwnd = M->FindWindow((HANDLE) wParam)) {
+ if (lParam) {
+ HWND hEdit = GetDlgItem(hwnd, IDC_MESSAGE);
+ SendMessage(hEdit, EM_SETSEL, -1, SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0));
+ SendMessageA(hEdit, EM_REPLACESEL, FALSE, (LPARAM)(char *) lParam);
+ }
+ SendMessage(hwnd, DM_ACTIVATEME, 0, 0); // ask the message window about its parent...
+ } else {
+ TCHAR szName[CONTAINER_NAMELEN + 1];
+ GetContainerNameForContact((HANDLE) wParam, szName, CONTAINER_NAMELEN);
+ pContainer = FindContainerByName(szName);
+ if (pContainer == NULL)
+ pContainer = CreateContainer(szName, FALSE, (HANDLE)wParam);
+ CreateNewTabForContact(pContainer, (HANDLE) wParam, 0, (const char *) lParam, TRUE, TRUE, FALSE, 0);
+ }
+ return 0;
+}
+
+/*
+ * open a window when user clicks on the flashing "typing message" tray icon.
+ * just calls SendMessageCommand() for the given contact.
+ */
+static INT_PTR TypingMessageCommand(WPARAM wParam, LPARAM lParam)
+{
+ CLISTEVENT *cle = (CLISTEVENT *) lParam;
+
+ if (!cle)
+ return 0;
+ SendMessageCommand((WPARAM) cle->hContact, 0);
+ return 0;
+}
+
+int SplitmsgShutdown(void)
+{
+#if defined(__USE_EX_HANDLERS)
+ __try {
+#endif
+ DestroyCursor(PluginConfig.hCurSplitNS);
+ DestroyCursor(PluginConfig.hCurHyperlinkHand);
+ DestroyCursor(PluginConfig.hCurSplitWE);
+ FreeLibrary(GetModuleHandleA("riched20"));
+ if (g_hIconDLL)
+ FreeLibrary(g_hIconDLL);
+
+ ImageList_RemoveAll(PluginConfig.g_hImageList);
+ ImageList_Destroy(PluginConfig.g_hImageList);
+
+ delete Win7Taskbar;
+ delete mREOLECallback;
+
+ OleUninitialize();
+ DestroyMenu(PluginConfig.g_hMenuContext);
+ if (PluginConfig.g_hMenuContainer)
+ DestroyMenu(PluginConfig.g_hMenuContainer);
+ if (PluginConfig.g_hMenuEncoding)
+ DestroyMenu(PluginConfig.g_hMenuEncoding);
+
+ UnloadIcons();
+ FreeTabConfig();
+
+ if (Utils::rtf_ctable)
+ free(Utils::rtf_ctable);
+
+ UnloadTSButtonModule();
+
+ if (g_hIconDLL) {
+ FreeLibrary(g_hIconDLL);
+ g_hIconDLL = 0;
+ }
+#if defined(__USE_EX_HANDLERS)
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"SHUTDOWN_STAGE3", false)) {
+ return(0);
+ }
+#endif
+ return 0;
+}
+
+int MyAvatarChanged(WPARAM wParam, LPARAM lParam)
+{
+ struct TContainerData *pContainer = pFirstContainer;
+
+ if (wParam == 0 || IsBadReadPtr((void *)wParam, 4))
+ return 0;
+
+ while (pContainer) {
+ BroadCastContainer(pContainer, DM_MYAVATARCHANGED, wParam, lParam);
+ pContainer = pContainer->pNextContainer;
+ }
+ return 0;
+}
+
+int AvatarChanged(WPARAM wParam, LPARAM lParam)
+{
+ struct avatarCacheEntry *ace = (struct avatarCacheEntry *)lParam;
+ HWND hwnd = M->FindWindow((HANDLE)wParam);
+
+ if (wParam == 0) { // protocol picture has changed...
+ M->BroadcastMessage(DM_PROTOAVATARCHANGED, wParam, lParam);
+ return 0;
+ }
+ if (hwnd) {
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (dat) {
+ dat->ace = ace;
+ if(dat->hTaskbarIcon)
+ DestroyIcon(dat->hTaskbarIcon);
+ dat->hTaskbarIcon = 0;
+ DM_RecalcPictureSize(dat);
+ if (dat->showPic == 0 || dat->showInfoPic == 0)
+ GetAvatarVisibility(hwnd, dat);
+ if(dat->hwndPanelPic) {
+ dat->panelWidth = -1; // force new size calculations (not for flash avatars)
+ SendMessage(dat->hwnd, WM_SIZE, 0, 1);
+ }
+ dat->panelWidth = -1; // force new size calculations (not for flash avatars)
+ RedrawWindow(dat->hwnd, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
+ SendMessage(dat->hwnd, WM_SIZE, 0, 1);
+ ShowPicture(dat, TRUE);
+ dat->dwFlagsEx |= MWF_EX_AVATARCHANGED;
+ dat->pContainer->SideBar->updateSession(dat);
+ }
+ }
+ return 0;
+}
+
+int IcoLibIconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ LoadFromIconLib();
+ CacheMsgLogIcons();
+ if (PluginConfig.m_chat_enabled)
+ Chat_IconsChanged(wParam, lParam);
+ return 0;
+}
+
+int IconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ CreateImageList(FALSE);
+ CacheMsgLogIcons();
+ M->BroadcastMessage(DM_OPTIONSAPPLIED, 0, 0);
+ M->BroadcastMessage(DM_UPDATEWINICON, 0, 0);
+ if (PluginConfig.m_chat_enabled)
+ Chat_IconsChanged(wParam, lParam);
+
+ return 0;
+}
+
+/**
+ * initialises the internal API, services, events etc...
+ */
+
+static struct _svcdef {
+ char *szName;
+ INT_PTR (*pfnService)(WPARAM wParam, LPARAM lParam);
+ HANDLE *h;
+} SERVICES[] = {
+ MS_MSG_SENDMESSAGE, SendMessageCommand, &PluginConfig.hSvc[CGlobals::H_MS_MSG_SENDMESSAGE],
+ MS_MSG_GETWINDOWAPI, GetWindowAPI, &PluginConfig.hSvc[CGlobals::H_MS_MSG_GETWINDOWAPI],
+ MS_MSG_GETWINDOWCLASS, GetWindowClass, &PluginConfig.hSvc[CGlobals::H_MS_MSG_GETWINDOWCLASS],
+ MS_MSG_GETWINDOWDATA, GetWindowData, &PluginConfig.hSvc[CGlobals::H_MS_MSG_GETWINDOWDATA],
+ "SRMsg/ReadMessage", ReadMessageCommand, &PluginConfig.hSvc[CGlobals::H_MS_MSG_READMESSAGE],
+ "SRMsg/TypingMessage", TypingMessageCommand, &PluginConfig.hSvc[CGlobals::H_MS_MSG_TYPINGMESSAGE],
+ MS_MSG_MOD_MESSAGEDIALOGOPENED, MessageWindowOpened, &PluginConfig.hSvc[CGlobals::H_MS_MSG_MOD_MESSAGEDIALOGOPENED],
+ MS_TABMSG_SETUSERPREFS, SetUserPrefs, &PluginConfig.hSvc[CGlobals::H_MS_TABMSG_SETUSERPREFS],
+ MS_TABMSG_TRAYSUPPORT, Service_OpenTrayMenu, &PluginConfig.hSvc[CGlobals::H_MS_TABMSG_TRAYSUPPORT],
+ MS_MSG_MOD_GETWINDOWFLAGS, GetMessageWindowFlags, &PluginConfig.hSvc[CGlobals::H_MSG_MOD_GETWINDOWFLAGS],
+ MS_TABMSG_SLQMGR, CSendLater::svcQMgr, &PluginConfig.hSvc[CGlobals::H_MS_TABMSG_SLQMGR]
+};
+
+static void TSAPI InitAPI()
+{
+ int i;
+
+ ZeroMemory(PluginConfig.hSvc, sizeof(HANDLE) * CGlobals::SERVICE_LAST);
+
+ for(i = 0; i < safe_sizeof(SERVICES); i++)
+ *(SERVICES[i].h) = CreateServiceFunction(SERVICES[i].szName, SERVICES[i].pfnService);
+
+ *(SERVICES[CGlobals::H_MS_MSG_SENDMESSAGEW].h) = CreateServiceFunction(MS_MSG_SENDMESSAGE "W", SendMessageCommand_W);
+ SI_InitStatusIcons();
+ CB_InitCustomButtons();
+
+ /*
+ * the event API
+ */
+
+ PluginConfig.m_event_MsgWin = CreateHookableEvent(ME_MSG_WINDOWEVENT);
+ PluginConfig.m_event_MsgPopup = CreateHookableEvent(ME_MSG_WINDOWPOPUP);
+}
+
+int LoadSendRecvMessageModule(void)
+{
+ INITCOMMONCONTROLSEX icex;
+
+ if(FIF == 0) {
+ MessageBox(0, TranslateT("The image service plugin (advaimg.dll) is not properly installed.\n\nTabSRMM is disabled."), TranslateT("TabSRMM fatal error"), MB_OK | MB_ICONERROR);
+ return(1);
+ }
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES;;
+ InitCommonControlsEx(&icex);
+
+ Utils::loadSystemLibrary(L"\\riched20.dll");
+
+ OleInitialize(NULL);
+ mREOLECallback = new REOLECallback;
+ Win7Taskbar = new CTaskbarInteract;
+ Win7Taskbar->updateMetrics();
+
+ ZeroMemory((void *)&nen_options, sizeof(nen_options));
+ M->m_hMessageWindowList = (HANDLE) CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0);
+ PluginConfig.hUserPrefsWindowList = (HANDLE) CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0);
+ sendQueue = new SendQueue;
+ Skin = new CSkin;
+ sendLater = new CSendLater;
+
+ InitOptions();
+
+ InitAPI();
+
+ PluginConfig.reloadSystemStartup();
+ ReloadTabConfig();
+ NEN_ReadOptions(&nen_options);
+
+ M->WriteByte(TEMPLATES_MODULE, "setup", 2);
+ LoadDefaultTemplates();
+
+ BuildCodePageList();
+
+ return 0;
+}
+
+STDMETHODIMP REOLECallback::GetNewStorage(LPSTORAGE FAR *lplpstg)
+{
+ LPLOCKBYTES lpLockBytes = NULL;
+ SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
+ if (sc != S_OK)
+ return sc;
+ sc = ::StgCreateDocfileOnILockBytes(lpLockBytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, lplpstg);
+ if (sc != S_OK)
+ lpLockBytes->Release();
+ return sc;
+}
+
+
+/*
+ * tabbed mode support functions...
+ * (C) by Nightwish
+ *
+ * this function searches and activates the tab belonging to the given hwnd (which is the
+ * hwnd of a message dialog window)
+ */
+
+int TSAPI ActivateExistingTab(TContainerData *pContainer, HWND hwndChild)
+{
+ struct TWindowData *dat = 0;
+ NMHDR nmhdr;
+
+ dat = (struct TWindowData *) GetWindowLongPtr(hwndChild, GWLP_USERDATA); // needed to obtain the hContact for the message window
+ if (dat && pContainer) {
+ ZeroMemory((void *)&nmhdr, sizeof(nmhdr));
+ nmhdr.code = TCN_SELCHANGE;
+ if (TabCtrl_GetItemCount(GetDlgItem(pContainer->hwnd, IDC_MSGTABS)) > 1 && !(pContainer->dwFlags & CNT_DEFERREDTABSELECT)) {
+ TabCtrl_SetCurSel(GetDlgItem(pContainer->hwnd, IDC_MSGTABS), GetTabIndexFromHWND(GetDlgItem(pContainer->hwnd, IDC_MSGTABS), hwndChild));
+ SendMessage(pContainer->hwnd, WM_NOTIFY, 0, (LPARAM) &nmhdr); // just select the tab and let WM_NOTIFY do the rest
+ }
+ if (dat->bType == SESSIONTYPE_IM)
+ SendMessage(pContainer->hwnd, DM_UPDATETITLE, (WPARAM)dat->hContact, 0);
+ if (IsIconic(pContainer->hwnd)) {
+ SendMessage(pContainer->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+ SetForegroundWindow(pContainer->hwnd);
+ }
+ //MaD - hide on close feature
+ if (!IsWindowVisible(pContainer->hwnd)) {
+ WINDOWPLACEMENT wp={0};
+ wp.length = sizeof(wp);
+ GetWindowPlacement(pContainer->hwnd, &wp);
+
+ /*
+ * all tabs must re-check the layout on activation because adding a tab while
+ * the container was hidden can make this necessary
+ */
+ BroadCastContainer(pContainer, DM_CHECKSIZE, 0, 0);
+ if(wp.showCmd == SW_SHOWMAXIMIZED)
+ ShowWindow(pContainer->hwnd, SW_SHOWMAXIMIZED);
+ else {
+ ShowWindow(pContainer->hwnd, SW_SHOWNA);
+ SetForegroundWindow(pContainer->hwnd);
+ }
+ SendMessage(pContainer->hwndActive, WM_SIZE, 0, 0); // make sure the active tab resizes its layout properly
+ }
+ //MaD_
+ else if (GetForegroundWindow() != pContainer->hwnd)
+ SetForegroundWindow(pContainer->hwnd);
+ if (dat->bType == SESSIONTYPE_IM)
+ SetFocus(GetDlgItem(hwndChild, IDC_MESSAGE));
+ return TRUE;
+ } else
+ return FALSE;
+}
+
+/*
+ * this function creates and activates a new tab within the given container.
+ * bActivateTab: make the new tab the active one
+ * bPopupContainer: restore container if it was minimized, otherwise flash it...
+ */
+
+HWND TSAPI CreateNewTabForContact(struct TContainerData *pContainer, HANDLE hContact, int isSend, const char *pszInitialText, BOOL bActivateTab, BOOL bPopupContainer, BOOL bWantPopup, HANDLE hdbEvent)
+{
+ TCHAR *contactName = NULL, newcontactname[128], *szStatus, tabtitle[128];
+ char *szProto = NULL;
+ WORD wStatus;
+ int newItem;
+ HWND hwndNew = 0;
+ HWND hwndTab;
+ struct TNewWindowData newData = {0};
+ DBVARIANT dbv = {0};
+
+ if (M->FindWindow(hContact) != 0) {
+ _DebugPopup(hContact, _T("Warning: trying to create duplicate window"));
+ return 0;
+ }
+ // if we have a max # of tabs/container set and want to open something in the default container...
+ if (hContact != 0 && M->GetByte("limittabs", 0) && !_tcsncmp(pContainer->szName, _T("default"), 6)) {
+ if ((pContainer = FindMatchingContainer(_T("default"), hContact)) == NULL) {
+ TCHAR szName[CONTAINER_NAMELEN + 1];
+
+ _sntprintf(szName, CONTAINER_NAMELEN, _T("default"));
+ pContainer = CreateContainer(szName, CNT_CREATEFLAG_CLONED, hContact);
+ }
+ }
+
+ newData.hContact = hContact;
+ newData.isWchar = isSend;
+ newData.szInitialText = pszInitialText;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) newData.hContact, 0);
+
+ ZeroMemory((void *)&newData.item, sizeof(newData.item));
+
+ // obtain various status information about the contact
+ contactName = (TCHAR *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) newData.hContact, GCDNF_TCHAR);
+
+ /*
+ * cut nickname if larger than x chars...
+ */
+
+ if (contactName && lstrlen(contactName) > 0) {
+ if (M->GetByte("cuttitle", 0))
+ CutContactName(contactName, newcontactname, safe_sizeof(newcontactname));
+ else {
+ lstrcpyn(newcontactname, contactName, safe_sizeof(newcontactname));
+ newcontactname[127] = 0;
+ }
+ //Mad: to fix tab width for nicknames with ampersands
+ Utils::DoubleAmpersands(newcontactname);
+ } else
+ lstrcpyn(newcontactname, _T("_U_"), safe_sizeof(newcontactname));
+
+ wStatus = szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord((HANDLE) newData.hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ szStatus = (TCHAR *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord((HANDLE)newData.hContact, szProto, "Status", ID_STATUS_OFFLINE), GSMDF_TCHAR);
+
+ if (M->GetByte("tabstatus", 1))
+ mir_sntprintf(tabtitle, safe_sizeof(tabtitle), _T("%s (%s) "), newcontactname, szStatus);
+ else
+ mir_sntprintf(tabtitle, safe_sizeof(tabtitle), _T("%s "), newcontactname);
+
+ newData.item.pszText = tabtitle;
+ newData.item.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
+ newData.item.iImage = 0;
+ newData.item.cchTextMax = 255;
+
+ hwndTab = GetDlgItem(pContainer->hwnd, IDC_MSGTABS);
+ // hide the active tab
+ if (pContainer->hwndActive && bActivateTab)
+ ShowWindow(pContainer->hwndActive, SW_HIDE);
+
+ {
+ int iTabIndex_wanted = M->GetDword(hContact, "tabindex", pContainer->iChilds * 100);
+ int iCount = TabCtrl_GetItemCount(hwndTab);
+ TCITEM item = {0};
+ HWND hwnd;
+ struct TWindowData *dat;
+ int relPos;
+ int i;
+
+ pContainer->iTabIndex = iCount;
+ if (iCount > 0) {
+ for (i = iCount - 1; i >= 0; i--) {
+ item.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, i, &item);
+ hwnd = (HWND)item.lParam;
+ dat = (struct TWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (dat) {
+ relPos = M->GetDword(dat->hContact, "tabindex", i * 100);
+ if (iTabIndex_wanted <= relPos)
+ pContainer->iTabIndex = i;
+ }
+ }
+ }
+ }
+ newItem = TabCtrl_InsertItem(hwndTab, pContainer->iTabIndex, &newData.item);
+ SendMessage(hwndTab, EM_REFRESHWITHOUTCLIP, 0, 0);
+ if (bActivateTab)
+ TabCtrl_SetCurSel(GetDlgItem(pContainer->hwnd, IDC_MSGTABS), newItem);
+ newData.iTabID = newItem;
+ newData.iTabImage = newData.item.iImage;
+ newData.pContainer = pContainer;
+ newData.iActivate = (int) bActivateTab;
+ pContainer->iChilds++;
+ newData.bWantPopup = bWantPopup;
+ newData.hdbEvent = hdbEvent;
+ hwndNew = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSGSPLITNEW), GetDlgItem(pContainer->hwnd, IDC_MSGTABS), DlgProcMessage, (LPARAM) & newData);
+ /*
+ * switchbar support
+ */
+ if(pContainer->dwFlags & CNT_SIDEBAR) {
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(hwndNew, GWLP_USERDATA);
+ if(dat)
+ pContainer->SideBar->addSession(dat, pContainer->iTabIndex);
+ }
+ SendMessage(pContainer->hwnd, WM_SIZE, 0, 0);
+
+ // if the container is minimized, then pop it up...
+
+ if (IsIconic(pContainer->hwnd)) {
+ if (bPopupContainer) {
+ SendMessage(pContainer->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+ SetFocus(pContainer->hwndActive);
+ } else {
+ if (pContainer->dwFlags & CNT_NOFLASH)
+ SendMessage(pContainer->hwnd, DM_SETICON, 0, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE));
+ else
+ FlashContainer(pContainer, 1, 0);
+ }
+ }
+ if (bActivateTab) {
+ ActivateExistingTab(pContainer, hwndNew);
+ SetFocus(hwndNew);
+ RedrawWindow(pContainer->hwnd, NULL, NULL, RDW_ERASENOW);
+ UpdateWindow(pContainer->hwnd);
+ if (GetForegroundWindow() != pContainer->hwnd && bPopupContainer == TRUE)
+ SetForegroundWindow(pContainer->hwnd);
+ }
+ else if(!IsIconic(pContainer->hwnd) && IsWindowVisible(pContainer->hwnd)){
+ SendMessage(pContainer->hwndActive, WM_SIZE, 0, 0);
+ RedrawWindow(pContainer->hwndActive, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);
+ RedrawWindow(pContainer->hwndActive, NULL, NULL, RDW_ERASENOW | RDW_UPDATENOW);
+ }
+
+ //MaD
+ if (PluginConfig.m_HideOnClose&&!IsWindowVisible(pContainer->hwnd)){
+ WINDOWPLACEMENT wp={0};
+ wp.length = sizeof(wp);
+ GetWindowPlacement(pContainer->hwnd, &wp);
+
+ BroadCastContainer(pContainer, DM_CHECKSIZE, 0, 0); // make sure all tabs will re-check layout on activation
+ if(wp.showCmd == SW_SHOWMAXIMIZED)
+ ShowWindow(pContainer->hwnd, SW_SHOWMAXIMIZED);
+ else {
+ if(bPopupContainer)
+ ShowWindow(pContainer->hwnd, SW_SHOWNORMAL);
+ else
+ ShowWindow(pContainer->hwnd, SW_SHOWMINNOACTIVE);
+ }
+ SendMessage(pContainer->hwndActive, WM_SIZE, 0, 0);
+ }
+ if(PluginConfig.m_bIsWin7 && PluginConfig.m_useAeroPeek && CSkin::m_skinEnabled) // && !M->GetByte("forceAeroPeek", 0))
+ CWarning::show(CWarning::WARN_AEROPEEK_SKIN, MB_ICONWARNING|MB_OK);
+
+ if(ServiceExists(MS_HPP_EG_EVENT) && ServiceExists(MS_IEVIEW_EVENT) && M->GetByte(0, "HistoryPlusPlus", "IEViewAPI", 0)) {
+ if(IDYES == CWarning::show(CWarning::WARN_HPP_APICHECK, MB_ICONWARNING|MB_YESNO))
+ M->WriteByte(0, "HistoryPlusPlus", "IEViewAPI", 0);
+ }
+ return hwndNew; // return handle of the new dialog
+}
+
+/*
+ * this is used by the 2nd containermode (limit tabs on default containers).
+ * it searches a container with "room" for the new tabs or otherwise creates
+ * a new (cloned) one.
+ */
+
+struct TContainerData* TSAPI FindMatchingContainer(const TCHAR *szName, HANDLE hContact)
+{
+ struct TContainerData *pDesired = 0;
+ int iMaxTabs = M->GetDword("maxtabs", 0);
+
+ if (iMaxTabs > 0 && M->GetByte("limittabs", 0) && !_tcsncmp(szName, _T("default"), 6)) {
+ struct TContainerData *pCurrent = pFirstContainer;
+ // search a "default" with less than iMaxTabs opened...
+ while (pCurrent) {
+ if (!_tcsncmp(pCurrent->szName, _T("default"), 6) && pCurrent->iChilds < iMaxTabs) {
+ pDesired = pCurrent;
+ break;
+ }
+ pCurrent = pCurrent->pNextContainer;
+ }
+ return(pDesired != NULL ? pDesired : NULL);
+ } else
+ return FindContainerByName(szName);
+}
+/*
+ * load some global icons.
+ */
+
+void TSAPI CreateImageList(BOOL bInitial)
+{
+ HICON hIcon;
+ int cxIcon = GetSystemMetrics(SM_CXSMICON);
+ int cyIcon = GetSystemMetrics(SM_CYSMICON);
+
+ /*
+ * the imagelist is now a fake. It is still needed to provide the tab control with a
+ * image list handle. This will make sure that the tab control will reserve space for
+ * an icon on each tab. This is a blank and empty icon
+ */
+
+ if (bInitial) {
+ PluginConfig.g_hImageList = ImageList_Create(16, 16, PluginConfig.m_bIsXP ? ILC_COLOR32 | ILC_MASK : ILC_COLOR8 | ILC_MASK, 2, 0);
+ hIcon = CreateIcon(g_hInst, 16, 16, 1, 4, NULL, NULL);
+ ImageList_AddIcon(PluginConfig.g_hImageList, hIcon);
+ DestroyIcon(hIcon);
+ }
+
+ PluginConfig.g_IconFileEvent = LoadSkinnedIcon(SKINICON_EVENT_FILE);
+ PluginConfig.g_IconMsgEvent = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ PluginConfig.g_IconMsgEventBig = LoadSkinnedIconBig(SKINICON_EVENT_MESSAGE);
+ if((HICON)CALLSERVICE_NOTFOUND == PluginConfig.g_IconMsgEventBig)
+ PluginConfig.g_IconMsgEventBig = 0;
+ PluginConfig.g_IconTypingEventBig = LoadSkinnedIconBig(SKINICON_OTHER_TYPING);
+ if((HICON)CALLSERVICE_NOTFOUND == PluginConfig.g_IconTypingEventBig)
+ PluginConfig.g_IconTypingEventBig = 0;
+ PluginConfig.g_IconSend = PluginConfig.g_buttonBarIcons[9];
+ PluginConfig.g_IconTypingEvent = PluginConfig.g_buttonBarIcons[5];
+}
+
+int TABSRMM_FireEvent(HANDLE hContact, HWND hwnd, unsigned int type, unsigned int subType)
+{
+ MessageWindowEventData mwe = { 0 };
+ struct TABSRMM_SessionInfo se = { 0 };
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ BYTE bType = dat ? dat->bType : SESSIONTYPE_IM;
+
+ if (hContact == NULL || hwnd == NULL)
+ return 0;
+
+ if (!M->GetByte("_eventapi", 1))
+ return 0;
+ mwe.cbSize = sizeof(mwe);
+ mwe.hContact = hContact;
+ mwe.hwndWindow = hwnd;
+ mwe.szModule = "tabSRMsgW";
+ mwe.uType = type;
+ mwe.hwndInput = GetDlgItem(hwnd, bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE);
+ mwe.hwndLog = GetDlgItem(hwnd, bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG);
+
+ if (type == MSG_WINDOW_EVT_CUSTOM) {
+ se.cbSize = sizeof(se);
+ se.evtCode = HIWORD(subType);
+ se.hwnd = hwnd;
+ se.extraFlags = (unsigned int)(LOWORD(subType));
+ se.local = (void *)dat->sendBuffer;
+ mwe.local = (void *) & se;
+ } else
+ mwe.local = NULL;
+ return(NotifyEventHooks(PluginConfig.m_event_MsgWin, 0, (LPARAM)&mwe));
+}
+
+/*
+ * standard icon definitions
+ */
+
+static TIconDesc _toolbaricons[] = {
+ "tabSRMM_mlog", LPGEN("Message Log Options"), &PluginConfig.g_buttonBarIcons[2], -IDI_MSGLOGOPT, 1,
+ "tabSRMM_multi", LPGEN("Image tag"), &PluginConfig.g_buttonBarIcons[3], -IDI_IMAGETAG, 1,
+ "tabSRMM_quote", LPGEN("Quote text"), &PluginConfig.g_buttonBarIcons[8], -IDI_QUOTE, 1,
+ "tabSRMM_save", LPGEN("Save and close"), &PluginConfig.g_buttonBarIcons[7], -IDI_SAVE, 1,
+ "tabSRMM_send", LPGEN("Send message"), &PluginConfig.g_buttonBarIcons[9], -IDI_SEND, 1,
+ "tabSRMM_avatar", LPGEN("Edit user notes"), &PluginConfig.g_buttonBarIcons[10], -IDI_CONTACTPIC, 1,
+ "tabSRMM_close", LPGEN("Close"), &PluginConfig.g_buttonBarIcons[6], -IDI_CLOSEMSGDLG, 1,
+ NULL, NULL, NULL, 0, 0
+};
+
+static TIconDesc _exttoolbaricons[] = {
+ "tabSRMM_emoticon", LPGEN("Smiley button"), &PluginConfig.g_buttonBarIcons[11], -IDI_SMILEYICON, 1,
+ "tabSRMM_bold", LPGEN("Format bold"), &PluginConfig.g_buttonBarIcons[17], -IDI_FONTBOLD, 1,
+ "tabSRMM_italic", LPGEN("Format italic"), &PluginConfig.g_buttonBarIcons[18], -IDI_FONTITALIC, 1,
+ "tabSRMM_underline", LPGEN("Format underline"), &PluginConfig.g_buttonBarIcons[19], -IDI_FONTUNDERLINE, 1,
+ "tabSRMM_face", LPGEN("Font face"), &PluginConfig.g_buttonBarIcons[20], -IDI_FONTFACE, 1,
+ "tabSRMM_color", LPGEN("Font color"), &PluginConfig.g_buttonBarIcons[21], -IDI_FONTCOLOR, 1,
+ "tabSRMM_strikeout", LPGEN("Format strike-through"), &PluginConfig.g_buttonBarIcons[30], -IDI_STRIKEOUT, 1,
+ NULL, NULL, NULL, 0, 0
+};
+//MAD
+static TIconDesc _chattoolbaricons[] = {
+ "chat_bkgcol",LPGEN("Background colour"), &PluginConfig.g_buttonBarIcons[31] ,-IDI_BKGCOLOR, 1,
+ "chat_settings",LPGEN("Room settings"), &PluginConfig.g_buttonBarIcons[32],-IDI_TOPICBUT, 1,
+ "chat_filter",LPGEN("Event filter"), &PluginConfig.g_buttonBarIcons[33] ,-IDI_FILTER2, 1,
+ "chat_shownicklist",LPGEN("Nick list"),&PluginConfig.g_buttonBarIcons[35] ,-IDI_SHOWNICKLIST, 1,
+ NULL, NULL, NULL, 0, 0
+ };
+//
+static TIconDesc _logicons[] = {
+ "tabSRMM_error", LPGEN("Message delivery error"), &PluginConfig.g_iconErr, -IDI_MSGERROR, 1,
+ "tabSRMM_in", LPGEN("Incoming message"), &PluginConfig.g_iconIn, -IDI_ICONIN, 0,
+ "tabSRMM_out", LPGEN("Outgoing message"), &PluginConfig.g_iconOut, -IDI_ICONOUT, 0,
+ "tabSRMM_status", LPGEN("Statuschange"), &PluginConfig.g_iconStatus, -IDI_STATUSCHANGE, 0,
+ NULL, NULL, NULL, 0, 0
+};
+static TIconDesc _deficons[] = {
+ "tabSRMM_container", LPGEN("Static container icon"), &PluginConfig.g_iconContainer, -IDI_CONTAINER, 1,
+ "tabSRMM_sounds_on", LPGEN("Sounds (status bar)"), &PluginConfig.g_buttonBarIcons[ICON_DEFAULT_SOUNDS], -IDI_SOUNDSON, 1,
+ "tabSRMM_pulldown", LPGEN("Pulldown Arrow"), &PluginConfig.g_buttonBarIcons[ICON_DEFAULT_PULLDOWN], -IDI_PULLDOWNARROW, 1,
+ "tabSRMM_Leftarrow", LPGEN("Left Arrow"), &PluginConfig.g_buttonBarIcons[ICON_DEFAULT_LEFT], -IDI_LEFTARROW, 1,
+ "tabSRMM_Rightarrow", LPGEN("Right Arrow"), &PluginConfig.g_buttonBarIcons[ICON_DEFAULT_RIGHT], -IDI_RIGHTARROW, 1,
+ "tabSRMM_Pulluparrow", LPGEN("Up Arrow"), &PluginConfig.g_buttonBarIcons[ICON_DEFAULT_UP], -IDI_PULLUPARROW, 1,
+ "tabSRMM_sb_slist", LPGEN("Session List"), &PluginConfig.g_sideBarIcons[0], -IDI_SESSIONLIST, 1,
+ NULL, NULL, NULL, 0, 0
+};
+static TIconDesc _trayIcon[] = {
+ "tabSRMM_frame1", LPGEN("Frame 1"), &PluginConfig.m_AnimTrayIcons[0], -IDI_TRAYANIM1, 1,
+ "tabSRMM_frame2", LPGEN("Frame 2"), &PluginConfig.m_AnimTrayIcons[1], -IDI_TRAYANIM2, 1,
+ "tabSRMM_frame3", LPGEN("Frame 3"), &PluginConfig.m_AnimTrayIcons[2], -IDI_TRAYANIM3, 1,
+ "tabSRMM_frame4", LPGEN("Frame 4"), &PluginConfig.m_AnimTrayIcons[3], -IDI_TRAYANIM4, 1,
+ NULL, NULL, NULL, 0, 0
+};
+
+static struct _iconblocks {
+ char *szSection;
+ TIconDesc *idesc;
+} ICONBLOCKS[] = {
+ "TabSRMM/Default", _deficons,
+ "TabSRMM/Toolbar", _toolbaricons,
+ "TabSRMM/Toolbar", _exttoolbaricons,
+ "TabSRMM/Toolbar", _chattoolbaricons,
+ "TabSRMM/Message Log", _logicons,
+ "TabSRMM/Animated Tray", _trayIcon,
+ NULL, 0
+};
+
+static int GetIconPackVersion(HMODULE hDLL)
+{
+ char szIDString[256];
+ int version = 0;
+
+ if (LoadStringA(hDLL, IDS_IDENTIFY, szIDString, sizeof(szIDString)) == 0)
+ version = 0;
+ else {
+ if (!strcmp(szIDString, "__tabSRMM_ICONPACK 1.0__"))
+ version = 1;
+ else if (!strcmp(szIDString, "__tabSRMM_ICONPACK 2.0__"))
+ version = 2;
+ else if (!strcmp(szIDString, "__tabSRMM_ICONPACK 3.0__"))
+ version = 3;
+ else if (!strcmp(szIDString, "__tabSRMM_ICONPACK 3.5__"))
+ version = 4;
+ else if (!strcmp(szIDString, "__tabSRMM_ICONPACK 5.0__"))
+ version = 5;
+ }
+
+ if (version < 5)
+ CWarning::show(CWarning::WARN_ICONPACK_VERSION, MB_OK|MB_ICONERROR);
+ return version;
+}
+/*
+ * setup default icons for the IcoLib service. This needs to be done every time the plugin is loaded
+ * default icons are taken from the icon pack in either \icons or \plugins
+ */
+
+static int TSAPI SetupIconLibConfig()
+{
+ SKINICONDESC sid = { 0 };
+ char szFilename[MAX_PATH];
+ int i = 0, j = 2, version = 0, n = 0;
+
+ strncpy(szFilename, "icons\\tabsrmm_icons.dll", MAX_PATH);
+ g_hIconDLL = LoadLibraryA(szFilename);
+ if (g_hIconDLL == 0) {
+ CWarning::show(CWarning::WARN_ICONPACKMISSING, CWarning::CWF_NOALLOWHIDE|MB_ICONERROR|MB_OK);
+ return 0;
+ }
+
+ GetModuleFileNameA(g_hIconDLL, szFilename, MAX_PATH);
+ if (PluginConfig.m_chat_enabled)
+ Chat_AddIcons();
+ version = GetIconPackVersion(g_hIconDLL);
+ FreeLibrary(g_hIconDLL);
+ g_hIconDLL = 0;
+
+ sid.cbSize = sizeof(SKINICONDESC);
+ sid.pszDefaultFile = szFilename;
+
+ while (ICONBLOCKS[n].szSection) {
+ i = 0;
+ sid.pszSection = ICONBLOCKS[n].szSection;
+ while (ICONBLOCKS[n].idesc[i].szDesc) {
+ sid.pszName = ICONBLOCKS[n].idesc[i].szName;
+ sid.pszDescription = ICONBLOCKS[n].idesc[i].szDesc;
+ sid.iDefaultIndex = ICONBLOCKS[n].idesc[i].uId == -IDI_HISTORY ? 0 : ICONBLOCKS[n].idesc[i].uId; // workaround problem /w icoLib and a resource id of 1 (actually, a Windows problem)
+ i++;
+ if(n>0&&n<4)
+ PluginConfig.g_buttonBarIconHandles[j++]=(HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+ else
+ CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+ }
+ n++;
+ }
+
+ sid.pszSection = "TabSRMM/Default";
+
+ sid.pszName = "tabSRMM_clock_symbol";
+ sid.pszDescription = "Clock symbol (for the info panel clock)";
+ sid.iDefaultIndex = -IDI_CLOCK;
+ CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ strncpy(szFilename, "plugins\\tabsrmm.dll", MAX_PATH);
+
+ sid.pszName = "tabSRMM_overlay_disabled";
+ sid.pszDescription = "Feature disabled (used as overlay)";
+ sid.iDefaultIndex = -IDI_FEATURE_DISABLED;
+ CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ sid.pszName = "tabSRMM_overlay_enabled";
+ sid.pszDescription = "Feature enabled (used as overlay)";
+ sid.iDefaultIndex = -IDI_FEATURE_ENABLED;
+ CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+
+ return 1;
+}
+
+// load the icon theme from IconLib - check if it exists...
+
+static int TSAPI LoadFromIconLib()
+{
+ int i = 0, n = 0;
+
+ while (ICONBLOCKS[n].szSection) {
+ i = 0;
+ while (ICONBLOCKS[n].idesc[i].szDesc) {
+ *(ICONBLOCKS[n].idesc[i].phIcon) = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)ICONBLOCKS[n].idesc[i].szName);
+ i++;
+ }
+ n++;
+ }
+ PluginConfig.g_buttonBarIcons[0] = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"core_main_8");
+ PluginConfig.g_buttonBarIcons[1] = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"core_main_10");
+ PluginConfig.g_buttonBarIconHandles[0] = (HICON)CallService(MS_SKIN2_GETICONHANDLE, 0, (LPARAM)"core_main_10");
+ PluginConfig.g_buttonBarIconHandles[1] = (HICON)CallService(MS_SKIN2_GETICONHANDLE, 0, (LPARAM)"core_main_8");
+ PluginConfig.g_buttonBarIconHandles[20] = (HICON)CallService(MS_SKIN2_GETICONHANDLE, 0, (LPARAM)"core_main_9");
+
+ PluginConfig.g_buttonBarIcons[5] = PluginConfig.g_buttonBarIcons[12] = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"core_main_23");
+ PluginConfig.g_IconChecked = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"core_main_19");
+ PluginConfig.g_IconUnchecked = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"core_main_20");
+ PluginConfig.g_IconFolder = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"core_main_5");
+
+ PluginConfig.g_iconOverlayEnabled = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"tabSRMM_overlay_enabled");
+ PluginConfig.g_iconOverlayDisabled = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"tabSRMM_overlay_disabled");
+
+ PluginConfig.g_iconClock = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"tabSRMM_clock_symbol");
+
+ CacheMsgLogIcons();
+ M->BroadcastMessage(DM_LOADBUTTONBARICONS, 0, 0);
+ return 0;
+}
+
+/*
+ * load icon theme from either icon pack or IcoLib
+ */
+
+void TSAPI LoadIconTheme()
+{
+ if (SetupIconLibConfig() == 0)
+ return;
+ else
+ LoadFromIconLib();
+
+ Skin->setupTabCloseBitmap();
+ return;
+}
+
+static void UnloadIcons()
+{
+ int i = 0, n = 0;
+
+ while (ICONBLOCKS[n].szSection) {
+ i = 0;
+ while (ICONBLOCKS[n].idesc[i].szDesc) {
+ if (*(ICONBLOCKS[n].idesc[i].phIcon) != 0) {
+ DestroyIcon(*(ICONBLOCKS[n].idesc[i].phIcon));
+ *(ICONBLOCKS[n].idesc[i].phIcon) = 0;
+ }
+ i++;
+ }
+ n++;
+ }
+ if (PluginConfig.g_hbmUnknown)
+ DeleteObject(PluginConfig.g_hbmUnknown);
+ for (i = 0; i < 4; i++) {
+ if (PluginConfig.m_AnimTrayIcons[i])
+ DestroyIcon(PluginConfig.m_AnimTrayIcons[i]);
+ }
+}
diff --git a/plugins/TabSRMM/src/selectcontainer.cpp b/plugins/TabSRMM/src/selectcontainer.cpp
new file mode 100644
index 0000000000..975f7496a4
--- /dev/null
+++ b/plugins/TabSRMM/src/selectcontainer.cpp
@@ -0,0 +1,226 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: selectcontainer.cpp 12351 2010-08-21 21:44:54Z Michael.Kunz@s2005.TU-Chemnitz.de $
+ *
+ * dialog to manage containers (attaching sessions to containers etc.)
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+INT_PTR CALLBACK SelectContainerDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndMsgDlg = 0;
+
+ hwndMsgDlg = (HWND) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg) {
+ case WM_INITDIALOG: {
+ TCHAR szNewTitle[128];
+ RECT rc, rcParent;
+ struct TContainerData *pContainer = 0;
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) lParam);
+ hwndMsgDlg = (HWND) lParam;
+
+ TranslateDialogDefault(hwndDlg);
+
+ if (lParam) {
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr((HWND)lParam, GWLP_USERDATA);
+ if (dat) {
+ mir_sntprintf(szNewTitle, safe_sizeof(szNewTitle), CTranslator::get(CTranslator::CNT_SELECT_FOR), dat->cache->getNick());
+ SetWindowText(hwndDlg, szNewTitle);
+ }
+ }
+
+ SendMessage(hwndDlg, DM_SC_BUILDLIST, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_NEWCONTAINERNAME, EM_LIMITTEXT, (WPARAM)CONTAINER_NAMELEN, 0);
+ SendDlgItemMessage(hwndDlg, IDC_NEWCONTAINER, EM_LIMITTEXT, (WPARAM)CONTAINER_NAMELEN, 0);
+
+ GetWindowRect(hwndDlg, &rc);
+ GetWindowRect(GetParent(hwndDlg), &rcParent);
+ SetWindowPos(hwndDlg, 0, (rcParent.left + rcParent.right - (rc.right - rc.left)) / 2, (rcParent.top + rcParent.bottom - (rc.bottom - rc.top)) / 2, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK: {
+ TCHAR szName[CONTAINER_NAMELEN];
+ LRESULT iItem;
+
+ if ((iItem = SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_GETCURSEL, 0, 0)) != LB_ERR) {
+ SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_GETTEXT, (WPARAM) iItem, (LPARAM) szName);
+ if (IsWindow(hwndMsgDlg))
+ SendMessage(hwndMsgDlg, DM_CONTAINERSELECTED, 0, (LPARAM) szName);
+ }
+ if (IsWindow(hwndDlg))
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ case IDC_DELETECONTAINER: {
+ TCHAR szName[CONTAINER_NAMELEN + 1];
+ LRESULT iItem;
+
+ if ((iItem = SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_GETCURSEL, 0, 0)) != LB_ERR) {
+ SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_GETTEXT, (WPARAM) iItem, (LPARAM) szName);
+ if (!_tcsncmp(szName, _T("default"), CONTAINER_NAMELEN) || !_tcsncmp(szName, CTranslator::get(CTranslator::GEN_DEFAULT_CONTAINER_NAME), CONTAINER_NAMELEN))
+ MessageBox(hwndDlg, CTranslator::get(CTranslator::CNT_SELECT_DELETEERROR), _T("Error"), MB_OK | MB_ICONERROR);
+ else {
+ int iIndex = SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_GETITEMDATA, (WPARAM)iItem, 0);
+ DeleteContainer(iIndex);
+ SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_RESETCONTENT, 0, 0);
+ SendMessage(hwndDlg, DM_SC_BUILDLIST, 0, 0);
+ BuildContainerMenu();
+ }
+ }
+ break;
+ }
+ case IDC_RENAMECONTAINER: {
+ TCHAR szNewName[CONTAINER_NAMELEN], szName[CONTAINER_NAMELEN + 1];
+ int iLen, iItem;
+ struct TContainerData *pCurrent = pFirstContainer;
+
+ iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_NEWCONTAINERNAME));
+ if (iLen) {
+ GetWindowText(GetDlgItem(hwndDlg, IDC_NEWCONTAINERNAME), szNewName, CONTAINER_NAMELEN);
+ if(!_tcsncmp(szNewName, CGlobals::m_default_container_name, CONTAINER_NAMELEN) || !_tcsncmp(szNewName, CTranslator::get(CTranslator::GEN_DEFAULT_CONTAINER_NAME), CONTAINER_NAMELEN)) {
+ MessageBox(hwndDlg, CTranslator::get(CTranslator::CNT_SELECT_RENAMEERROR), _T("Error"), MB_OK | MB_ICONERROR);
+ break;
+ }
+
+ iItem = SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_FINDSTRING, (WPARAM) - 1, (LPARAM) szNewName);
+ if (iItem != LB_ERR) {
+ TCHAR szOldName[CONTAINER_NAMELEN + 1];
+ SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_GETTEXT, (WPARAM) iItem, (LPARAM) szOldName);
+ if (lstrlen(szOldName) == lstrlen(szNewName)) {
+ MessageBox(0, CTranslator::get(CTranslator::CNT_SELECT_INUSE), _T("Error"), MB_OK | MB_ICONERROR);
+ SetFocus(GetDlgItem(hwndDlg, IDC_NEWCONTAINERNAME));
+ break;
+ }
+ }
+ if ((iItem = SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_GETCURSEL, 0, 0)) != LB_ERR) {
+ SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_GETTEXT, (WPARAM) iItem, (LPARAM) szName);
+ if (!_tcsncmp(szName, _T("default"), CONTAINER_NAMELEN) || !_tcsncmp(szName, CTranslator::get(CTranslator::GEN_DEFAULT_CONTAINER_NAME), CONTAINER_NAMELEN))
+ MessageBox(hwndDlg, CTranslator::get(CTranslator::CNT_SELECT_RENAMEERROR), _T("Error"), MB_OK | MB_ICONERROR);
+ else {
+ int iIndex = SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_GETITEMDATA, (WPARAM)iItem, 0);
+ RenameContainer(iIndex, szNewName);
+ SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_RESETCONTENT, 0, 0);
+ while (pCurrent) {
+ if (!_tcsncmp(pCurrent->szName, szName, CONTAINER_NAMELEN) && lstrlen(pCurrent->szName) == lstrlen(szName)) {
+ _tcsncpy(pCurrent->szName, szNewName, CONTAINER_NAMELEN);
+ SendMessage(pCurrent->hwnd, DM_CONFIGURECONTAINER, 0, 0);
+ }
+ pCurrent = pCurrent->pNextContainer;
+ }
+ SendMessage(hwndDlg, DM_SC_BUILDLIST, 0, 0);
+ BuildContainerMenu();
+ }
+ }
+ }
+ break;
+ }
+ case IDC_CREATENEW: {
+ int iLen, iItem;
+ TCHAR szNewName[CONTAINER_NAMELEN], szName[CONTAINER_NAMELEN + 1];
+
+ iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_NEWCONTAINER));
+ if (iLen) {
+ GetWindowText(GetDlgItem(hwndDlg, IDC_NEWCONTAINER), szNewName, CONTAINER_NAMELEN);
+ iItem = SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_FINDSTRING, (WPARAM) - 1, (LPARAM) szNewName);
+ if (iItem != LB_ERR || !_tcsncmp(szNewName, CGlobals::m_default_container_name, CONTAINER_NAMELEN)) {
+ SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_GETTEXT, (WPARAM)iItem, (LPARAM)szName);
+ if (lstrlen(szName) == lstrlen(szNewName) || !_tcsncmp(szNewName, CGlobals::m_default_container_name, CONTAINER_NAMELEN)) {
+ MessageBox(0, CTranslator::get(CTranslator::CNT_SELECT_INUSE), _T("Error"), MB_OK | MB_ICONERROR);
+ SetFocus(GetDlgItem(hwndDlg, IDC_NEWCONTAINER));
+ break;
+ }
+ }
+ if (IsWindow(hwndMsgDlg)) {
+ SendMessage(hwndMsgDlg, DM_CONTAINERSELECTED, 0, (LPARAM) szNewName);
+ if (IsWindow(hwndDlg))
+ DestroyWindow(hwndDlg);
+ }
+ }
+ break;
+ }
+ case IDC_CNTLIST:
+ if (HIWORD(wParam) == LBN_DBLCLK)
+ SendMessage(hwndDlg, WM_COMMAND, IDOK, 0);
+ break;
+ }
+ break;
+ /*
+ * fill the list box...
+ */
+ case DM_SC_BUILDLIST: {
+ DBVARIANT dbv;
+ int iCounter = 0, iItemNew;
+ char *szKey = "TAB_ContainersW";
+ char szValue[10];
+ struct TContainerData *pContainer = 0;
+ do {
+ _snprintf(szValue, 8, "%d", iCounter);
+ if (M->GetTString(NULL, szKey, szValue, &dbv))
+ break; // end of list
+ if (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR) {
+ if (_tcsncmp(dbv.ptszVal, _T("**free**"), CONTAINER_NAMELEN)) {
+ iItemNew = SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_ADDSTRING, 0, (LPARAM)(!_tcscmp(dbv.ptszVal, _T("default")) ?
+ CTranslator::get(CTranslator::GEN_DEFAULT_CONTAINER_NAME) : dbv.ptszVal));
+ if (iItemNew != LB_ERR)
+ SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_SETITEMDATA, (WPARAM)iItemNew, (LPARAM)iCounter);
+ }
+ DBFreeVariant(&dbv);
+ }
+ } while (++iCounter);
+
+ /*
+ * highlight the name of the container to which the message window currently is assigned
+ */
+
+ SendMessage(hwndMsgDlg, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
+ if (pContainer) {
+ LRESULT iItem;
+
+ iItem = SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_FINDSTRING, (WPARAM) - 1, (LPARAM)(!_tcscmp(pContainer->szName, _T("default")) ?
+ CTranslator::get(CTranslator::GEN_DEFAULT_CONTAINER_NAME) : pContainer->szName));
+ if (iItem != LB_ERR)
+ SendDlgItemMessage(hwndDlg, IDC_CNTLIST, LB_SETCURSEL, (WPARAM) iItem, 0);
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
diff --git a/plugins/TabSRMM/src/sendlater.cpp b/plugins/TabSRMM/src/sendlater.cpp
new file mode 100644
index 0000000000..2cbf0b7237
--- /dev/null
+++ b/plugins/TabSRMM/src/sendlater.cpp
@@ -0,0 +1,989 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: sendlater.cpp 14225 2012-05-08 19:49:18Z george.hazan $
+ *
+ * the sendlater class implementation
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+#define U_PREF_UNICODE PREF_UNICODE
+/*
+ * implementation of the CSendLaterJob class
+ */
+
+CSendLaterJob::CSendLaterJob()
+{
+ ZeroMemory(this, sizeof(CSendLaterJob));
+ fSuccess = false;
+}
+
+/**
+ * return true if this job is persistent (saved to the database).
+ * such a job will survive a restart of Miranda
+ */
+bool CSendLaterJob::isPersistentJob()
+{
+ return(szId[0] == 'S' ? true : false);
+}
+
+/**
+ * check conditions for deletion
+ */
+bool CSendLaterJob::mustDelete()
+{
+ if(fSuccess)
+ return(true);
+ else if(fFailed) {
+ if(bCode == JOB_REMOVABLE)
+ return(true);
+ }
+ return(false);
+}
+
+/**
+ * clean database entries for a persistent job (currently: manual send later jobs)
+ */
+void CSendLaterJob::cleanDB()
+{
+ if(isPersistentJob()) {
+ char szKey[100];
+
+ DBDeleteContactSetting(hContact, "SendLater", szId);
+ int iCount = M->GetDword(hContact, "SendLater", "count", 0);
+ if(iCount)
+ iCount--;
+ M->WriteDword(hContact, "SendLater", "count", iCount);
+ /*
+ * delete flags
+ */
+ mir_snprintf(szKey, 100, "$%s", szId);
+ DBDeleteContactSetting(hContact, "SendLater", szKey);
+ }
+}
+
+/**
+ * read flags for a persistent jobs from the db
+ * flag key name is the job id with a "$" prefix.
+ */
+void CSendLaterJob::readFlags()
+{
+ if(isPersistentJob()) {
+ char szKey[100];
+ DWORD localFlags;
+
+ mir_snprintf(szKey, 100, "$%s", szId);
+ localFlags = M->GetDword(hContact, "SendLater", szKey, 0);
+
+ if(localFlags & SLF_SUSPEND)
+ bCode = JOB_HOLD;
+ }
+}
+
+/**
+ * write flags for a persistent jobs from the db
+ * flag key name is the job id with a "$" prefix.
+ */
+void CSendLaterJob::writeFlags()
+{
+ if(isPersistentJob()) {
+ DWORD localFlags = (bCode == JOB_HOLD ? SLF_SUSPEND : 0);
+ char szKey[100];
+
+ mir_snprintf(szKey, 100, "$%s", szId);
+ M->WriteDword(hContact, "SendLater", szKey, localFlags);
+ }
+}
+
+/**
+ * delete a send later job
+ */
+CSendLaterJob::~CSendLaterJob()
+{
+ if(fSuccess || fFailed) {
+ POPUPDATAT_V2 ppd = {0};
+
+ if((sendLater->haveErrorPopups() && fFailed) || (sendLater->haveSuccessPopups() && fSuccess)) {
+ bool fShowPopup = true;
+
+ if(fFailed && bCode == JOB_REMOVABLE) // no popups for jobs removed on user's request
+ fShowPopup = false;
+ /*
+ * show a popup notification, unless they are disabled
+ */
+ if (PluginConfig.g_PopupAvail && fShowPopup) {
+ TCHAR *tszName = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR);
+
+ ZeroMemory((void *)&ppd, sizeof(ppd));
+ ppd.lchContact = hContact;
+ ppd.cbSize = sizeof(ppd);
+ mir_sntprintf(ppd.lptzContactName, MAX_CONTACTNAME, _T("%s"), tszName ? tszName : CTranslator::get(CTranslator::GEN_UNKNOWN_CONTACT));
+ TCHAR *msgPreview = Utils::GetPreviewWithEllipsis(reinterpret_cast<TCHAR *>(&pBuf[lstrlenA((char *)pBuf) + 1]), 100);
+ if(fSuccess) {
+ mir_sntprintf(ppd.lptzText, MAX_SECONDLINE, CTranslator::get(CTranslator::GEN_SQ_SENDLATER_SUCCESS_POPUP),
+ msgPreview);
+ mir_free(msgPreview);
+ }
+ else if(fFailed) {
+ mir_sntprintf(ppd.lptzText, MAX_SECONDLINE, CTranslator::get(CTranslator::GEN_SQ_SENDLATER_FAILED_POPUP),
+ msgPreview);
+ mir_free(msgPreview);
+ }
+ /*
+ * use message settings (timeout/colors) for success popups
+ */
+ ppd.colorText = fFailed ? RGB(255, 245, 225) : nen_options.colTextMsg;
+ ppd.colorBack = fFailed ? RGB(191, 0, 0) : nen_options.colBackMsg;
+ ppd.PluginWindowProc = reinterpret_cast<WNDPROC>(Utils::PopupDlgProcError);
+ ppd.lchIcon = fFailed ? PluginConfig.g_iconErr : PluginConfig.g_IconMsgEvent;
+ ppd.PluginData = (void *)hContact;
+ ppd.iSeconds = fFailed ? -1 : nen_options.iDelayMsg;
+ CallService(MS_POPUP_ADDPOPUPW, (WPARAM)&ppd, 0);
+ }
+ }
+ if(fFailed && (bCode == JOB_AGE || bCode == JOB_REMOVABLE) && szId[0] == 'S')
+ cleanDB();
+ mir_free(sendBuffer);
+ mir_free(pBuf);
+ }
+}
+
+CSendLater::CSendLater()
+{
+ m_sendLaterContactList.clear();
+ m_sendLaterJobList.clear();
+ m_fAvail = M->GetByte("sendLaterAvail", 0) ? true : false;
+ m_last_sendlater_processed = time(0);
+ m_hwndDlg = 0;
+ m_fIsInteractive = false;
+ m_fErrorPopups = M->GetByte(0, SRMSGMOD_T, "qmgrErrorPopups", 0) ? true : false;
+ m_fSuccessPopups = M->GetByte(0, SRMSGMOD_T, "qmgrSuccessPopups", 0) ? true : false;
+}
+
+/**
+ * clear all open send jobs. Only called on system shutdown to remove
+ * the jobs from memory. Must _NOT_ delete any sendlater related stuff from
+ * the database (only successful sends may do this).
+ */
+CSendLater::~CSendLater()
+{
+ if(m_hwndDlg)
+ ::DestroyWindow(m_hwndDlg);
+
+ if(m_sendLaterJobList.empty())
+ return;
+
+ SendLaterJobIterator it = m_sendLaterJobList.begin();
+
+ while(it != m_sendLaterJobList.end()) {
+ mir_free((*it)->sendBuffer);
+ mir_free((*it)->pBuf);
+ (*it)->fSuccess = false; // avoid clearing jobs from the database
+ delete *it;
+ it++;
+ }
+}
+
+void CSendLater::startJobListProcess()
+{
+ m_jobIterator = m_sendLaterJobList.begin();
+
+ if (m_hwndDlg)
+ Utils::enableDlgControl(m_hwndDlg, IDC_QMGR_LIST, false);
+}
+
+/**
+ * checks if the current job in the timer-based process queue is subject
+ * for deletion (that is, it has failed or succeeded)
+ *
+ * if not, it will send the job and increment the list iterator.
+ *
+ * this method is called once per tick from the timer based scheduler in
+ * hotkeyhandler.cpp.
+ *
+ * returns true if more jobs are awaiting processing, false otherwise.
+ */
+bool CSendLater::processCurrentJob()
+{
+ if(m_sendLaterJobList.empty() || m_jobIterator == m_sendLaterJobList.end())
+ return(false);
+
+ if((*m_jobIterator)->fSuccess || (*m_jobIterator)->fFailed) {
+ if((*m_jobIterator)->mustDelete()) {
+ delete *m_jobIterator;
+ m_jobIterator = m_sendLaterJobList.erase(m_jobIterator);
+ }
+ else
+ m_jobIterator++;
+ return(m_jobIterator == m_sendLaterJobList.end() ? false : true);
+ }
+ sendIt(*m_jobIterator);
+ m_jobIterator++;
+ return(m_jobIterator == m_sendLaterJobList.end() ? false : true);
+}
+
+/**
+ * stub used as enum proc for the database enumeration, collecting
+ * all entries in the SendLater module
+ * (static function)
+ */
+int _cdecl CSendLater::addStub(const char *szSetting, LPARAM lParam)
+{
+ return(sendLater->addJob(szSetting, lParam));
+}
+
+/**
+ * Process a single contact from the list of contacts with open send later jobs
+ * enum the "SendLater" module and add all jobs to the list of open jobs.
+ * addJob() will deal with possible duplicates
+ * @param hContact HANDLE: contact's handle
+ */
+void CSendLater::processSingleContact(const HANDLE hContact)
+{
+ int iCount = M->GetDword(hContact, "SendLater", "count", 0);
+
+ if(iCount) {
+ DBCONTACTENUMSETTINGS ces = {0};
+
+ ces.pfnEnumProc = CSendLater::addStub;
+ ces.szModule = "SendLater";
+ ces.lParam = (LPARAM)hContact;
+
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)hContact, (LPARAM)&ces);
+ }
+}
+
+/**
+ * called periodically from a timer, check if new contacts were added
+ * and process them
+ */
+void CSendLater::processContacts()
+{
+ if(m_fAvail && !m_sendLaterContactList.empty()) {
+ std::vector<HANDLE>::iterator it = m_sendLaterContactList.begin();
+ while(it != m_sendLaterContactList.end()) {
+ processSingleContact(*it);
+ it++;
+ }
+ m_sendLaterContactList.clear();
+ }
+}
+
+/**
+ * This function adds a new job to the list of messages to send unattended
+ * used by the send later feature and multisend
+ *
+ * @param szSetting is either the name of the database key for a send later
+ * job OR the utf-8 encoded message for a multisend job prefixed with
+ * a 'M+timestamp'. Send later job ids start with "S".
+ *
+ * @param lParam: a contact handle for which the job should be scheduled
+ * @return 0 on failure, 1 otherwise
+ */
+int CSendLater::addJob(const char *szSetting, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)lParam;
+ DBVARIANT dbv = {0};
+ char *szOrig_Utf = 0;
+
+ if(!m_fAvail || !szSetting || !strcmp(szSetting, "count") || lstrlenA(szSetting) < 8)
+ return(0);
+
+ if(szSetting[0] != 'S' && szSetting[0] != 'M')
+ return(0);
+
+ SendLaterJobIterator it = m_sendLaterJobList.begin();
+
+ /*
+ * check for possible dupes
+ */
+ while(it != m_sendLaterJobList.end()) {
+ if((*it)->hContact == hContact && !strcmp((*it)->szId, szSetting)) {
+ return(0);
+ }
+ it++;
+ }
+
+ if(szSetting[0] == 'S') {
+ if(0 == DBGetContactSettingString(hContact, "SendLater", szSetting, &dbv))
+ szOrig_Utf = dbv.pszVal;
+ else
+ return(0);
+ }
+ else if(szSetting[0] == 'M') {
+ char *szSep = strchr(const_cast<char *>(szSetting), '|');
+ if(!szSep)
+ return(0);
+ *szSep = 0;
+ szOrig_Utf = szSep + 1;
+ }
+ else
+ return(0);
+
+ CSendLaterJob *job = new CSendLaterJob;
+
+ strncpy(job->szId, szSetting, 20);
+ job->szId[19] = 0;
+ job->hContact = hContact;
+ job->created = atol(&szSetting[1]);
+
+ char *szAnsi = 0;
+ wchar_t *szWchar = 0;
+ UINT required = 0;
+
+ int iLen = lstrlenA(szOrig_Utf);
+ job->sendBuffer = reinterpret_cast<char *>(mir_alloc(iLen + 1));
+ strncpy(job->sendBuffer, szOrig_Utf, iLen);
+ job->sendBuffer[iLen] = 0;
+
+ /*
+ * construct conventional send buffer
+ */
+
+ szAnsi = M->utf8_decodecp(szOrig_Utf, CP_ACP, &szWchar);
+ iLen = lstrlenA(szAnsi);
+ if(szWchar)
+ required = iLen + 1 + ((lstrlenW(szWchar) + 1) * sizeof(wchar_t));
+ else
+ required = iLen + 1;
+
+ job->pBuf = (PBYTE)mir_calloc(required);
+
+ strncpy((char *)job->pBuf, szAnsi, iLen);
+ job->pBuf[iLen] = 0;
+ if(szWchar)
+ wcsncpy((wchar_t *)&job->pBuf[iLen + 1], szWchar, lstrlenW(szWchar));
+
+ if(szSetting[0] == 'S')
+ DBFreeVariant(&dbv);
+
+ mir_free(szWchar);
+ job->readFlags();
+ m_sendLaterJobList.push_back(job);
+ qMgrUpdate();
+ return(1);
+}
+
+/**
+ * Try to send an open job from the job list
+ * this is ONLY called from the WM_TIMER handler and should never be executed
+ * directly.
+ */
+int CSendLater::sendIt(CSendLaterJob *job)
+{
+ HANDLE hContact = job->hContact;
+ time_t now = time(0);
+ DWORD dwFlags = 0;
+ DBVARIANT dbv = {0};
+ const char* szProto = 0;
+
+
+ if(job->bCode == CSendLaterJob::JOB_HOLD || job->bCode == CSendLaterJob::JOB_DEFERRED || job->fSuccess || job->fFailed || job->lastSent > now)
+ return(0); // this one is frozen or done (will be removed soon), don't process it now.
+
+ if(now - job->created > SENDLATER_AGE_THRESHOLD) { // too old, this will be discarded and user informed by popup
+ job->fFailed = true;
+ job->bCode = CSendLaterJob::JOB_AGE;
+ return(0);
+ }
+
+ /*
+ * mark job as deferred (5 unsuccessful sends). Job will not be removed, but
+ * the user must manually reset it in order to trigger a new send attempt.
+ */
+ if(job->iSendCount == 5) {
+ job->bCode = CSendLaterJob::JOB_DEFERRED;
+ return(0);
+ }
+
+ if(job->iSendCount > 0 && (now - job->lastSent < SENDLATER_RESEND_THRESHOLD)) {
+ //_DebugTraceA("Send it: message %s for %s RESEND but not old enough", job->szId, (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0));
+ return(0); // this one was sent, but probably failed. Resend it after a while
+ }
+
+ CContactCache *c = CContactCache::getContactCache(hContact);
+ if(!c)
+ return(0); // should not happen
+
+ if(!c->isValid()) {
+ job->fFailed = true;
+ job->bCode = CSendLaterJob::INVALID_CONTACT;
+ return(0); // can happen (contact has been deleted). mark the job as failed
+ }
+
+ hContact = c->getActiveContact();
+ szProto = c->getActiveProto();
+
+ if(!hContact || szProto == 0)
+ return(0);
+
+ WORD wMyStatus = (WORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ WORD wContactStatus = c->getActiveStatus();
+
+ /*
+ * status mode checks
+ */
+ if(wMyStatus == ID_STATUS_OFFLINE) {
+ job->bCode = CSendLaterJob::JOB_MYSTATUS;
+ return(0);
+ }
+ if(job->szId[0] == 'S') {
+ if(!(wMyStatus == ID_STATUS_ONLINE || wMyStatus == ID_STATUS_FREECHAT)) {
+ job->bCode = CSendLaterJob::JOB_MYSTATUS;
+ return(0);
+ }
+ }
+ if(wContactStatus == ID_STATUS_OFFLINE) {
+ job->bCode = CSendLaterJob::JOB_STATUS;
+ return(0);
+ }
+
+ dwFlags = IsUtfSendAvailable(hContact) ? PREF_UTF : U_PREF_UNICODE;
+
+ char *svcName = SendQueue::MsgServiceName(hContact, 0, dwFlags);
+
+ job->lastSent = now;
+ job->iSendCount++;
+ job->hTargetContact = hContact;
+ job->bCode = CSendLaterJob::JOB_WAITACK;
+
+ if(dwFlags & PREF_UTF)
+ job->hProcess = (HANDLE)CallContactService(hContact, svcName, dwFlags, (LPARAM)job->sendBuffer);
+ else
+ job->hProcess = (HANDLE)CallContactService(hContact, svcName, dwFlags, (LPARAM)job->pBuf);
+ return(0);
+}
+
+/*
+ * add a contact to the list of contacts having open send later jobs.
+ * This ist is periodically checked for new additions (processContacts())
+ * and new jobs are created.
+ */
+
+void CSendLater::addContact(const HANDLE hContact)
+{
+ if(!m_fAvail)
+ return;
+
+ std::vector<HANDLE>::iterator it = m_sendLaterContactList.begin();
+
+ if(m_sendLaterContactList.empty()) {
+ m_sendLaterContactList.push_back(hContact);
+ m_last_sendlater_processed = 0; // force processing at next tick
+ return;
+ }
+
+ /*
+ * this list should not have duplicate entries
+ */
+
+ while(it != m_sendLaterContactList.end()) {
+ if(*it == hContact)
+ return;
+ it++;
+ }
+ m_sendLaterContactList.push_back(hContact);
+ m_last_sendlater_processed = 0; // force processing at next tick
+}
+
+/**
+ * process ACK messages for the send later job list. Called from the proto ack
+ * handler when it does not find a match in the normal send queue
+ *
+ * Add the message to the database and mark it as successful. The job will be
+ * removed later by the job list processing code.
+ */
+HANDLE CSendLater::processAck(const ACKDATA *ack)
+{
+ if(m_sendLaterJobList.empty() || !m_fAvail)
+ return(0);
+
+ SendLaterJobIterator it = m_sendLaterJobList.begin();
+
+ while(it != m_sendLaterJobList.end()) {
+ if((*it)->hProcess == ack->hProcess && (*it)->hTargetContact == ack->hContact && !((*it)->fSuccess || (*it)->fFailed)) {
+ DBEVENTINFO dbei = {0};
+
+ if(!(*it)->fSuccess) {
+ dbei.cbSize = sizeof(dbei);
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.flags = DBEF_SENT;
+ dbei.szModule = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)((*it)->hContact), 0);
+ dbei.timestamp = time(NULL);
+ dbei.cbBlob = lstrlenA((*it)->sendBuffer) + 1;
+ dbei.flags |= DBEF_UTF;
+ dbei.pBlob = (PBYTE)((*it)->sendBuffer);
+ HANDLE hNewEvent = (HANDLE) CallService(MS_DB_EVENT_ADD, (WPARAM)((*it)->hContact), (LPARAM)&dbei);
+
+ (*it)->cleanDB();
+ }
+ (*it)->fSuccess = true; // mark as successful, job list processing code will remove it later
+ (*it)->hProcess = (HANDLE)-1;
+ (*it)->bCode = '-';
+ qMgrUpdate();
+ return(0);
+ }
+ it++;
+ }
+ return(0);
+}
+
+/*
+ * UI stuff (dialog procedures for the queue manager dialog
+ */
+
+void CSendLater::qMgrUpdate(bool fReEnable)
+{
+ if(m_hwndDlg) {
+ if(fReEnable)
+ Utils::enableDlgControl(m_hwndDlg, IDC_QMGR_LIST, true);
+ ::SendMessage(m_hwndDlg, WM_USER + 100, 0, 0); // if qmgr is open, tell it to update
+ }
+}
+
+LRESULT CSendLater::qMgrAddFilter(const HANDLE hContact, const TCHAR* tszNick)
+{
+ LRESULT lr;
+
+ lr = ::SendMessage(m_hwndFilter, CB_FINDSTRING, 0, reinterpret_cast<LPARAM>(tszNick));
+ if(lr == CB_ERR) {
+ lr = ::SendMessage(m_hwndFilter, CB_INSERTSTRING, -1, reinterpret_cast<LPARAM>(tszNick));
+ ::SendMessage(m_hwndFilter, CB_SETITEMDATA, lr, reinterpret_cast<LPARAM>(hContact));
+ if(hContact == m_hFilter)
+ m_sel = lr;
+ }
+ return(m_sel);
+}
+
+/**
+ * fills the list of jobs with current contents of the job queue
+ * filters by m_hFilter (contact handle)
+ *
+ */
+void CSendLater::qMgrFillList(bool fClear)
+{
+ LVITEM lvItem = {0};
+ unsigned uIndex = 0;
+ CContactCache* c = 0;
+ TCHAR* formatTime = _T("%Y.%m.%d - %H:%M");
+ TCHAR tszTimestamp[30];
+ TCHAR tszStatus[20];
+ const TCHAR* tszStatusText = 0;
+ BYTE bCode = '-';
+
+ if(fClear) {
+ ::SendMessage(m_hwndList, LVM_DELETEALLITEMS, 0, 0);
+ ::SendMessage(m_hwndFilter, CB_RESETCONTENT, 0, 0);
+ }
+
+ m_sel = 0;
+ ::SendMessage(m_hwndFilter, CB_INSERTSTRING, -1,
+ reinterpret_cast<LPARAM>(CTranslator::get(CTranslator::QMGR_FILTER_ALLCONTACTS)));
+ ::SendMessage(m_hwndFilter, CB_SETITEMDATA, 0, 0);
+
+ lvItem.cchTextMax = 255;
+
+ SendLaterJobIterator it = m_sendLaterJobList.begin();
+
+ while(it != m_sendLaterJobList.end()) {
+
+ c = CContactCache::getContactCache((*it)->hContact);
+ if(c) {
+ const TCHAR* tszNick = c->getNick();
+ TCHAR tszBuf[255];
+
+ if(m_hFilter && m_hFilter != (*it)->hContact) {
+ qMgrAddFilter(c->getContact(), tszNick);
+ it++;
+ continue;
+ }
+ lvItem.mask = LVIF_TEXT|LVIF_PARAM;
+ mir_sntprintf(tszBuf, 255, _T("%s [%s]"), tszNick, c->getRealAccount());
+ lvItem.pszText = tszBuf;
+ lvItem.iItem = uIndex++;
+ lvItem.iSubItem = 0;
+ lvItem.lParam = reinterpret_cast<LPARAM>(*it);
+ ::SendMessage(m_hwndList, LVM_INSERTITEM, 0, reinterpret_cast<LPARAM>(&lvItem));
+ qMgrAddFilter(c->getContact(), tszNick);
+
+ lvItem.mask = LVIF_TEXT;
+ _tcsftime(tszTimestamp, 30, formatTime, _localtime32((__time32_t *)&(*it)->created));
+ tszTimestamp[29] = 0;
+ lvItem.pszText = tszTimestamp;
+ lvItem.iSubItem = 1;
+ ::SendMessage(m_hwndList, LVM_SETITEM, 0, reinterpret_cast<LPARAM>(&lvItem));
+
+ TCHAR* msg = M->utf8_decodeT((*it)->sendBuffer);
+ TCHAR* preview = Utils::GetPreviewWithEllipsis(msg, 255);
+ lvItem.pszText = preview;
+ lvItem.iSubItem = 2;
+ ::SendMessage(m_hwndList, LVM_SETITEM, 0, reinterpret_cast<LPARAM>(&lvItem));
+ mir_free(preview);
+ mir_free(msg);
+
+ if((*it)->fFailed) {
+ tszStatusText = (*it)->bCode == CSendLaterJob::JOB_REMOVABLE ?
+ CTranslator::get(CTranslator::QMGR_STATUS_REMOVED) : CTranslator::get(CTranslator::QMGR_STATUS_FAILED);
+ }
+ else if((*it)->fSuccess)
+ tszStatusText = CTranslator::get(CTranslator::QMGR_STATUS_SENTOK);
+ else {
+ switch((*it)->bCode) {
+ case CSendLaterJob::JOB_DEFERRED:
+ tszStatusText = CTranslator::get(CTranslator::QMGR_STATUS_DEFERRED);
+ break;
+ case CSendLaterJob::JOB_AGE:
+ tszStatusText = CTranslator::get(CTranslator::QMGR_STATUS_FAILED);
+ break;
+ case CSendLaterJob::JOB_HOLD:
+ tszStatusText = CTranslator::get(CTranslator::QMGR_STATUS_HOLD);
+ break;
+ default:
+ tszStatusText = CTranslator::get(CTranslator::QMGR_STATUS_PENDING);
+ break;
+ }
+ }
+ if((*it)->bCode)
+ bCode = (*it)->bCode;
+ mir_sntprintf(tszStatus, 20, _T("X/%s[%c] (%d)"), tszStatusText, bCode, (*it)->iSendCount);
+ tszStatus[0] = static_cast<TCHAR>((*it)->szId[0]);
+ lvItem.pszText = tszStatus;
+ lvItem.iSubItem = 3;
+ ::SendMessage(m_hwndList, LVM_SETITEM, 0, reinterpret_cast<LPARAM>(&lvItem));
+
+ if((*it)->lastSent == 0)
+ mir_sntprintf(tszTimestamp, 30, _T("%s"), _T("Never"));
+ else {
+ _tcsftime(tszTimestamp, 30, formatTime, _localtime32((__time32_t *)&(*it)->lastSent));
+ tszTimestamp[29] = 0;
+ }
+ lvItem.pszText = tszTimestamp;
+ lvItem.iSubItem = 4;
+ ::SendMessage(m_hwndList, LVM_SETITEM, 0, reinterpret_cast<LPARAM>(&lvItem));
+ }
+ it++;
+ }
+ if(m_hFilter == 0)
+ ::SendMessage(m_hwndFilter, CB_SETCURSEL, 0, 0);
+ else
+ ::SendMessage(m_hwndFilter, CB_SETCURSEL, m_sel, 0);
+}
+
+/*
+ * set the column headers
+ */
+#define QMGR_LIST_NRCOLUMNS 5
+
+static char* szColFormat = "%d;%d;%d;%d;%d";
+static char* szColDefault = "100;120;80;120;120";
+
+void CSendLater::qMgrSetupColumns()
+{
+ LVCOLUMN col = {0};
+ int nWidths[QMGR_LIST_NRCOLUMNS];
+ DBVARIANT dbv = {0};
+ RECT rcList;
+ LONG cxList;
+
+ ::GetWindowRect(m_hwndList, &rcList);
+ cxList = rcList.right - rcList.left;
+
+ if(0 == M->GetString(0, SRMSGMOD_T, "qmgrListColumns", &dbv)) {
+ sscanf(dbv.pszVal, szColFormat, &nWidths[0], &nWidths[1], &nWidths[2], &nWidths[3], &nWidths[4]);
+ DBFreeVariant(&dbv);
+ }
+ else
+ sscanf(szColDefault, szColFormat, &nWidths[0], &nWidths[1], &nWidths[2], &nWidths[3], &nWidths[4]);
+
+ col.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM;
+ col.cx = max(nWidths[0], 10);
+ col.pszText = const_cast<TCHAR *>(CTranslator::get(CTranslator::GEN_CONTACT));
+
+ ::SendMessage(m_hwndList, LVM_INSERTCOLUMN, 0, reinterpret_cast<LPARAM>(&col));
+
+ col.pszText = const_cast<TCHAR *>(CTranslator::get(CTranslator::QMGR_COL_ODATE));
+ col.cx = max(nWidths[1], 10);
+ ::SendMessage(m_hwndList, LVM_INSERTCOLUMN, 1, reinterpret_cast<LPARAM>(&col));
+
+ col.pszText = const_cast<TCHAR *>(CTranslator::get(CTranslator::QMGR_COL_MESSAGETEXT));
+ col.cx = max((cxList - nWidths[0] - nWidths[1] - nWidths[3] - nWidths[4] - 10), 10);
+ ::SendMessage(m_hwndList, LVM_INSERTCOLUMN, 2, reinterpret_cast<LPARAM>(&col));
+
+ col.pszText = const_cast<TCHAR *>(CTranslator::get(CTranslator::QMGR_COL_STATUS));
+ col.cx = max(nWidths[3], 10);
+ ::SendMessage(m_hwndList, LVM_INSERTCOLUMN, 3, reinterpret_cast<LPARAM>(&col));
+
+ col.pszText = const_cast<TCHAR *>(CTranslator::get(CTranslator::QMGR_COL_LASTSENDINFO));
+ col.cx = max(nWidths[4], 10);
+ ::SendMessage(m_hwndList, LVM_INSERTCOLUMN, 4, reinterpret_cast<LPARAM>(&col));
+
+}
+
+/**
+ * save user defined column widths to the database
+ */
+void CSendLater::qMgrSaveColumns()
+{
+ char szColFormatNew[100];
+ int nWidths[QMGR_LIST_NRCOLUMNS], i;
+ LVCOLUMN col = {0};
+
+ col.mask = LVCF_WIDTH;
+ for(i = 0; i < QMGR_LIST_NRCOLUMNS; i++) {
+ ::SendMessage(m_hwndList, LVM_GETCOLUMN, i, reinterpret_cast<LPARAM>(&col));
+ nWidths[i] = max(col.cx, 10);
+ }
+ mir_snprintf(szColFormatNew, 100, "%d;%d;%d;%d;%d", nWidths[0], nWidths[1], nWidths[2], nWidths[3], nWidths[4]);
+ ::DBWriteContactSettingString(0, SRMSGMOD_T, "qmgrListColumns", szColFormatNew);
+}
+
+INT_PTR CALLBACK CSendLater::DlgProcStub(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CSendLater *s = reinterpret_cast<CSendLater *>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
+
+ if(s)
+ return(s->DlgProc(hwnd, msg, wParam, lParam));
+
+ switch(msg) {
+ case WM_INITDIALOG: {
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
+ s = reinterpret_cast<CSendLater *>(lParam);
+ return(s->DlgProc(hwnd, msg, wParam, lParam));
+ }
+ default:
+ break;
+ }
+ return(FALSE);
+}
+
+INT_PTR CALLBACK CSendLater::DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ m_hwndDlg = hwnd;
+ TranslateDialogDefault(hwnd);
+ m_hwndList = ::GetDlgItem(m_hwndDlg, IDC_QMGR_LIST);
+ m_hwndFilter = ::GetDlgItem(m_hwndDlg, IDC_QMGR_FILTER);
+ m_hFilter = reinterpret_cast<HANDLE>(M->GetDword(0, SRMSGMOD_T, "qmgrFilterContact", 0));
+
+ ::SetWindowLongPtr(m_hwndList, GWL_STYLE, ::GetWindowLongPtr(m_hwndList, GWL_STYLE) | LVS_SHOWSELALWAYS);
+ ::SendMessage(m_hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_LABELTIP|LVS_EX_DOUBLEBUFFER);
+ qMgrSetupColumns();
+ qMgrFillList();
+ if(PluginConfig.g_PopupAvail) {
+ ::CheckDlgButton(m_hwndDlg, IDC_QMGR_SUCCESSPOPUPS, m_fSuccessPopups ? BST_CHECKED : BST_UNCHECKED);
+ ::CheckDlgButton(m_hwndDlg, IDC_QMGR_ERRORPOPUPS, m_fErrorPopups ? BST_CHECKED : BST_UNCHECKED);
+ }
+ else {
+ Utils::showDlgControl(m_hwndDlg, IDC_QMGR_ERRORPOPUPS, SW_HIDE);
+ Utils::showDlgControl(m_hwndDlg, IDC_QMGR_SUCCESSPOPUPS, SW_HIDE);
+ }
+ ::ShowWindow(hwnd, SW_NORMAL);
+ return(FALSE);
+
+ case WM_NOTIFY: {
+ NMHDR* pNMHDR = reinterpret_cast<NMHDR *>(lParam);
+
+ if(pNMHDR->hwndFrom == m_hwndList) {
+ switch(pNMHDR->code) {
+ case NM_RCLICK: {
+ HMENU hMenu = ::LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_TABCONTEXT));
+ HMENU hSubMenu = ::GetSubMenu(hMenu, 13);
+ ::TranslateMenu(hSubMenu);
+
+ POINT pt;
+ ::GetCursorPos(&pt);
+ /*
+ * copy to clipboard only allowed with a single selection
+ */
+ if(::SendMessage(m_hwndList, LVM_GETSELECTEDCOUNT, 0, 0) == 1)
+ ::EnableMenuItem(hSubMenu, ID_QUEUEMANAGER_COPYMESSAGETOCLIPBOARD, MF_ENABLED);
+
+ m_fIsInteractive = true;
+ int selection = ::TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_hwndDlg, NULL);
+ if(selection == ID_QUEUEMANAGER_CANCELALLMULTISENDJOBS) {
+ SendLaterJobIterator it = m_sendLaterJobList.begin();
+ while(it != m_sendLaterJobList.end()) {
+ if((*it)->szId[0] == 'M') {
+ (*it)->fFailed = true;
+ (*it)->bCode = CSendLaterJob::JOB_REMOVABLE;
+ }
+ it++;
+ }
+ }
+ else if(selection != 0) {
+ ::SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_QMGR_REMOVE, LOWORD(selection)), 0);
+ m_last_sendlater_processed = 0; // force a queue check
+ }
+ ::DestroyMenu(hMenu);
+ m_fIsInteractive = false;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ case WM_COMMAND:
+ if(HIWORD(wParam) == CBN_SELCHANGE && reinterpret_cast<HWND>(lParam) == m_hwndFilter) {
+ LRESULT lr = ::SendMessage(m_hwndFilter, CB_GETCURSEL, 0, 0);
+ if(lr != CB_ERR) {
+ m_hFilter = reinterpret_cast<HANDLE>(::SendMessage(m_hwndFilter, CB_GETITEMDATA, lr, 0));
+ qMgrFillList();
+ }
+ break;
+ }
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ qMgrSaveColumns();
+ ::DestroyWindow(hwnd);
+ break;
+
+ case IDC_QMGR_SUCCESSPOPUPS:
+ m_fSuccessPopups = ::IsDlgButtonChecked(m_hwndDlg, IDC_QMGR_SUCCESSPOPUPS) ? true : false;
+ M->WriteByte(0, SRMSGMOD_T, "qmgrSuccessPopups", m_fSuccessPopups ? 1 : 0);
+ break;
+
+ case IDC_QMGR_ERRORPOPUPS:
+ m_fErrorPopups = ::IsDlgButtonChecked(m_hwndDlg, IDC_QMGR_ERRORPOPUPS) ? true : false;
+ M->WriteByte(0, SRMSGMOD_T, "qmgrErrorPopups", m_fErrorPopups ? 1 : 0);
+ break;
+
+ case IDC_QMGR_HELP:
+ CallService(MS_UTILS_OPENURL, 0, reinterpret_cast<LPARAM>("http://wiki.miranda.or.at/TabSRMM/SendLater"));
+ break;
+ /*
+ * this handles all commands sent by the context menu
+ * mark jobs for removal/reset/hold/unhold
+ * exception: kill all open multisend jobs is directly handled from the context menu
+ */
+ case IDC_QMGR_REMOVE: {
+ if(::SendMessage(m_hwndList, LVM_GETSELECTEDCOUNT, 0, 0) != 0) {
+ LVITEM item = {0};
+ LRESULT items = ::SendMessage(m_hwndList, LVM_GETITEMCOUNT, 0, 0);
+ item.mask = LVIF_STATE|LVIF_PARAM;
+ item.stateMask = LVIS_SELECTED;
+
+ if(HIWORD(wParam) != ID_QUEUEMANAGER_COPYMESSAGETOCLIPBOARD) {
+ if(MessageBox(0, CTranslator::get(CTranslator::QMGR_WARNING_REMOVAL), CTranslator::get(CTranslator::QMGR_TITLE),
+ MB_ICONQUESTION | MB_OKCANCEL) == IDCANCEL)
+ break;
+ }
+ for(LRESULT i = 0; i < items; i++) {
+ item.iItem = i;
+ ::SendMessage(m_hwndList, LVM_GETITEM, 0, reinterpret_cast<LPARAM>(&item));
+ if(item.state & LVIS_SELECTED) {
+ CSendLaterJob* job = reinterpret_cast<CSendLaterJob *>(item.lParam);
+ if(job) {
+ switch(HIWORD(wParam)) {
+ case ID_QUEUEMANAGER_MARKSELECTEDFORREMOVAL:
+ job->bCode = CSendLaterJob::JOB_REMOVABLE;
+ job->fFailed = true;
+ break;
+ case ID_QUEUEMANAGER_HOLDSELECTED:
+ job->bCode = CSendLaterJob::JOB_HOLD;
+ job->writeFlags();
+ break;
+ case ID_QUEUEMANAGER_RESUMESELECTED:
+ job->bCode = 0;
+ job->writeFlags();
+ break;
+ case ID_QUEUEMANAGER_COPYMESSAGETOCLIPBOARD: {
+ TCHAR *msg = M->utf8_decodeT(job->sendBuffer);
+ Utils::CopyToClipBoard(msg, m_hwndDlg);
+ mir_free(msg);
+ break;
+ }
+ /*
+ * reset deferred and aged jobs
+ * so they can be resent at next processing
+ */
+ case ID_QUEUEMANAGER_RESETSELECTED: {
+ if(job->bCode == CSendLaterJob::JOB_DEFERRED) {
+ job->iSendCount = 0;
+ job->bCode = '-';
+ }
+ else if(job->bCode == CSendLaterJob::JOB_AGE) {
+ job->fFailed = false;
+ job->bCode = '-';
+ job->created = time(0);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+ qMgrFillList();
+ }
+ break;
+ }
+ }
+ break;
+
+ case WM_USER + 100:
+ qMgrFillList();
+ break;
+ case WM_NCDESTROY: {
+ m_hwndDlg = 0;
+ M->WriteDword(0, SRMSGMOD_T, "qmgrFilterContact", reinterpret_cast<DWORD>(m_hFilter));
+ break;
+ }
+ }
+ return(FALSE);
+}
+
+/**
+ * invoke queue manager dialog - do nothing if this dialog is already open
+ */
+void CSendLater::invokeQueueMgrDlg()
+{
+ if(m_hwndDlg == 0)
+ m_hwndDlg = ::CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_SENDLATER_QMGR), 0, CSendLater::DlgProcStub,
+ reinterpret_cast<LPARAM>(this));
+}
+
+/*
+ * service function to invoke the queue manager
+ */
+
+INT_PTR CSendLater::svcQMgr(WPARAM wParam, LPARAM lParam)
+{
+ sendLater->invokeQueueMgrDlg();
+ return(0);
+}
+
+
+CSendLater* sendLater = 0;
diff --git a/plugins/TabSRMM/src/sendqueue.cpp b/plugins/TabSRMM/src/sendqueue.cpp
new file mode 100644
index 0000000000..b4e90359e9
--- /dev/null
+++ b/plugins/TabSRMM/src/sendqueue.cpp
@@ -0,0 +1,989 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: sendqueue.cpp 13750 2011-08-03 20:10:43Z george.hazan $
+ *
+ * Implements a queued, asynchronous sending system for tabSRMM.
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+SendQueue *sendQueue = 0;
+
+extern const TCHAR *pszIDCSAVE_save, *pszIDCSAVE_close;
+
+static char *pss_msg = "/SendMsg";
+static char *pss_msgw = "/SendMsgW";
+
+/**
+ * get the service name to send a message
+ *
+ * @param hContact (HANDLE) contact's handle
+ * @param dat _MessageWindowData
+ * @param dwFlags
+ *
+ * @return (char *) name of the service to send a message to this contact
+ */
+char *SendQueue::MsgServiceName(const HANDLE hContact = 0, const TWindowData *dat = 0, int dwFlags = 0)
+{
+ char szServiceName[100];
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+
+ if (szProto == NULL)
+ return pss_msg;
+
+ if(dat) {
+ if (dat->sendMode & SMODE_FORCEANSI || !(dwFlags & PREF_UNICODE))
+ return pss_msg;
+ }
+
+ _snprintf(szServiceName, sizeof(szServiceName), "%s%sW", szProto, PSS_MESSAGE);
+ if (ServiceExists(szServiceName))
+ return pss_msgw;
+
+ return pss_msg;
+}
+
+/*
+ * searches the queue for a message belonging to the given contact which has been marked
+ * as "failed" by either the ACKRESULT_FAILED or a timeout handler
+ * returns: zero-based queue index or -1 if none was found
+ */
+
+int SendQueue::findNextFailed(const TWindowData *dat) const
+{
+ if(dat) {
+ int i;
+
+ for (i = 0; i < NR_SENDJOBS; i++) {
+ if (m_jobs[i].hOwner == dat->hContact && m_jobs[i].iStatus == SQ_ERROR)
+ return i;
+ }
+ return -1;
+ }
+ return -1;
+}
+void SendQueue::handleError(TWindowData *dat, const int iEntry) const
+{
+ if(dat) {
+ TCHAR szErrorMsg[500];
+
+ dat->iCurrentQueueError = iEntry;
+ mir_sntprintf(szErrorMsg, 500, _T("%s"), m_jobs[iEntry].szErrorMsg);
+ logError(dat, iEntry, szErrorMsg);
+ recallFailed(dat, iEntry);
+ showErrorControls(dat, TRUE);
+ ::HandleIconFeedback(dat, PluginConfig.g_iconErr);
+ }
+}
+/*
+ * add a message to the sending queue.
+ * iLen = required size of the memory block to hold the message
+ */
+int SendQueue::addTo(TWindowData *dat, const int iLen, int dwFlags)
+{
+ int iLength = 0, i;
+ int iFound = NR_SENDJOBS;
+
+ if (m_currentIndex >= NR_SENDJOBS) {
+ _DebugPopup(dat->hContact, _T("Send queue full"));
+ return 0;
+ }
+ /*
+ * find a free entry in the send queue...
+ */
+ for (i = 0; i < NR_SENDJOBS; i++) {
+ if (m_jobs[i].hOwner != 0 || m_jobs[i].iStatus != 0) {
+ // this entry is used, check if it's orphaned and can be removed...
+ if (m_jobs[i].hwndOwner && IsWindow(m_jobs[i].hwndOwner)) // window exists, do not reuse it
+ continue;
+ if (time(NULL) - m_jobs[i].dwTime < 120) // non-acked entry, but not old enough, don't re-use it
+ continue;
+ clearJob(i);
+ iFound = i;
+ goto entry_found;
+ }
+ iFound = i;
+ break;
+ }
+entry_found:
+ if (iFound == NR_SENDJOBS) {
+ _DebugPopup(dat->hContact, _T("Send queue full"));
+ return 0;
+ }
+ iLength = iLen;
+ if (iLength > 0) {
+ if (m_jobs[iFound].sendBuffer == NULL) {
+ if (iLength < HISTORY_INITIAL_ALLOCSIZE)
+ iLength = HISTORY_INITIAL_ALLOCSIZE;
+ m_jobs[iFound].sendBuffer = (char *)malloc(iLength);
+ m_jobs[iFound].dwLen = iLength;
+ }
+ else {
+ if (iLength > m_jobs[iFound].dwLen) {
+ m_jobs[iFound].sendBuffer = (char *)realloc(m_jobs[iFound].sendBuffer, iLength);
+ m_jobs[iFound].dwLen = iLength;
+ }
+ }
+ CopyMemory(m_jobs[iFound].sendBuffer, dat->sendBuffer, iLen);
+ }
+ m_jobs[iFound].dwFlags = dwFlags;
+ m_jobs[iFound].dwTime = time(NULL);
+
+ HWND hwndDlg = dat->hwnd;
+
+ dat->cache->saveHistory(0, 0);
+ ::SetDlgItemText(hwndDlg, IDC_MESSAGE, _T(""));
+ ::SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+
+ UpdateSaveAndSendButton(dat);
+ sendQueued(dat, iFound);
+ return 0;
+}
+
+/*
+ * threshold for word-wrapping when sending messages in chunks
+ */
+
+#define SPLIT_WORD_CUTOFF 20
+
+static int SendChunkW(WCHAR *chunk, HANDLE hContact, char *szSvc, DWORD dwFlags)
+{
+ BYTE *pBuf = NULL;
+ int wLen = lstrlenW(chunk), id;
+ DWORD memRequired = (wLen + 1) * sizeof(WCHAR);
+ DWORD codePage = DBGetContactSettingDword(hContact, SRMSGMOD_T, "ANSIcodepage", CP_ACP);
+ int mbcsSize = WideCharToMultiByte(codePage, 0, chunk, -1, (char *)pBuf, 0, 0, 0);
+
+ memRequired += mbcsSize;
+ pBuf = (BYTE *)mir_alloc(memRequired);
+ WideCharToMultiByte(codePage, 0, chunk, -1, (char *)pBuf, mbcsSize, 0, 0);
+ CopyMemory(&pBuf[mbcsSize], chunk, (wLen + 1) * sizeof(WCHAR));
+ id = CallContactService(hContact, szSvc, dwFlags, (LPARAM)pBuf);
+ mir_free(pBuf);
+ return id;
+}
+
+static int SendChunkA(char *chunk, HANDLE hContact, char *szSvc, DWORD dwFlags)
+{
+ return(CallContactService(hContact, szSvc, dwFlags, (LPARAM)chunk));
+}
+
+static void DoSplitSendW(LPVOID param)
+{
+ struct SendJob *job = sendQueue->getJobByIndex((int)param);
+ int id;
+ BOOL fFirstSend = FALSE;
+ WCHAR *wszBegin, *wszTemp, *wszSaved, savedChar;
+ int iLen, iCur = 0, iSavedCur = 0, i;
+ BOOL fSplitting = TRUE;
+ char szServiceName[100], *svcName;
+ HANDLE hContact = job->hOwner;
+ DWORD dwFlags = job->dwFlags;
+ int chunkSize = job->chunkSize / 2;
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+
+ if (szProto == NULL)
+ svcName = pss_msg;
+ else {
+ _snprintf(szServiceName, sizeof(szServiceName), "%s%sW", szProto, PSS_MESSAGE);
+ if (ServiceExists(szServiceName))
+ svcName = pss_msgw;
+ else
+ svcName = pss_msg;
+ }
+
+ iLen = lstrlenA(job->sendBuffer);
+ wszBegin = (WCHAR *) & job->sendBuffer[iLen + 1];
+ wszTemp = (WCHAR *)mir_alloc(sizeof(WCHAR) * (lstrlenW(wszBegin) + 1));
+ CopyMemory(wszTemp, wszBegin, sizeof(WCHAR) * (lstrlenW(wszBegin) + 1));
+ wszBegin = wszTemp;
+
+ do {
+ iCur += chunkSize;
+ if (iCur > iLen)
+ fSplitting = FALSE;
+
+ /*
+ * try to "word wrap" the chunks - split on word boundaries (space characters), if possible.
+ * SPLIT_WORD_CUTOFF = max length of unbreakable words, longer words may be split.
+ */
+
+ if (fSplitting) {
+ i = 0;
+ wszSaved = &wszBegin[iCur];
+ iSavedCur = iCur;
+ while (iCur) {
+ if (wszBegin[iCur] == (TCHAR)' ') {
+ wszSaved = &wszBegin[iCur];
+ break;
+ }
+ if (i == SPLIT_WORD_CUTOFF) { // no space found backwards, restore old split position
+ iCur = iSavedCur;
+ wszSaved = &wszBegin[iCur];
+ break;
+ }
+ i++;
+ iCur--;
+ }
+ savedChar = *wszSaved;
+ *wszSaved = 0;
+ id = SendChunkW(wszTemp, hContact, svcName, dwFlags);
+ if (!fFirstSend) {
+ job->hSendId = (HANDLE)id;
+ fFirstSend = TRUE;
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SPLITSENDACK, (WPARAM)param, 0);
+ }
+ *wszSaved = savedChar;
+ wszTemp = wszSaved;
+ if (savedChar == (TCHAR)' ') {
+ wszTemp++;
+ iCur++;
+ }
+ }
+ else {
+ id = SendChunkW(wszTemp, hContact, svcName, dwFlags);
+ if (!fFirstSend) {
+ job->hSendId = (HANDLE)id;
+ fFirstSend = TRUE;
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SPLITSENDACK, (WPARAM)param, 0);
+ }
+ }
+ Sleep(500L);
+ }
+ while (fSplitting);
+ mir_free(wszBegin);
+}
+
+static void DoSplitSendA(LPVOID param)
+{
+ struct SendJob *job = sendQueue->getJobByIndex((int)param);
+ int id;
+ BOOL fFirstSend = FALSE;
+ char *szBegin, *szTemp, *szSaved, savedChar;
+ int iLen, iCur = 0, iSavedCur = 0, i;
+ BOOL fSplitting = TRUE;
+ char *svcName;
+ HANDLE hContact = job->hOwner;
+ DWORD dwFlags = job->dwFlags;
+ int chunkSize = job->chunkSize;
+
+ svcName = pss_msg;
+
+ iLen = lstrlenA(job->sendBuffer);
+ szTemp = (char *)mir_alloc(iLen + 1);
+ CopyMemory(szTemp, job->sendBuffer, iLen + 1);
+ szBegin = szTemp;
+
+ do {
+ iCur += chunkSize;
+ if (iCur > iLen)
+ fSplitting = FALSE;
+
+ if (fSplitting) {
+ i = 0;
+ szSaved = &szBegin[iCur];
+ iSavedCur = iCur;
+ while (iCur) {
+ if (szBegin[iCur] == ' ') {
+ szSaved = &szBegin[iCur];
+ break;
+ }
+ if (i == SPLIT_WORD_CUTOFF) {
+ iCur = iSavedCur;
+ szSaved = &szBegin[iCur];
+ break;
+ }
+ i++;
+ iCur--;
+ }
+ savedChar = *szSaved;
+ *szSaved = 0;
+ id = SendChunkA(szTemp, hContact, PSS_MESSAGE, dwFlags);
+ if (!fFirstSend) {
+ job->hSendId = (HANDLE)id;
+ fFirstSend = TRUE;
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SPLITSENDACK, (WPARAM)param, 0);
+ }
+ *szSaved = savedChar;
+ szTemp = szSaved;
+ if (savedChar == ' ') {
+ szTemp++;
+ iCur++;
+ }
+ }
+ else {
+ id = SendChunkA(szTemp, hContact, PSS_MESSAGE, dwFlags);
+ if (!fFirstSend) {
+ job->hSendId = (HANDLE)id;
+ fFirstSend = TRUE;
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SPLITSENDACK, (WPARAM)param, 0);
+ }
+ }
+ Sleep(500L);
+ }
+ while (fSplitting);
+ mir_free(szBegin);
+}
+
+/**
+ * return effective length of the message in bytes (utf-8 encoded)
+ */
+int SendQueue::getSendLength(const int iEntry, int sendMode)
+{
+ if(m_jobs[iEntry].dwFlags & PREF_UNICODE && !(sendMode & SMODE_FORCEANSI)) {
+ int iLen;
+ WCHAR *wszBuf;
+ char *utf8;
+ iLen = lstrlenA(m_jobs[iEntry].sendBuffer);
+ wszBuf = (WCHAR *) & m_jobs[iEntry].sendBuffer[iLen + 1];
+ utf8 = M->utf8_encodeW(wszBuf);
+ m_jobs[iEntry].iSendLength = lstrlenA(utf8);
+ mir_free(utf8);
+ return(m_jobs[iEntry].iSendLength);
+ }
+ else {
+ m_jobs[iEntry].iSendLength = lstrlenA(m_jobs[iEntry].sendBuffer);
+ return(m_jobs[iEntry].iSendLength);
+ }
+}
+
+int SendQueue::sendQueued(TWindowData *dat, const int iEntry)
+{
+ HWND hwndDlg = dat->hwnd;
+
+ if (dat->sendMode & SMODE_MULTIPLE) {
+ HANDLE hContact, hItem;
+ int iJobs = 0;
+ int iMinLength = 0;
+ CContactCache* c = 0;
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+
+ m_jobs[iEntry].hOwner = dat->hContact;
+ m_jobs[iEntry].iStatus = SQ_INPROGRESS;
+ m_jobs[iEntry].hwndOwner = hwndDlg;
+
+ int iSendLength = getSendLength(iEntry, dat->sendMode);
+
+ do {
+ hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0);
+ if (hItem && SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItem, 0)) {
+ c = CContactCache::getContactCache(hContact);
+ if(c)
+ iMinLength = (iMinLength == 0 ? c->getMaxMessageLength() : min(c->getMaxMessageLength(), iMinLength));
+ }
+ } while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0));
+
+ if(iSendLength >= iMinLength) {
+ TCHAR tszError[256];
+
+ mir_sntprintf(tszError, 256, CTranslator::get(CTranslator::GEN_SQ_SENDLATER_ERROR_MSG_TOO_LONG), iMinLength);
+ ::SendMessage(dat->hwnd, DM_ACTIVATETOOLTIP, IDC_MESSAGE, reinterpret_cast<LPARAM>(tszError));
+ sendQueue->clearJob(iEntry);
+ return(0);
+ }
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do {
+ hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0);
+ if (hItem && SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItem, 0)) {
+ doSendLater(iEntry, 0, hContact, false);
+ iJobs++;
+ }
+ } while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0));
+
+ sendQueue->clearJob(iEntry);
+ if(iJobs)
+ sendLater->flushQueue(); // force queue processing
+ return(0);
+ }
+ else {
+ if (dat->hContact == NULL)
+ return 0; //never happens
+
+ dat->nMax = dat->cache->getMaxMessageLength(); // refresh length info
+
+ if (dat->sendMode & SMODE_FORCEANSI && M->GetByte(dat->cache->getActiveContact(), dat->cache->getActiveProto(), "UnicodeSend", 1))
+ M->WriteByte(dat->cache->getActiveContact(), dat->cache->getActiveProto(), "UnicodeSend", 0);
+ else if (!(dat->sendMode & SMODE_FORCEANSI) && !M->GetByte(dat->cache->getActiveContact(), dat->cache->getActiveProto(), "UnicodeSend", 0))
+ M->WriteByte(dat->cache->getActiveContact(), dat->cache->getActiveProto(), "UnicodeSend", 1);
+
+ if (M->GetByte("autosplit", 0) && !(dat->sendMode & SMODE_SENDLATER)) {
+ BOOL fSplit = FALSE;
+ DWORD dwOldFlags;
+
+ /*
+ * determine send buffer length
+ */
+ if(getSendLength(iEntry, dat->sendMode) >= dat->nMax)
+ fSplit = true;
+
+ if (!fSplit)
+ goto send_unsplitted;
+
+ m_jobs[iEntry].hOwner = dat->hContact;
+ m_jobs[iEntry].hwndOwner = hwndDlg;
+ m_jobs[iEntry].iStatus = SQ_INPROGRESS;
+ m_jobs[iEntry].iAcksNeeded = 1;
+ m_jobs[iEntry].chunkSize = dat->nMax;
+
+ dwOldFlags = m_jobs[iEntry].dwFlags;
+ if (dat->sendMode & SMODE_FORCEANSI)
+ m_jobs[iEntry].dwFlags &= ~PREF_UNICODE;
+
+ if (!(m_jobs[iEntry].dwFlags & PREF_UNICODE) || dat->sendMode & SMODE_FORCEANSI)
+ mir_forkthread(DoSplitSendA, (LPVOID)iEntry);
+ else
+ mir_forkthread(DoSplitSendW, (LPVOID)iEntry);
+ m_jobs[iEntry].dwFlags = dwOldFlags;
+ }
+ else {
+
+send_unsplitted:
+
+ m_jobs[iEntry].hOwner = dat->hContact;
+ m_jobs[iEntry].hwndOwner = hwndDlg;
+ m_jobs[iEntry].iStatus = SQ_INPROGRESS;
+ m_jobs[iEntry].iAcksNeeded = 1;
+ if(dat->sendMode & SMODE_SENDLATER) {
+ TCHAR tszError[256];
+
+ int iSendLength = getSendLength(iEntry, dat->sendMode);
+ if(iSendLength >= dat->nMax) {
+ mir_sntprintf(tszError, 256, CTranslator::get(CTranslator::GEN_SQ_SENDLATER_ERROR_MSG_TOO_LONG), dat->nMax);
+ SendMessage(dat->hwnd, DM_ACTIVATETOOLTIP, IDC_MESSAGE, reinterpret_cast<LPARAM>(tszError));
+ clearJob(iEntry);
+ return(0);
+ }
+ doSendLater(iEntry, dat);
+ clearJob(iEntry);
+ return(0);
+ }
+ m_jobs[iEntry].hSendId = (HANDLE) CallContactService(dat->hContact, MsgServiceName(dat->hContact, dat, m_jobs[iEntry].dwFlags), (dat->sendMode & SMODE_FORCEANSI) ? (m_jobs[iEntry].dwFlags & ~PREF_UNICODE) : m_jobs[iEntry].dwFlags, (LPARAM) m_jobs[iEntry].sendBuffer);
+
+ if (dat->sendMode & SMODE_NOACK) { // fake the ack if we are not interested in receiving real acks
+ ACKDATA ack = {0};
+ ack.hContact = dat->hContact;
+ ack.hProcess = m_jobs[iEntry].hSendId;
+ ack.type = ACKTYPE_MESSAGE;
+ ack.result = ACKRESULT_SUCCESS;
+ SendMessage(hwndDlg, HM_EVENTSENT, (WPARAM)MAKELONG(iEntry, 0), (LPARAM)&ack);
+ }
+ else
+ SetTimer(hwndDlg, TIMERID_MSGSEND + iEntry, PluginConfig.m_MsgTimeout, NULL);
+ }
+ }
+ dat->iOpenJobs++;
+ m_currentIndex++;
+
+ // give icon feedback...
+
+ if (dat->pContainer->hwndActive == hwndDlg)
+ ::UpdateReadChars(dat);
+
+ if (!(dat->sendMode & SMODE_NOACK))
+ ::HandleIconFeedback(dat, PluginConfig.g_IconSend);
+
+ if (M->GetByte(SRMSGSET_AUTOMIN, SRMSGDEFSET_AUTOMIN))
+ ::SendMessage(dat->pContainer->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+ return 0;
+}
+
+void SendQueue::clearJob(const int iIndex)
+{
+ m_jobs[iIndex].hOwner = 0;
+ m_jobs[iIndex].hwndOwner = 0;
+ m_jobs[iIndex].iStatus = 0;
+ m_jobs[iIndex].iAcksNeeded = 0;
+ m_jobs[iIndex].dwFlags = 0;
+ m_jobs[iIndex].chunkSize = 0;
+ m_jobs[iIndex].dwTime = 0;
+ m_jobs[iIndex].hSendId = 0;
+ m_jobs[iIndex].iSendLength = 0;
+}
+
+/*
+ * this is called when:
+ *
+ * ) a delivery has completed successfully
+ * ) user decided to cancel a failed send
+ * it removes the completed / canceled send job from the queue and schedules the next job to send (if any)
+ */
+
+void SendQueue::checkQueue(const TWindowData *dat) const
+{
+ if(dat) {
+ HWND hwndDlg = dat->hwnd;
+
+ if (dat->iOpenJobs == 0) {
+ ::HandleIconFeedback(const_cast<TWindowData *>(dat), (HICON) - 1);
+ }
+ else if (!(dat->sendMode & SMODE_NOACK))
+ ::HandleIconFeedback(const_cast<TWindowData *>(dat), PluginConfig.g_IconSend);
+
+ if (dat->pContainer->hwndActive == hwndDlg)
+ ::UpdateReadChars(const_cast<TWindowData *>(dat));
+ }
+}
+
+/*
+ * logs an error message to the message window. Optionally, appends the original message
+ * from the given sendJob (queue index)
+ */
+
+void SendQueue::logError(const TWindowData *dat, int iSendJobIndex, const TCHAR *szErrMsg) const
+{
+ DBEVENTINFO dbei = {0};
+ int iMsgLen;
+
+ if(dat == 0)
+ return;
+
+ dbei.eventType = EVENTTYPE_ERRMSG;
+ dbei.cbSize = sizeof(dbei);
+ if (iSendJobIndex >= 0) {
+ dbei.pBlob = (BYTE *)m_jobs[iSendJobIndex].sendBuffer;
+ iMsgLen = lstrlenA(m_jobs[iSendJobIndex].sendBuffer) + 1;
+ }
+ else {
+ iMsgLen = 0;
+ dbei.pBlob = NULL;
+ }
+ if (m_jobs[iSendJobIndex].dwFlags & PREF_UTF)
+ dbei.flags = DBEF_UTF;
+ if (iSendJobIndex >= 0) {
+ if (m_jobs[iSendJobIndex].dwFlags & PREF_UNICODE) {
+ iMsgLen *= 3;
+ }
+ }
+ dbei.cbBlob = iMsgLen;
+ dbei.timestamp = time(NULL);
+ dbei.szModule = (char *)szErrMsg;
+ StreamInEvents(dat->hwnd, NULL, 1, 1, &dbei);
+}
+
+/*
+ * enable or disable the sending controls in the given window
+ * ) input area
+ * ) multisend contact list instance
+ * ) send button
+ */
+
+void SendQueue::EnableSending(const TWindowData *dat, const int iMode)
+{
+ if(dat) {
+ HWND hwndDlg = dat->hwnd;
+ ::SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETREADONLY, (WPARAM) iMode ? FALSE : TRUE, 0);
+ Utils::enableDlgControl(hwndDlg, IDC_CLIST, iMode ? TRUE : FALSE);
+ ::EnableSendButton(dat, iMode);
+ }
+}
+
+/*
+ * show or hide the error control button bar on top of the window
+ */
+
+void SendQueue::showErrorControls(TWindowData *dat, const int showCmd) const
+{
+ UINT myerrorControls[] = { IDC_STATICERRORICON, IDC_STATICTEXT, IDC_RETRY, IDC_CANCELSEND, IDC_MSGSENDLATER};
+ int i;
+ HWND hwndDlg = dat->hwnd;
+
+ if (showCmd) {
+ TCITEM item = {0};
+ dat->hTabIcon = PluginConfig.g_iconErr;
+ item.mask = TCIF_IMAGE;
+ item.iImage = 0;
+ TabCtrl_SetItem(GetDlgItem(dat->pContainer->hwnd, IDC_MSGTABS), dat->iTabID, &item);
+ dat->dwFlags |= MWF_ERRORSTATE;
+ }
+ else {
+ dat->dwFlags &= ~MWF_ERRORSTATE;
+ dat->hTabIcon = dat->hTabStatusIcon;
+ }
+
+ for (i = 0; i < 5; i++) {
+ if (IsWindow(GetDlgItem(hwndDlg, myerrorControls[i])))
+ Utils::showDlgControl(hwndDlg, myerrorControls[i], showCmd ? SW_SHOW : SW_HIDE);
+ }
+
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ DM_ScrollToBottom(dat, 0, 1);
+ if (m_jobs[0].hOwner != 0)
+ EnableSending(dat, TRUE);
+}
+
+void SendQueue::recallFailed(const TWindowData *dat, int iEntry) const
+{
+ int iLen = GetWindowTextLengthA(GetDlgItem(dat->hwnd, IDC_MESSAGE));
+
+ if(dat) {
+ NotifyDeliveryFailure(dat);
+ if (iLen == 0) { // message area is empty, so we can recall the failed message...
+ SETTEXTEX stx = {ST_DEFAULT, 1200};
+ if (m_jobs[iEntry].dwFlags & PREF_UNICODE)
+ SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)&m_jobs[iEntry].sendBuffer[lstrlenA(m_jobs[iEntry].sendBuffer) + 1]);
+ else {
+ stx.codepage = (m_jobs[iEntry].dwFlags & PREF_UTF) ? CP_UTF8 : CP_ACP;
+ SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)m_jobs[iEntry].sendBuffer);
+ }
+ UpdateSaveAndSendButton(const_cast<TWindowData *>(dat));
+ SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_SETSEL, (WPARAM) - 1, (LPARAM) - 1);
+ }
+ }
+}
+
+void SendQueue::UpdateSaveAndSendButton(TWindowData *dat)
+{
+ if(dat) {
+ int len;
+ HWND hwndDlg = dat->hwnd;
+
+ GETTEXTLENGTHEX gtxl = {0};
+ gtxl.codepage = CP_UTF8;
+ gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMBYTES;
+
+ len = SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_GETTEXTLENGTHEX, (WPARAM) & gtxl, 0);
+ if (len && GetSendButtonState(hwndDlg) == PBS_DISABLED)
+ EnableSendButton(dat, TRUE);
+ else if (len == 0 && GetSendButtonState(hwndDlg) != PBS_DISABLED)
+ EnableSendButton(dat, FALSE);
+
+ if (len) { // looks complex but avoids flickering on the button while typing.
+ if (!(dat->dwFlags & MWF_SAVEBTN_SAV)) {
+ SendDlgItemMessage(hwndDlg, IDC_SAVE, BM_SETIMAGE, IMAGE_ICON, (LPARAM) PluginConfig.g_buttonBarIcons[ICON_BUTTON_SAVE]);
+ SendDlgItemMessage(hwndDlg, IDC_SAVE, BUTTONADDTOOLTIP, (WPARAM) pszIDCSAVE_save, 0);
+ dat->dwFlags |= MWF_SAVEBTN_SAV;
+ }
+ }
+ else {
+ SendDlgItemMessage(hwndDlg, IDC_SAVE, BM_SETIMAGE, IMAGE_ICON, (LPARAM) PluginConfig.g_buttonBarIcons[ICON_BUTTON_CANCEL]);
+ SendDlgItemMessage(hwndDlg, IDC_SAVE, BUTTONADDTOOLTIP, (WPARAM) pszIDCSAVE_close, 0);
+ dat->dwFlags &= ~MWF_SAVEBTN_SAV;
+ }
+ dat->textLen = len;
+ }
+}
+
+void SendQueue::NotifyDeliveryFailure(const TWindowData *dat)
+{
+ POPUPDATAT_V2 ppd = {0};
+ int ibsize = 1023;
+
+ if(M->GetByte("adv_noErrorPopups", 0))
+ return;
+
+ if (CallService(MS_POPUP_QUERY, PUQS_GETSTATUS, 0) == 1) {
+ ZeroMemory((void *)&ppd, sizeof(ppd));
+ ppd.lchContact = dat->hContact;
+ mir_sntprintf(ppd.lptzContactName, MAX_CONTACTNAME, _T("%s"), dat->cache->getNick());
+ mir_sntprintf(ppd.lptzText, MAX_SECONDLINE, _T("%s"), CTranslator::get(CTranslator::GEN_SQ_DELIVERYFAILED));
+ if (!(BOOL)M->GetByte(MODULE, OPT_COLDEFAULT_ERR, TRUE))
+ {
+ ppd.colorText = (COLORREF)M->GetDword(MODULE, OPT_COLTEXT_ERR, DEFAULT_COLTEXT);
+ ppd.colorBack = (COLORREF)M->GetDword(MODULE, OPT_COLBACK_ERR, DEFAULT_COLBACK);
+ }
+ else
+ ppd.colorText = ppd.colorBack = 0;
+ ppd.PluginWindowProc = reinterpret_cast<WNDPROC>(Utils::PopupDlgProcError);
+ ppd.lchIcon = PluginConfig.g_iconErr;
+ ppd.PluginData = (void *)dat->hContact;
+ ppd.iSeconds = (int)M->GetDword(MODULE, OPT_DELAY_ERR, (DWORD)DEFAULT_DELAY);
+ CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&ppd, 0);
+ }
+}
+
+/*
+ * searches string for characters typical for RTL text (hebrew and other RTL languages
+*/
+
+int SendQueue::RTL_Detect(const WCHAR *pszwText)
+{
+ WORD *infoTypeC2;
+ int i, n = 0;
+ int iLen = lstrlenW(pszwText);
+
+ infoTypeC2 = (WORD *)mir_alloc(sizeof(WORD) * (iLen + 2));
+
+ if (infoTypeC2) {
+ ZeroMemory(infoTypeC2, sizeof(WORD) * (iLen + 2));
+
+ GetStringTypeW(CT_CTYPE2, pszwText, iLen, infoTypeC2);
+
+ for (i = 0; i < iLen; i++) {
+ if (infoTypeC2[i] == C2_RIGHTTOLEFT)
+ n++;
+ }
+ mir_free(infoTypeC2);
+ return(n >= 2 ? 1 : 0);
+ }
+ return 0;
+}
+
+int SendQueue::ackMessage(TWindowData *dat, WPARAM wParam, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA *) lParam;
+ DBEVENTINFO dbei = { 0};
+ HANDLE hNewEvent;
+ int iFound = SendQueue::NR_SENDJOBS, iNextFailed;
+ TContainerData *m_pContainer = 0;
+ if (dat)
+ m_pContainer = dat->pContainer;
+
+ iFound = (int)(LOWORD(wParam));
+ //i = (int)(HIWORD(wParam));
+
+ if (m_jobs[iFound].iStatus == SQ_ERROR) { // received ack for a job which is already in error state...
+ if (dat) { // window still open
+ if (dat->iCurrentQueueError == iFound) {
+ dat->iCurrentQueueError = -1;
+ showErrorControls(dat, FALSE);
+ }
+ }
+ /*
+ * we must discard this job, because there is no message window open to handle the
+ * error properly. But we display a tray notification to inform the user about the problem.
+ */
+ else
+ goto inform_and_discard;
+ }
+
+ // failed acks are only handled when the window is still open. with no window open, they will be *silently* discarded
+
+ if (ack->result == ACKRESULT_FAILED) {
+ if (dat) {
+ /*
+ * "hard" errors are handled differently in multisend. There is no option to retry - once failed, they
+ * are discarded and the user is notified with a small log message.
+ */
+ if (!nen_options.iNoSounds && !(m_pContainer->dwFlags & CNT_NOSOUND))
+ SkinPlaySound("SendError");
+
+ TCHAR *szAckMsg = mir_a2t((char *)ack->lParam);
+ mir_sntprintf(m_jobs[iFound].szErrorMsg, safe_sizeof(m_jobs[iFound].szErrorMsg),
+ CTranslator::get(CTranslator::GEN_MSG_DELIVERYFAILURE), szAckMsg);
+ m_jobs[iFound].iStatus = SQ_ERROR;
+ mir_free(szAckMsg);
+ KillTimer(dat->hwnd, TIMERID_MSGSEND + iFound);
+ if (!(dat->dwFlags & MWF_ERRORSTATE))
+ handleError(dat, iFound);
+ return 0;
+ }
+ else {
+inform_and_discard:
+ _DebugPopup(m_jobs[iFound].hOwner, CTranslator::get(CTranslator::GEN_SQ_DELIVERYFAILEDLATE));
+ clearJob(iFound);
+ return 0;
+ }
+ }
+
+ dbei.cbSize = sizeof(dbei);
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.flags = DBEF_SENT;
+ dbei.szModule = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) m_jobs[iFound].hOwner, 0);
+ dbei.timestamp = time(NULL);
+ dbei.cbBlob = lstrlenA(m_jobs[iFound].sendBuffer) + 1;
+
+ if (dat)
+ dat->cache->updateStats(TSessionStats::BYTES_SENT, dbei.cbBlob - 1);
+ else {
+ CContactCache *c = CContactCache::getContactCache(m_jobs[iFound].hOwner);
+ if(c)
+ c->updateStats(TSessionStats::BYTES_SENT, dbei.cbBlob - 1);
+ }
+
+ if (m_jobs[iFound].dwFlags & PREF_UNICODE)
+ dbei.cbBlob *= sizeof(TCHAR) + 1;
+ if (m_jobs[iFound].dwFlags & PREF_RTL)
+ dbei.flags |= DBEF_RTL;
+ if (m_jobs[iFound].dwFlags & PREF_UTF)
+ dbei.flags |= DBEF_UTF;
+ dbei.pBlob = (PBYTE) m_jobs[iFound].sendBuffer;
+ hNewEvent = (HANDLE) CallService(MS_DB_EVENT_ADD, (WPARAM) m_jobs[iFound].hOwner, (LPARAM) & dbei);
+
+ if (m_pContainer) {
+ if (!nen_options.iNoSounds && !(m_pContainer->dwFlags & CNT_NOSOUND))
+ SkinPlaySound("SendMsg");
+ }
+
+ if (dat && (m_jobs[iFound].hOwner == dat->hContact)) {
+ if (dat->hDbEventFirst == NULL) {
+ dat->hDbEventFirst = hNewEvent;
+ SendMessage(dat->hwnd, DM_REMAKELOG, 0, 0);
+ }
+ }
+
+ m_jobs[iFound].hSendId = NULL;
+ m_jobs[iFound].iAcksNeeded--;
+
+ if (m_jobs[iFound].iAcksNeeded == 0) { // everything sent
+ //if (m_jobs[iFound].hOwner != 0 && dat)
+ // EnableSending(dat, TRUE);
+ clearJob(iFound);
+ if (dat) {
+ KillTimer(dat->hwnd, TIMERID_MSGSEND + iFound);
+ dat->iOpenJobs--;
+ }
+ m_currentIndex--;
+ }
+ if (dat) {
+ checkQueue(dat);
+ if ((iNextFailed = findNextFailed(dat)) >= 0 && !(dat->dwFlags & MWF_ERRORSTATE))
+ handleError(dat, iNextFailed);
+ //MAD: close on send mode
+ else {
+ if (M->GetByte("AutoClose", 0)) {
+ if(M->GetByte("adv_AutoClose_2", 0))
+ SendMessage(dat->hwnd, WM_CLOSE, 0, 1);
+ else
+ SendMessage(dat->pContainer->hwnd, WM_CLOSE, 0, 0);
+ }
+ }
+ //MAD_
+ }
+ return 0;
+}
+
+LRESULT SendQueue::WarnPendingJobs(unsigned int uNrMessages)
+{
+ return(MessageBox(0, CTranslator::get(CTranslator::GEN_SQ_WARNING),
+ CTranslator::get(CTranslator::GEN_SQ_WARNING_TITLE), MB_YESNO | MB_ICONHAND));
+}
+
+/**
+ * This just adds the message to the database for later delivery and
+ * adds the contact to the list of contacts that have queued messages
+ *
+ * @param iJobIndex int: index of the send job
+ * dat: Message window data
+ * fAddHeader: add the "message was sent delayed" header (default = true)
+ * hContact : contact to which the job should be added (default = hOwner of the send job)
+ *
+ * @return the index on success, -1 on failure
+ */
+int SendQueue::doSendLater(int iJobIndex, TWindowData *dat, HANDLE hContact, bool fIsSendLater)
+{
+ bool fAvail = sendLater->isAvail();
+
+ const TCHAR *szNote = 0;
+
+ if(fIsSendLater && dat) {
+ if(fAvail)
+ szNote = CTranslator::get(CTranslator::GEN_SQ_QUEUED_MESSAGE);
+ else
+ szNote = CTranslator::get(CTranslator::GEN_SQ_QUEUING_NOT_AVAIL);
+
+ char *utfText = M->utf8_encodeT(szNote);
+ DBEVENTINFO dbei;
+ dbei.cbSize = sizeof(dbei);
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.flags = DBEF_SENT | DBEF_UTF;
+ dbei.szModule = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) dat->hContact, 0);
+ dbei.timestamp = time(NULL);
+ dbei.cbBlob = lstrlenA(utfText) + 1;
+ dbei.pBlob = (PBYTE) utfText;
+ StreamInEvents(dat->hwnd, 0, 1, 1, &dbei);
+ if (dat->hDbEventFirst == NULL)
+ SendMessage(dat->hwnd, DM_REMAKELOG, 0, 0);
+ dat->cache->saveHistory(0, 0);
+ EnableSendButton(dat, FALSE);
+ if (dat->pContainer->hwndActive == dat->hwnd)
+ UpdateReadChars(dat);
+ SendDlgItemMessage(dat->hwnd, IDC_SAVE, BM_SETIMAGE, IMAGE_ICON, (LPARAM) PluginConfig.g_buttonBarIcons[ICON_BUTTON_CANCEL]);
+ SendDlgItemMessage(dat->hwnd, IDC_SAVE, BUTTONADDTOOLTIP, (WPARAM)pszIDCSAVE_close, 0);
+ dat->dwFlags &= ~MWF_SAVEBTN_SAV;
+ mir_free(utfText);
+
+ if(!fAvail)
+ return(0);
+ }
+
+ if(iJobIndex >= 0 && iJobIndex < NR_SENDJOBS) {
+ SendJob* job = &m_jobs[iJobIndex];
+ char szKeyName[20];
+ TCHAR tszTimestamp[30], tszHeader[150];
+ time_t now = time(0);
+
+ if(fIsSendLater) {
+ TCHAR *formatTime = _T("%Y.%m.%d - %H:%M");
+ _tcsftime(tszTimestamp, 30, formatTime, _localtime32((__time32_t *)&now));
+ tszTimestamp[29] = 0;
+ mir_snprintf(szKeyName, 20, "S%d", now);
+ mir_sntprintf(tszHeader, safe_sizeof(tszHeader), CTranslator::get(CTranslator::GEN_SQ_SENDLATER_HEADER), tszTimestamp);
+ }
+ else
+ mir_sntprintf(tszHeader, safe_sizeof(tszHeader), _T("M%d|"), time(0));
+
+ if(job->dwFlags & PREF_UTF || !(job->dwFlags & PREF_UNICODE)) {
+ char *utf_header = M->utf8_encodeT(tszHeader);
+ UINT required = lstrlenA(utf_header) + lstrlenA(job->sendBuffer) + 10;
+ char *tszMsg = reinterpret_cast<char *>(mir_alloc(required));
+
+ if(fIsSendLater) {
+ mir_snprintf(tszMsg, required, "%s%s", job->sendBuffer, utf_header);
+ DBWriteContactSettingString(hContact ? hContact : job->hOwner, "SendLater", szKeyName, tszMsg);
+ }
+ else {
+ mir_snprintf(tszMsg, required, "%s%s", utf_header, job->sendBuffer);
+ sendLater->addJob(tszMsg, (LPARAM)hContact);
+ }
+ mir_free(utf_header);
+ mir_free(tszMsg);
+ }
+ else if(job->dwFlags & PREF_UNICODE) {
+ int iLen = lstrlenA(job->sendBuffer);
+ wchar_t *wszMsg = (wchar_t *)&job->sendBuffer[iLen + 1];
+
+ UINT required = sizeof(TCHAR) * (lstrlen(tszHeader) + lstrlenW(wszMsg) + 10);
+
+ TCHAR *tszMsg = reinterpret_cast<TCHAR *>(mir_alloc(required));
+ if(fIsSendLater)
+ mir_sntprintf(tszMsg, required, _T("%s%s"), wszMsg, tszHeader);
+ else
+ mir_sntprintf(tszMsg, required, _T("%s%s"), tszHeader, wszMsg);
+ char *utf = M->utf8_encodeT(tszMsg);
+ if(fIsSendLater)
+ DBWriteContactSettingString(hContact ? hContact : job->hOwner, "SendLater", szKeyName, utf);
+ else
+ sendLater->addJob(utf, (LPARAM)hContact);
+ mir_free(utf);
+ mir_free(tszMsg);
+ }
+ if(fIsSendLater) {
+ int iCount = M->GetDword(hContact ? hContact : job->hOwner, "SendLater", "count", 0);
+ iCount++;
+ M->WriteDword(hContact ? hContact : job->hOwner, "SendLater", "count", iCount);
+ sendLater->addContact(hContact ? hContact : job->hOwner);
+ }
+ return(iJobIndex);
+ }
+ return(-1);
+}
diff --git a/plugins/TabSRMM/src/sidebar.cpp b/plugins/TabSRMM/src/sidebar.cpp
new file mode 100644
index 0000000000..85dbf3e6c3
--- /dev/null
+++ b/plugins/TabSRMM/src/sidebar.cpp
@@ -0,0 +1,1232 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: sidebar.cpp 12647 2010-09-09 22:17:49Z silvercircle $
+ *
+ * the contact switch bar on the left (or right) side
+ *
+ */
+
+#include "commonheaders.h"
+
+extern int TSAPI TBStateConvert2Flat(int state);
+extern int TSAPI RBStateConvert2Flat(int state);
+extern void TSAPI FillTabBackground(const HDC hdc, int iStateId, const TWindowData* dat, RECT* rc);
+
+TSideBarLayout CSideBar::m_layouts[CSideBar::NR_LAYOUTS] = {
+ {
+ _T("Like tabs, vertical text orientation"),
+ 26, 30,
+ SIDEBARLAYOUT_DYNHEIGHT | SIDEBARLAYOUT_VERTICALORIENTATION,
+ CSideBar::m_DefaultContentRenderer,
+ CSideBar::m_DefaultBackgroundRenderer,
+ NULL,
+ NULL,
+ SIDEBARLAYOUT_VERTICAL
+ },
+ {
+ _T("Compact layout, horizontal buttons"),
+ 100, 24,
+ 0,
+ CSideBar::m_DefaultContentRenderer,
+ CSideBar::m_DefaultBackgroundRenderer,
+ NULL,
+ NULL,
+ SIDEBARLAYOUT_NORMAL
+ },
+ {
+ _T("Advanced layout with avatars"),
+ 140, 40,
+ SIDEBARLAYOUT_NOCLOSEBUTTONS,
+ CSideBar::m_AdvancedContentRenderer,
+ CSideBar::m_DefaultBackgroundRenderer,
+ NULL,
+ NULL,
+ SIDEBARLAYOUT_NORMAL
+ },
+ {
+ _T("Advanced with avatars, vertical orientation"),
+ 40, 40,
+ SIDEBARLAYOUT_DYNHEIGHT | SIDEBARLAYOUT_VERTICALORIENTATION | SIDEBARLAYOUT_NOCLOSEBUTTONS,
+ CSideBar::m_AdvancedContentRenderer,
+ CSideBar::m_DefaultBackgroundRenderer,
+ CSideBar::m_measureAdvancedVertical,
+ NULL,
+ SIDEBARLAYOUT_VERTICAL
+ }
+};
+
+CSideBarButton::CSideBarButton(const TWindowData *dat, CSideBar *sideBar)
+{
+ m_dat = dat;
+ m_id = reinterpret_cast<UINT>(dat->hContact); // set the control id
+ m_sideBar = sideBar;
+ _create();
+}
+
+CSideBarButton::CSideBarButton(const UINT id, CSideBar *sideBar)
+{
+ m_dat = 0;
+ m_id = id;
+ m_sideBar = sideBar;
+ _create();
+}
+
+/**
+ * Internal method to create the button item and configure the associated button control
+ */
+void CSideBarButton::_create()
+{
+ m_hwnd = 0;
+ m_isTopAligned = true;
+ m_sz.cx = m_sz.cy = 0;
+
+ m_hwnd = ::CreateWindowEx(0, _T("TSButtonClass"), _T(""), WS_CHILD | WS_TABSTOP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ 0, 0, 40, 40, m_sideBar->getScrollWnd(), reinterpret_cast<HMENU>(m_id), g_hInst, NULL);
+
+ if(m_hwnd) {
+ ::SendMessage(m_hwnd, BUTTONSETASSIDEBARBUTTON, 0, (LPARAM)this);
+ ::SendMessage(m_hwnd, BUTTONSETASFLATBTN, 1, 1);
+ ::SendMessage(m_hwnd, BUTTONSETASFLATBTN + 10, 1, 1);
+ ::SendMessage(m_hwnd, BUTTONSETASFLATBTN + 12, 0, (LPARAM)m_sideBar->getContainer());
+ m_buttonControl = (MButtonCtrl *)::GetWindowLongPtr(m_hwnd, 0);
+ }
+ else
+ delete this;
+
+ if(m_id == IDC_SIDEBARUP || m_id == IDC_SIDEBARDOWN)
+ ::SetParent(m_hwnd, m_sideBar->getContainer()->hwnd);
+}
+
+CSideBarButton::~CSideBarButton()
+{
+ if(m_hwnd) {
+ ::SendMessage(m_hwnd, BUTTONSETASSIDEBARBUTTON, 0, 0); // make sure, the button will no longer call us back
+ ::DestroyWindow(m_hwnd);
+ }
+}
+
+void CSideBarButton::Show(const int showCmd) const
+{
+ ::ShowWindow(m_hwnd, showCmd);
+}
+
+/**
+ * Measure the metrics for the current item. The side bar layouting will call this
+ * whenever a layout with a dynamic height is active). For fixed dimension layouts,
+ * m_elementWidth and m_elementHeight will be used.
+ *
+ * @return SIZE&: reference to the item's size member. The caller may use cx and cy values
+ * to determine further layouting actions.
+ */
+const SIZE& CSideBarButton::measureItem()
+{
+ SIZE sz;
+
+ if(m_sideBarLayout->pfnMeasureItem)
+ m_sideBarLayout->pfnMeasureItem(this); // use the current layout's function, if available, else use default
+ else {
+ HDC dc = ::GetDC(m_hwnd);
+ TCHAR tszLabel[255];
+
+ HFONT oldFont = reinterpret_cast<HFONT>(::SelectObject(dc, ::GetStockObject(DEFAULT_GUI_FONT)));
+
+ mir_sntprintf(tszLabel, 255, _T("%s"), m_dat->newtitle);
+ ::GetTextExtentPoint32(dc, tszLabel, lstrlen(tszLabel), &sz);
+
+ sz.cx += 28;
+ if(m_dat->pContainer->dwFlagsEx & TCF_CLOSEBUTTON)
+ sz.cx += 20;
+
+ if(m_sideBarLayout->dwFlags & CSideBar::SIDEBARLAYOUT_VERTICALORIENTATION)
+ m_sz.cy = sz.cx;
+ else
+ m_sz.cx = sz.cx;
+
+ ::SelectObject(dc, oldFont);
+ ::ReleaseDC(m_hwnd, dc);
+ }
+ return(m_sz);
+}
+/**
+ * Render the button item. Callback from the button window procedure
+ *
+ * @param ctl MButtonCtrl *: pointer to the private button data structure
+ * @param hdc HDC: device context for painting
+ */
+void CSideBarButton::RenderThis(const HDC hdc) const
+{
+ RECT rc;
+ LONG cx, cy;
+ HDC hdcMem = 0;
+ bool fVertical = (m_sideBarLayout->dwFlags & CSideBar::SIDEBARLAYOUT_VERTICALORIENTATION) ? true : false;
+ HBITMAP hbmMem, hbmOld;
+ HANDLE hbp = 0;
+
+ ::GetClientRect(m_hwnd, &rc);
+
+ if(m_id == IDC_SIDEBARUP || m_id == IDC_SIDEBARDOWN)
+ fVertical = false;
+
+ if(fVertical) {
+ cx = rc.bottom;
+ cy = rc.right;
+ }
+ else {
+ cx = rc.right;
+ cy = rc.bottom;
+ }
+
+ hdcMem = ::CreateCompatibleDC(hdc);
+
+ if(fVertical) {
+ RECT rcFlipped = {0,0,cx,cy};
+ hbmMem = CSkin::CreateAeroCompatibleBitmap(rcFlipped, hdcMem);
+ rc = rcFlipped;
+ }
+ else
+ hbmMem = CSkin::CreateAeroCompatibleBitmap(rc, hdcMem);
+
+ hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(hdcMem, hbmMem));
+
+ HFONT hFontOld = reinterpret_cast<HFONT>(::SelectObject(hdcMem, ::GetStockObject(DEFAULT_GUI_FONT)));
+
+ m_sideBarLayout->pfnBackgroundRenderer(hdcMem, &rc, this);
+ m_sideBarLayout->pfnContentRenderer(hdcMem, &rc, this);
+
+ ::SelectObject(hdcMem, hFontOld);
+
+ /*
+ * for vertical tabs, we did draw to a rotated rectangle, so we now must rotate the
+ * final bitmap back to it's original orientation
+ */
+
+ if(fVertical) {
+ ::SelectObject(hdcMem, hbmOld);
+
+ FIBITMAP *fib = FIF->FI_CreateDIBFromHBITMAP(hbmMem);
+ FIBITMAP *fib_new = FIF->FI_RotateClassic(fib, 90.0f);
+ FIF->FI_Unload(fib);
+ ::DeleteObject(hbmMem);
+ hbmMem = FIF->FI_CreateHBITMAPFromDIB(fib_new);
+ FIF->FI_Unload(fib_new);
+ hbmOld =reinterpret_cast<HBITMAP>(::SelectObject(hdcMem, hbmMem));
+ ::BitBlt(hdc, 0, 0, cy, cx, hdcMem, 0, 0, SRCCOPY);
+ ::SelectObject(hdcMem, hbmOld);
+ ::DeleteObject(hbmMem);
+ ::DeleteDC(hdcMem);
+ }
+ else {
+ ::BitBlt(hdc, 0, 0, cx, cy, hdcMem, 0, 0, SRCCOPY);
+ ::SelectObject(hdcMem, hbmOld);
+ ::DeleteObject(hbmMem);
+ ::DeleteDC(hdcMem);
+ }
+ return;
+}
+
+/**
+ * render basic button content like nickname and icon. Used for the basic layouts
+ * only. Pretty much the same code as used for the tabs.
+ *
+ * @param hdc : target device context
+ * @param rcItem : rectangle to render into
+ */
+void CSideBarButton::renderIconAndNick(const HDC hdc, const RECT *rcItem) const
+{
+ HICON hIcon;
+ RECT rc = *rcItem;
+ DWORD dwTextFlags = DT_SINGLELINE | DT_VCENTER;
+ int stateId = m_buttonControl->stateId;
+ int iSize = 16;
+ const TContainerData *pContainer = m_sideBar->getContainer();
+
+ if(m_dat && pContainer) {
+ hIcon = m_dat->cache->getIcon(iSize);
+
+ if (m_dat->mayFlashTab == FALSE || (m_dat->mayFlashTab == TRUE && m_dat->bTabFlash != 0) || !(pContainer->dwFlagsEx & TCF_FLASHICON)) {
+ DWORD ix = rc.left + 4;
+ DWORD iy = (rc.bottom + rc.top - iSize) / 2;
+ if (m_dat->dwFlagsEx & MWF_SHOW_ISIDLE && PluginConfig.m_IdleDetect)
+ CSkin::DrawDimmedIcon(hdc, ix, iy, iSize, iSize, hIcon, 180);
+ else
+ ::DrawIconEx(hdc, ix, iy, hIcon, iSize, iSize, 0, NULL, DI_NORMAL | DI_COMPAT);
+ }
+
+ rc.left += (iSize + 7);
+
+ /*
+ * draw the close button if enabled
+ */
+ if(m_sideBar->getContainer()->dwFlagsEx & TCF_CLOSEBUTTON) {
+ if(m_sideBar->getHoveredClose() != this)
+ CSkin::m_default_bf.SourceConstantAlpha = 150;
+
+ CMimAPI::m_MyAlphaBlend(hdc, rc.right - 20, (rc.bottom + rc.top - 16) / 2, 16, 16, CSkin::m_tabCloseHDC,
+ 0, 0, 16, 16, CSkin::m_default_bf);
+
+ rc.right -= 19;
+ CSkin::m_default_bf.SourceConstantAlpha = 255;
+ }
+
+ ::SetBkMode(hdc, TRANSPARENT);
+
+ if (m_dat->mayFlashTab == FALSE || (m_dat->mayFlashTab == TRUE && m_dat->bTabFlash != 0) || !(pContainer->dwFlagsEx & TCF_FLASHLABEL)) {
+ bool fIsActive = (m_sideBar->getActiveItem() == this ? true : false);
+ COLORREF clr = 0;
+ dwTextFlags |= DT_WORD_ELLIPSIS;
+
+ if (fIsActive || stateId == PBS_PRESSED)
+ clr = PluginConfig.tabConfig.colors[1];
+ else if (stateId == PBS_HOT)
+ clr = PluginConfig.tabConfig.colors[3];
+ else
+ clr = PluginConfig.tabConfig.colors[0];
+
+ CSkin::RenderText(hdc, m_buttonControl->hThemeButton, m_dat->newtitle, &rc, dwTextFlags, CSkin::m_glowSize, clr);
+ }
+ }
+}
+
+/**
+ * test if we have the mouse pointer over our close button.
+ * @return: 1 if the pointer is inside the button's rect, -1 otherwise
+ */
+int CSideBarButton::testCloseButton() const
+{
+ if(m_id == IDC_SIDEBARUP || m_id == IDC_SIDEBARDOWN) // scroller buttons don't have a close button
+ return(-1);
+
+ if(m_sideBar->getContainer()->dwFlagsEx & TCF_CLOSEBUTTON && !(getLayout()->dwFlags & CSideBar::SIDEBARLAYOUT_NOCLOSEBUTTONS)) {
+ POINT pt;
+ ::GetCursorPos(&pt);
+ ::ScreenToClient(m_hwnd, &pt);
+ RECT rc;
+
+ ::GetClientRect(m_hwnd, &rc);
+ if(getLayout()->dwFlags & CSideBar::SIDEBARLAYOUT_VERTICALORIENTATION) {
+ rc.bottom = rc.top + 18; rc.top += 2;
+ rc.left += 2; rc.right -= 2;
+ if(::PtInRect(&rc, pt))
+ return(1);
+ }
+ else {
+ rc.bottom -= 4; rc.top += 4;
+ rc.right -= 3; rc.left = rc.right - 16;
+ if(::PtInRect(&rc, pt))
+ return(1);
+ }
+ }
+ return(-1);
+}
+/**
+ * call back from the button window procedure. Activate my session
+ */
+void CSideBarButton::activateSession() const
+{
+ if(m_dat)
+ ::SendMessage(m_dat->hwnd, DM_ACTIVATEME, 0, 0); // the child window will activate itself
+}
+
+/**
+ * show the context menu (same as on tabs
+ */
+void CSideBarButton::invokeContextMenu()
+{
+ const TContainerData* pContainer = m_sideBar->getContainer();
+
+ if(pContainer) {
+ TSideBarNotify tsn = {0};
+ tsn.nmHdr.code = NM_RCLICK;
+ tsn.nmHdr.idFrom = 5000;
+ tsn.nmHdr.hwndFrom = ::GetDlgItem(pContainer->hwnd, 5000);
+ tsn.dat = m_dat;
+ ::SendMessage(pContainer->hwnd, WM_NOTIFY, 0, reinterpret_cast<LPARAM>(&tsn));
+ }
+}
+
+CSideBar::CSideBar(TContainerData *pContainer)
+{
+ m_pContainer = pContainer;
+ m_up = m_down = 0;
+ m_hwndScrollWnd = 0;
+ m_buttonlist.clear();
+ m_activeItem = 0;
+ m_isVisible = true;
+
+ Init(true);
+}
+
+CSideBar::~CSideBar()
+{
+ destroyScroller();
+ m_buttonlist.clear();
+
+ if(m_hwndScrollWnd)
+ ::DestroyWindow(m_hwndScrollWnd);
+}
+
+void CSideBar::Init(const bool fForce)
+{
+ m_iTopButtons = m_iBottomButtons = 0;
+ m_topHeight = m_bottomHeight = 0;
+ m_firstVisibleOffset = 0;
+ m_totalItemHeight = 0;
+
+ m_uLayout = (m_pContainer->dwFlagsEx & 0xff000000) >> 24;
+ m_uLayout = ((m_uLayout >= 0 && m_uLayout < NR_LAYOUTS) ? m_uLayout : 0);
+
+ m_currentLayout = &m_layouts[m_uLayout];
+
+ m_dwFlags = m_currentLayout->dwFlags;
+
+ m_dwFlags = (m_pContainer->dwFlagsEx & TCF_SBARLEFT ? m_dwFlags | SIDEBARORIENTATION_LEFT : m_dwFlags & ~SIDEBARORIENTATION_LEFT);
+ m_dwFlags = (m_pContainer->dwFlagsEx & TCF_SBARRIGHT ? m_dwFlags | SIDEBARORIENTATION_RIGHT : m_dwFlags & ~SIDEBARORIENTATION_RIGHT);
+
+ if(m_pContainer->dwFlags & CNT_SIDEBAR) {
+ if(m_hwndScrollWnd == 0)
+ m_hwndScrollWnd = ::CreateWindowEx(0, _T("TS_SideBarClass"), _T(""), WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE | WS_CHILD,
+ 0, 0, m_width, 40, m_pContainer->hwnd, reinterpret_cast<HMENU>(5000), g_hInst, this);
+
+ m_isActive = true;
+ m_isVisible = m_isActive ? m_isVisible : true;
+ createScroller();
+ m_elementHeight = m_currentLayout->height;
+ m_elementWidth = m_currentLayout->width;
+ m_width = m_elementWidth + 4;
+ populateAll();
+ if(m_activeItem)
+ setActiveItem(m_activeItem);
+ }
+ else {
+ destroyScroller();
+ m_width = 0;
+ m_isActive = m_isVisible = false;
+ m_activeItem = 0;
+
+ removeAll();
+ if(m_hwndScrollWnd)
+ ::DestroyWindow(m_hwndScrollWnd);
+ m_hwndScrollWnd = 0;
+ }
+}
+
+/**
+ * sets visibility status for the sidebar. An invisible sidebar (collapsed
+ * by the button in the message dialog) will remain active, it will, however
+ * not do any drawing or other things that are only visually important.
+ *
+ * @param fNewVisible : set the new visibility status
+ */
+void CSideBar::setVisible(bool fNewVisible)
+{
+ m_isVisible = fNewVisible;
+
+ /*
+ * only needed on hiding. Layout() will do it when showing it
+ */
+
+ if(!m_isVisible)
+ showAll(SW_HIDE);
+ else {
+ m_up->Show(SW_SHOW);
+ m_down->Show(SW_SHOW);
+ }
+}
+
+/**
+ * Create both scrollbar buttons which can be used to scroll the switchbar
+ * up and down.
+ */
+void CSideBar::createScroller()
+{
+ if(m_up == 0)
+ m_up = new CSideBarButton(IDC_SIDEBARUP, this);
+ if(m_down == 0)
+ m_down = new CSideBarButton(IDC_SIDEBARDOWN, this);
+
+ m_up->setLayout(m_currentLayout);
+ m_down->setLayout(m_currentLayout);
+}
+
+/**
+ * Destroy the scroller buttons.
+ */
+void CSideBar::destroyScroller()
+{
+ if(m_up) {
+ delete m_up;
+ m_up = 0;
+ }
+ if(m_down) {
+ delete m_down;
+ m_down = 0;
+ }
+}
+
+/**
+ * remove all buttons from the current list
+ * Does not remove the sessions. This is basically only used when switching
+ * from a sidebar to a tabbed interface
+ */
+void CSideBar::removeAll()
+{
+ ButtonIterator item = m_buttonlist.begin();
+
+ while(item != m_buttonlist.end()) {
+ delete *item;
+ item++;
+ }
+ m_buttonlist.clear();
+}
+
+/**
+ * popuplate the side bar with all sessions inside the current window. Information
+ * is gathered from the tab control, which remains active (but invisible) when the
+ * switch bar is in use.
+ *
+ * This is needed when the user switches from tabs to a switchbar layout while a
+ * window is open.
+ */
+void CSideBar::populateAll()
+{
+ HWND hwndTab = ::GetDlgItem(m_pContainer->hwnd, IDC_MSGTABS);
+
+ if(hwndTab) {
+ int iItems = (int)TabCtrl_GetItemCount(hwndTab);
+ TCITEM item = {0};
+
+ item.mask = TCIF_PARAM;
+ std::vector<CSideBarButton *>::iterator b_item;
+
+ m_iTopButtons = 0;
+
+ for(int i = 0; i < iItems; i++) {
+ TabCtrl_GetItem(hwndTab, i, &item);
+ if(item.lParam && ::IsWindow((HWND)item.lParam)) {
+ TWindowData *dat = (TWindowData *)::GetWindowLongPtr((HWND)item.lParam, GWLP_USERDATA);
+ if(dat) {
+ if((b_item = findSession(dat)) == m_buttonlist.end())
+ addSession(dat, i);
+ else {
+ (*b_item)->setLayout(m_currentLayout);
+ if(m_dwFlags & SIDEBARLAYOUT_VERTICALORIENTATION) {
+ (*b_item)->measureItem();
+ m_topHeight += ((*b_item)->getHeight() + 1);
+ }
+ else
+ m_topHeight += (m_elementHeight + 1);
+ }
+ }
+ }
+ }
+ }
+}
+/**
+ * Add a new session to the switchbar.
+ *
+ * @param dat _MessageWindowData *: session data for a client session. Must be fully initialized
+ * (that is, it can only be used after WM_INITIALOG completed).
+ * position: -1 = append, otherwise insert it at the given position
+ */
+void CSideBar::addSession(const TWindowData *dat, int position)
+{
+ if(!m_isActive)
+ return;
+
+ CSideBarButton *item = new CSideBarButton(dat, this);
+
+ item->setLayout(m_currentLayout);
+
+ if(m_dwFlags & SIDEBARLAYOUT_DYNHEIGHT) {
+ SIZE sz = item->measureItem();
+ m_topHeight += (sz.cy + 1);
+ }
+ else
+ m_topHeight += (m_elementHeight + 1);
+
+ m_iTopButtons++;
+ if(position == -1 || (size_t)position >= m_buttonlist.size())
+ m_buttonlist.push_back(item);
+ else {
+ ButtonIterator it = m_buttonlist.begin() + position;
+ m_buttonlist.insert(it, item);
+ }
+ SendDlgItemMessage(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_TOGGLESIDEBAR : IDC_CHAT_TOGGLESIDEBAR, BM_SETIMAGE, IMAGE_ICON,
+ (LPARAM)(m_dwFlags & SIDEBARORIENTATION_LEFT ? PluginConfig.g_buttonBarIcons[ICON_DEFAULT_LEFT] : PluginConfig.g_buttonBarIcons[ICON_DEFAULT_RIGHT]));
+
+ Invalidate();
+}
+
+/**
+ * Remove a new session from the switchbar.
+ *
+ * @param dat _MessageWindowData *: session data for a client session.
+ */
+HRESULT CSideBar::removeSession(const TWindowData *dat)
+{
+ if(dat) {
+ std::vector<CSideBarButton *>::iterator item = findSession(dat);
+
+ if(item != m_buttonlist.end()) {
+ m_iTopButtons--;
+ if(m_dwFlags & SIDEBARLAYOUT_DYNHEIGHT) {
+ SIZE sz = (*item)->getSize();
+ m_topHeight -= (sz.cy + 1);
+ }
+ else
+ m_topHeight -= (m_elementHeight + 1);
+ delete *item;
+ m_buttonlist.erase(item);
+ Invalidate();
+ return(S_OK);
+ }
+ }
+ return(S_FALSE);
+}
+
+/**
+ * make sure the given item is visible in a scrolled switch bar
+ *
+ * @param item CSideBarButtonItem*: the item which must be visible in the switch bar
+ */
+void CSideBar::scrollIntoView(const CSideBarButton *item)
+{
+ LONG spaceUsed = 0, itemHeight;
+ bool fNeedLayout = false;
+
+ if(!m_isActive)
+ return;
+
+ if(item == 0)
+ item = m_activeItem;
+
+ ButtonIterator it = m_buttonlist.begin();
+
+ while(it != m_buttonlist.end()) {
+ itemHeight = (*it)->getHeight();
+ spaceUsed += (itemHeight + 1);
+ if(*it == item )
+ break;
+ it++;
+ }
+
+ RECT rc;
+ GetClientRect(m_hwndScrollWnd, &rc);
+
+ if(m_topHeight <= rc.bottom) {
+ m_firstVisibleOffset = 0;
+ Layout();
+ return;
+ }
+ if(it == m_buttonlist.end() || (it == m_buttonlist.begin() && m_firstVisibleOffset == 0)) {
+ Layout();
+ return; // do nothing for the first item and .end() should not really happen
+ }
+
+ if(spaceUsed <= rc.bottom && spaceUsed - (itemHeight + 1) >= m_firstVisibleOffset) {
+ Layout();
+ return; // item fully visible, do nothing
+ }
+
+ /*
+ * button partially or not at all visible at the top
+ */
+ if(spaceUsed < m_firstVisibleOffset || spaceUsed - (itemHeight + 1) < m_firstVisibleOffset) {
+ m_firstVisibleOffset = spaceUsed - (itemHeight + 1);
+ fNeedLayout = true;
+ } else {
+ if(spaceUsed > rc.bottom) { // partially or not at all visible at the bottom
+ fNeedLayout = true;
+ m_firstVisibleOffset = spaceUsed - rc.bottom;
+ }
+ }
+
+ //if(fNeedLayout)
+ Layout();
+}
+/**
+ * Invalidate the button associated with the given session.
+ *
+ * @param dat _MessageWindowData*: Session data
+ */
+void CSideBar::updateSession(const TWindowData *dat)
+{
+ if(!m_isVisible || !m_isActive)
+ return;
+
+ ButtonIterator item = findSession(dat);
+ if(item != m_buttonlist.end()) {
+ if(m_dwFlags & SIDEBARLAYOUT_DYNHEIGHT) {
+ LONG oldHeight = (*item)->getHeight();
+ m_topHeight -= (oldHeight + 1);
+ SIZE sz = (*item)->measureItem();
+ m_topHeight += (sz.cy + 1);
+ if(sz.cy != oldHeight) {
+ Invalidate();
+ ::InvalidateRect((*item)->getHwnd(), NULL, TRUE);
+ }
+ else
+ ::InvalidateRect((*item)->getHwnd(), NULL, FALSE);
+ }
+ else
+ ::InvalidateRect((*item)->getHwnd(), NULL, FALSE);
+ }
+}
+
+/**
+ * Sets the active session item
+ * called from the global update handler in msgdialog/group room window
+ * on every tab activation to ensure consistency
+ *
+ * @param dat _MessageWindowData*: session data
+ *
+ * @return The previously active item (that can be zero)
+ */
+const CSideBarButton* CSideBar::setActiveItem(const TWindowData *dat)
+{
+ ButtonIterator item = findSession(dat);
+ if(item != m_buttonlist.end()) {
+ return(setActiveItem(*item));
+ }
+ return(0);
+}
+
+/**
+ * Layout the buttons within the available space... ensure that buttons are
+ * set to invisible if there is not enough space. Also, update the state of
+ * the scroller buttons
+ *
+ * @param rc RECT*:the window rectangle
+ *
+ * @param fOnlyCalc bool: if false (default), window positions will be updated, otherwise,
+ * the method will only calculate the layout parameters. A final call to
+ * Layout() with the parameter set to false is required to perform the
+ * position update.
+ */
+void CSideBar::Layout(const RECT *rc, bool fOnlyCalc)
+{
+ if(!m_isVisible)
+ return;
+
+ RECT rcWnd;
+
+ rc = &rcWnd;
+ ::GetClientRect(m_hwndScrollWnd, &rcWnd);
+
+ if(m_currentLayout->pfnLayout) {
+ m_currentLayout->pfnLayout(this, const_cast<RECT *>(rc));
+ return;
+ }
+
+ HDWP hdwp = ::BeginDeferWindowPos(1);
+
+ int topCount = 0, bottomCount = 0;
+ size_t i = 0, j = 0;
+ BOOL topEnabled = FALSE, bottomEnabled = FALSE;
+ HWND hwnd;
+ LONG spaceUsed = 0;
+ DWORD dwFlags = SWP_NOZORDER|SWP_NOACTIVATE;
+ LONG iSpaceAvail = rc->bottom;
+
+ m_firstVisibleOffset = max(0, m_firstVisibleOffset);
+
+ ButtonIterator item = m_buttonlist.begin();
+
+ m_totalItemHeight = 0;
+
+ LONG height = m_elementHeight;
+
+ while (item != m_buttonlist.end()) {
+ hwnd = (*item)->getHwnd();
+
+ if(m_dwFlags & SIDEBARLAYOUT_DYNHEIGHT)
+ height = (*item)->getHeight();
+
+ if(spaceUsed > iSpaceAvail || m_totalItemHeight + height < m_firstVisibleOffset) {
+ ::ShowWindow(hwnd, SW_HIDE);
+ item++;
+ m_totalItemHeight += (height + 1);
+ continue;
+ }
+
+ if ((*item)->isTopAligned()) {
+ if(m_totalItemHeight <= m_firstVisibleOffset) { // partially visible
+ if(!fOnlyCalc)
+ hdwp = ::DeferWindowPos(hdwp, hwnd, 0, 2, -(m_firstVisibleOffset - m_totalItemHeight),
+ m_elementWidth, height, SWP_SHOWWINDOW | dwFlags);
+ spaceUsed += ((height + 1) - (m_firstVisibleOffset - m_totalItemHeight));
+ m_totalItemHeight += (height + 1);
+ }
+ else {
+ if(!fOnlyCalc)
+ hdwp = ::DeferWindowPos(hdwp, hwnd, 0, 2, spaceUsed,
+ m_elementWidth, height, SWP_SHOWWINDOW | dwFlags);
+ spaceUsed += (height + 1);
+ m_totalItemHeight += (height + 1);
+ }
+ }/*
+ else {
+ }*/
+ item++;
+ }
+ topEnabled = m_firstVisibleOffset > 0;
+ bottomEnabled = (m_totalItemHeight - m_firstVisibleOffset > rc->bottom);
+ ::EndDeferWindowPos(hdwp);
+
+ //_DebugTraceA("layout: total %d, used: %d, first visible: %d", m_totalItemHeight, spaceUsed, m_firstVisibleOffset);
+ if(!fOnlyCalc) {
+ RECT rcContainer;
+ ::GetClientRect(m_pContainer->hwnd, &rcContainer);
+
+ LONG dx = m_dwFlags & SIDEBARORIENTATION_LEFT ? m_pContainer->tBorder_outer_left :
+ rcContainer.right - m_pContainer->tBorder_outer_right - (m_elementWidth + 4);
+
+ ::SetWindowPos(m_up->getHwnd(), 0, dx, m_pContainer->tBorder_outer_top + m_pContainer->MenuBar->getHeight(),
+ m_elementWidth + 4, 14, dwFlags | SWP_SHOWWINDOW);
+ ::SetWindowPos(m_down->getHwnd(), 0, dx, (rcContainer.bottom - 14 - m_pContainer->statusBarHeight - 1),
+ m_elementWidth + 4, 14, dwFlags | SWP_SHOWWINDOW);
+ ::EnableWindow(m_up->getHwnd(), topEnabled);
+ ::EnableWindow(m_down->getHwnd(), bottomEnabled);
+ ::InvalidateRect(m_up->getHwnd(), NULL, FALSE);
+ ::InvalidateRect(m_down->getHwnd(), NULL, FALSE);
+ }
+}
+
+inline void CSideBar::Invalidate()
+{
+ Layout(0);
+}
+
+void CSideBar::showAll(int showCmd)
+{
+ ::ShowWindow(m_up->getHwnd(), showCmd);
+ ::ShowWindow(m_down->getHwnd(), showCmd);
+
+ std::vector<CSideBarButton *>::iterator item = m_buttonlist.begin();
+
+ while(item != m_buttonlist.end())
+ ::ShowWindow((*item++)->getHwnd(), showCmd);
+}
+
+/**
+ * Helper function: find a button item associated to the given
+ * session data
+ *
+ * @param dat _MessageWindowData*: session information
+ *
+ * @return CSideBarButtonItem*: pointer to the found item. Zero, if none was found
+ */
+ButtonIterator CSideBar::findSession(const TWindowData *dat)
+{
+ if(dat) {
+ std::vector<CSideBarButton *>::iterator item = m_buttonlist.begin();
+
+ if(m_buttonlist.size() > 0) {
+ while(item != m_buttonlist.end()) {
+ if((*item)->getDat() == dat)
+ return(item);
+ item++;
+ }
+ }
+ }
+ return(m_buttonlist.end());
+}
+
+/**
+ * Helper function: find a button item associated to the given
+ * contact handle
+ *
+ * @param hContact HANDLE: contact's handle to look for
+ *
+ * @return CSideBarButtonItem*: pointer to the found item. Zero, if none was found
+ */
+ButtonIterator CSideBar::findSession(const HANDLE hContact)
+{
+ if(hContact) {
+ std::vector<CSideBarButton *>::iterator item = m_buttonlist.begin();
+
+ if(m_buttonlist.size() > 0) {
+ while(item != m_buttonlist.end()) {
+ if((*item)->getContactHandle() == hContact)
+ return(item);
+ item++;
+ }
+ }
+ }
+ return(m_buttonlist.end());
+}
+
+void CSideBar::processScrollerButtons(UINT commandID)
+{
+ if(!m_isActive || m_down == 0)
+ return;
+
+ if(commandID == IDC_SIDEBARDOWN && ::IsWindowEnabled(m_down->getHwnd()))
+ m_firstVisibleOffset += 10;
+ else if(commandID == IDC_SIDEBARUP && ::IsWindowEnabled(m_up->getHwnd()))
+ m_firstVisibleOffset = max(0, m_firstVisibleOffset - 10);
+
+ Layout(0);
+}
+
+void CSideBar::resizeScrollWnd(LONG x, LONG y, LONG width, LONG height) const
+{
+ if(!m_isVisible || !m_isActive) {
+ ::ShowWindow(m_hwndScrollWnd, SW_HIDE);
+ return;
+ }
+ ::SetWindowPos(m_hwndScrollWnd, 0, x, y + 15, m_width, height - 30,
+ SWP_NOCOPYBITS | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOSENDCHANGING | SWP_DEFERERASE | SWP_ASYNCWINDOWPOS);
+}
+
+void CSideBar::invalidateButton(const TWindowData* dat)
+{
+ if(m_isActive && m_isVisible) {
+ ButtonIterator it = findSession(dat);
+
+ if(it != this->m_buttonlist.end())
+ RedrawWindow((*it)->m_buttonControl->hwnd, 0, 0, RDW_INVALIDATE | RDW_UPDATENOW);
+ }
+}
+
+/**
+ * the window procedure for the sidebar container window (the window which
+ * acts as a parent for the actual buttons). itself, this window is a child
+ * of the container window.
+ */
+LRESULT CALLBACK CSideBar::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_SIZE:
+ return(TRUE);
+ case WM_ERASEBKGND: {
+ HDC hdc = (HDC)wParam;
+ RECT rc;
+ ::GetClientRect(hwnd, &rc);
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item = &SkinItems[ID_EXTBKSIDEBARBG];
+
+ if(item->IGNORED)
+ CSkin::SkinDrawBG(hwnd, m_pContainer->hwnd, m_pContainer, &rc, hdc);
+ else
+ CSkin::DrawItem(hdc, &rc, item);
+ }
+ else if (M->isAero() || M->isVSThemed()) {
+ HDC hdcMem;
+ HANDLE hbp = 0;
+ HBITMAP hbm, hbmOld;
+
+ if(CMimAPI::m_haveBufferedPaint)
+ hbp = CSkin::InitiateBufferedPaint(hdc, rc, hdcMem);
+ else {
+ hdcMem = ::CreateCompatibleDC(hdc);
+ hbm = CSkin::CreateAeroCompatibleBitmap(rc, hdcMem);
+ hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(hdcMem, hbm));
+ }
+
+ if(M->isAero())
+ ::FillRect(hdcMem, &rc, CSkin::m_BrushBack);
+ else
+ CSkin::FillBack(hdcMem, &rc);
+
+ if(hbp)
+ CSkin::FinalizeBufferedPaint(hbp, &rc);
+ else {
+ ::BitBlt(hdc, 0, 0, rc.right, rc.bottom, hdcMem, 0, 0, SRCCOPY);
+ ::SelectObject(hdcMem, hbmOld);
+ ::DeleteObject(hbm);
+ ::DeleteDC(hdcMem);
+ }
+ }
+ else
+ ::FillRect(hdc, &rc, ::GetSysColorBrush(COLOR_3DFACE));
+ return(1);
+ }
+ default:
+ break;
+ }
+ return(DefWindowProc(hwnd, msg, wParam, lParam));
+}
+
+LRESULT CALLBACK CSideBar::wndProcStub(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CSideBar *sideBar = (CSideBar *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ if(sideBar)
+ return(sideBar->wndProc(hwnd, msg, wParam, lParam));
+
+ switch(msg) {
+ case WM_NCCREATE: {
+ CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)cs->lpCreateParams);
+ return(TRUE);
+ }
+ default:
+ break;
+ }
+ return(::DefWindowProc(hwnd, msg, wParam, lParam));
+}
+/**
+ * paints the background for a switchbar item. It can paint aero, visual styles, skins or
+ * classic buttons (depending on os and current plugin settings).
+ *
+ * @param hdc HDC: target device context
+ * @param rc RECT*: target rectangle
+ * @param stateId the state identifier (normal, pressed, hot, disabled etc.)
+ */
+void __fastcall CSideBar::m_DefaultBackgroundRenderer(const HDC hdc, const RECT *rc,
+ const CSideBarButton *item)
+{
+ UINT id = item->getID();
+ int stateId = item->m_buttonControl->stateId;
+ bool fIsActiveItem = (item->m_sideBar->getActiveItem() == item);
+
+ if(CSkin::m_skinEnabled) {
+ TContainerData* pContainer = const_cast<TContainerData *>(item->m_sideBar->getContainer());
+ int id = stateId == PBS_PRESSED || fIsActiveItem ? ID_EXTBKBUTTONSPRESSED : (stateId == PBS_HOT ? ID_EXTBKBUTTONSMOUSEOVER : ID_EXTBKBUTTONSNPRESSED);
+ CSkinItem* skinItem = &SkinItems[id];
+ HWND hwnd;
+
+ if(id == IDC_SIDEBARUP)
+ hwnd = item->m_sideBar->getScrollUp()->m_buttonControl->hwnd;
+ else if(id == IDC_SIDEBARDOWN)
+ hwnd = item->m_sideBar->getScrollDown()->m_buttonControl->hwnd;
+ else
+ hwnd = item->m_buttonControl->hwnd;
+
+ CSkin::SkinDrawBG(hwnd, pContainer->hwnd, pContainer, const_cast<RECT *>(rc), hdc);
+ CSkin::DrawItem(hdc, rc, skinItem);
+ }
+ else if(M->isAero() || PluginConfig.m_fillColor) {
+ if(id == IDC_SIDEBARUP || id == IDC_SIDEBARDOWN) {
+ if(M->isAero())
+ ::FillRect(hdc, const_cast<RECT *>(rc), CSkin::m_BrushBack);
+ else
+ CSkin::FillBack(hdc, const_cast<RECT *>(rc));
+
+ if(stateId == PBS_HOT || stateId == PBS_PRESSED)
+ DrawAlpha(hdc, const_cast<RECT *>(rc), 0xf0f0f0, 70, 0x000000, 0, 9,
+ 31, 4, 0);
+ else
+ DrawAlpha(hdc, const_cast<RECT *>(rc), 0xf0f0f0, 30, 0x707070, 0, 9,
+ 31, 4, 0);
+ }
+ else {
+ if(PluginConfig.m_fillColor)
+ FillTabBackground(hdc, stateId, item->getDat(), const_cast<RECT *>(rc));
+
+ CSkin::m_switchBarItem->setAlphaFormat(AC_SRC_ALPHA,
+ (stateId == PBS_HOT && !fIsActiveItem) ? 250 : (fIsActiveItem || stateId == PBS_PRESSED ? 250 : 230));
+ CSkin::m_switchBarItem->Render(hdc, rc, true);
+ if(stateId == PBS_HOT || stateId == PBS_PRESSED || fIsActiveItem) {
+ RECT rcGlow = *rc;
+ rcGlow.top += 1;
+ rcGlow.bottom -= 2;
+
+ CSkin::m_tabGlowTop->setAlphaFormat(AC_SRC_ALPHA, (stateId == PBS_PRESSED || fIsActiveItem) ? 180 : 100);
+ CSkin::m_tabGlowTop->Render(hdc, &rcGlow, true);
+ }
+ }
+ }
+ else if(M->isVSThemed()) {
+ RECT *rcDraw = const_cast<RECT *>(rc);
+ if(id == IDC_SIDEBARUP || id == IDC_SIDEBARDOWN) {
+ ::FillRect(hdc, rc, stateId == PBS_HOT ? ::GetSysColorBrush(COLOR_HOTLIGHT) : ::GetSysColorBrush(COLOR_3DFACE));
+ ::InflateRect(rcDraw, -2, 0);
+ ::DrawEdge(hdc, rcDraw, EDGE_ETCHED, BF_SOFT|BF_RECT|BF_FLAT);
+ }
+ else {
+ CSkin::FillBack(hdc, rcDraw);
+
+ if(CMimAPI::m_pfnIsThemeBackgroundPartiallyTransparent(item->m_buttonControl->hThemeToolbar, TP_BUTTON, stateId))
+ CMimAPI::m_pfnDrawThemeParentBackground(item->getHwnd(), hdc, rcDraw);
+
+ if(M->isAero() || PluginConfig.m_WinVerMajor >= 6) {
+ stateId = (fIsActiveItem ? PBS_PRESSED : PBS_HOT);
+ CMimAPI::m_pfnDrawThemeBackground(item->m_buttonControl->hThemeToolbar, hdc, 8, RBStateConvert2Flat(stateId), rcDraw, rcDraw);
+ }
+ else {
+ stateId = (fIsActiveItem ? PBS_PRESSED : PBS_HOT);
+ CMimAPI::m_pfnDrawThemeBackground(item->m_buttonControl->hThemeToolbar, hdc, TP_BUTTON, TBStateConvert2Flat(stateId), rcDraw, rcDraw);
+ }
+ }
+ }
+ else {
+ RECT *rcDraw = const_cast<RECT *>(rc);
+ if(!(id == IDC_SIDEBARUP || id == IDC_SIDEBARDOWN)) {
+ HBRUSH br = (stateId == PBS_HOT && !fIsActiveItem) ? ::GetSysColorBrush(COLOR_BTNSHADOW) : (fIsActiveItem || stateId == PBS_PRESSED ? ::GetSysColorBrush(COLOR_HOTLIGHT) : ::GetSysColorBrush(COLOR_3DFACE));
+ ::FillRect(hdc, rc, br);
+ ::DrawEdge(hdc, rcDraw, (stateId == PBS_HOT && !fIsActiveItem) ? EDGE_ETCHED : (fIsActiveItem || stateId == PBS_PRESSED) ? EDGE_BUMP : EDGE_ETCHED, BF_RECT | BF_SOFT | BF_FLAT);
+ }
+ else {
+ ::FillRect(hdc, rc, stateId == PBS_HOT ? ::GetSysColorBrush(COLOR_HOTLIGHT) : ::GetSysColorBrush(COLOR_3DFACE));
+ ::InflateRect(rcDraw, -2, 0);
+ ::DrawEdge(hdc, rcDraw, EDGE_ETCHED, BF_SOFT|BF_RECT|BF_FLAT);
+ }
+ }
+}
+
+void __fastcall CSideBar::m_DefaultContentRenderer(const HDC hdc, const RECT *rcBox,
+ const CSideBarButton *item)
+{
+ UINT id = item->getID();
+ const TWindowData* dat = item->getDat();
+ int stateID = item->m_buttonControl->stateId;
+
+ LONG cx = rcBox->right - rcBox->left;
+ LONG cy = rcBox->bottom - rcBox->top;
+
+ if(id == IDC_SIDEBARUP || id == IDC_SIDEBARDOWN) {
+ ::DrawIconEx(hdc, (rcBox->left + rcBox->right) / 2 - 8, (rcBox->top + rcBox->bottom) / 2 - 8, id == IDC_SIDEBARUP ? PluginConfig.g_buttonBarIcons[26] : PluginConfig.g_buttonBarIcons[16],
+ 16, 16, 0, 0, DI_NORMAL);
+ if(!M->isAero() && stateID == PBS_HOT)
+ ::DrawEdge(hdc, const_cast<RECT *>(rcBox), BDR_INNER, BF_RECT | BF_SOFT | BF_FLAT);
+ }
+ else if(dat)
+ item->renderIconAndNick(hdc, rcBox);
+}
+
+/**
+ * content renderer for the advanced side bar button layout. includes
+ * avatars
+ */
+void __fastcall CSideBar::m_AdvancedContentRenderer(const HDC hdc, const RECT *rcBox,
+ const CSideBarButton *item)
+{
+ UINT id = item->getID();
+ const TWindowData* dat = item->getDat();
+ int stateID = item->m_buttonControl->stateId;
+
+ LONG cx = rcBox->right - rcBox->left;
+ LONG cy = rcBox->bottom - rcBox->top;
+ SIZE szFirstLine, szSecondLine;
+
+ if(id == IDC_SIDEBARUP || id == IDC_SIDEBARDOWN)
+ m_DefaultContentRenderer(hdc, rcBox, item);
+ else if(dat) {
+ RECT rc = *rcBox;
+
+ if(dat->ace && dat->ace->hbmPic) { // we have an avatar
+ double dNewHeight, dNewWidth;
+ LONG maxHeight = cy - 8;
+ bool fFree = false;
+
+ Utils::scaleAvatarHeightLimited(dat->ace->hbmPic, dNewWidth, dNewHeight, maxHeight);
+
+ HBITMAP hbmResized = CSkin::ResizeBitmap(dat->ace->hbmPic, dNewWidth, dNewHeight, fFree);
+ HDC dc = CreateCompatibleDC(hdc);
+ HBITMAP hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(dc, hbmResized));
+
+ LONG xOff = (cx - maxHeight) + (maxHeight - (LONG)dNewWidth) / 2 - 4;
+ LONG yOff = (cy - (LONG)dNewHeight) / 2;
+
+ CMimAPI::m_MyAlphaBlend(hdc, xOff, yOff, (LONG)dNewWidth, (LONG)dNewHeight, dc, 0, 0, (LONG)dNewWidth, (LONG)dNewHeight, CSkin::m_default_bf);
+ ::SelectObject(dc, hbmOld);
+ if(hbmResized != dat->ace->hbmPic)
+ ::DeleteObject(hbmResized);
+ ::DeleteDC(dc);
+ rc.right -= (maxHeight + 6);
+ }
+
+ /*
+ * calculate metrics based on font configuration. Determine if we have enough
+ * space for both lines
+ */
+
+ rc.left += 3;
+ HFONT hOldFont = reinterpret_cast<HFONT>(::SelectObject(hdc, CInfoPanel::m_ipConfig.hFonts[IPFONTID_NICK]));
+ ::GetTextExtentPoint32A(hdc, "A", 1, &szFirstLine);
+ ::SelectObject(hdc, CInfoPanel::m_ipConfig.hFonts[IPFONTID_STATUS]);
+ ::GetTextExtentPoint32A(hdc, "A", 1, &szSecondLine);
+ szSecondLine.cy = max(szSecondLine.cy, 18);
+
+ LONG required = szFirstLine.cy + szSecondLine.cy;
+ bool fSecondLine = (required < cy ? true : false);
+
+ DWORD dtFlags = DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | (!fSecondLine ? DT_VCENTER : 0);
+
+ ::SelectObject(hdc, CInfoPanel::m_ipConfig.hFonts[IPFONTID_NICK]);
+ rc.top++;
+ ::SetBkMode(hdc, TRANSPARENT);
+ CSkin::RenderText(hdc, dat->hThemeIP, dat->cache->getNick(), &rc,
+ dtFlags, CSkin::m_glowSize, CInfoPanel::m_ipConfig.clrs[IPFONTID_NICK]);
+
+ if(fSecondLine) {
+ int iSize;
+ HICON hIcon = dat->cache->getIcon(iSize);
+
+ /*
+ * TODO support larger icons at a later time. This side bar button
+ * could use 32x32 icons as well.
+ */
+
+ rc.top = rc.bottom - szSecondLine.cy - 2;
+ ::DrawIconEx(hdc, rc.left, rc.top + (rc.bottom - rc.top) / 2 - 8, hIcon, 16, 16, 0, 0, DI_NORMAL);
+ rc.left += 18;
+ ::SelectObject(hdc, CInfoPanel::m_ipConfig.hFonts[IPFONTID_STATUS]);
+ CSkin::RenderText(hdc, dat->hThemeIP, dat->szStatus, &rc,
+ dtFlags | DT_VCENTER, CSkin::m_glowSize, CInfoPanel::m_ipConfig.clrs[IPFONTID_STATUS]);
+ }
+ ::SelectObject(hdc, hOldFont);
+ }
+}
+
+/**
+ * measure callback for the advanced sidebar button layout (vertical mode
+ * with variable height buttons)
+ */
+const SIZE& __fastcall CSideBar::m_measureAdvancedVertical(CSideBarButton* item)
+{
+ const TWindowData* dat = item->getDat();
+
+ SIZE sz = {0};
+
+ if(dat) {
+ SIZE szFirstLine, szSecondLine;
+
+ if(dat->ace && dat->ace->hbmPic)
+ sz.cy = item->getLayout()->width;
+
+ HDC dc = ::GetDC(dat->hwnd);
+
+ HFONT hOldFont = reinterpret_cast<HFONT>(::SelectObject(dc, CInfoPanel::m_ipConfig.hFonts[IPFONTID_NICK]));
+ ::GetTextExtentPoint32(dc, dat->cache->getNick(), lstrlen(dat->cache->getNick()), &szFirstLine);
+ ::SelectObject(dc, CInfoPanel::m_ipConfig.hFonts[IPFONTID_STATUS]);
+ ::GetTextExtentPoint32(dc, dat->szStatus, lstrlen(dat->szStatus), &szSecondLine);
+ ::SelectObject(dc, hOldFont);
+ ReleaseDC(dat->hwnd, dc);
+
+ szSecondLine.cx += 18; // icon space
+
+ sz.cy += max(szFirstLine.cx + 4, szSecondLine.cx + 4);
+ sz.cy += 2;
+ }
+ item->setSize(sz);
+ return(item->getSize());
+}
diff --git a/plugins/TabSRMM/src/srmm.cpp b/plugins/TabSRMM/src/srmm.cpp
new file mode 100644
index 0000000000..60af12edfd
--- /dev/null
+++ b/plugins/TabSRMM/src/srmm.cpp
@@ -0,0 +1,316 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: srmm.cpp 13596 2011-04-15 19:07:23Z george.hazan $
+ *
+ * plugin loading functions and global exports.
+ *
+ */
+
+#include "commonheaders.h"
+
+extern int LoadSendRecvMessageModule(void);
+extern int SplitmsgShutdown(void);
+extern void LogErrorMessage(HWND hwndDlg, struct TWindowData *dat, int i, TCHAR *szMsg);
+extern int Chat_Load(PLUGINLINK *link), Chat_Unload();
+extern void FreeLogFonts();
+
+PLUGINLINK *pluginLink;
+HINSTANCE g_hInst;
+LOGFONT lfDefault = {0};
+
+/*
+ * miranda interfaces
+ */
+
+struct LIST_INTERFACE li;
+struct MM_INTERFACE mmi;
+int hLangpack;
+TIME_API tmi = {0};
+
+PLUGININFOEX pluginInfo = {
+ sizeof(PLUGININFOEX),
+#ifdef __GNUWIN32__
+ "TabSRMM (MINGW32)",
+#else
+#ifdef _WIN64
+ "TabSRMM (x64, Unicode)",
+#else
+#ifdef _UNICODE
+ "TabSRMM (Unicode)",
+#else
+ "TabSRMM",
+#endif
+#endif
+#endif
+ PLUGIN_MAKE_VERSION(_VER_MAJOR, _VER_MINOR, _VER_REVISION, _VER_BUILD),
+ "IM and group chat module for Miranda IM.",
+ "The Miranda developers team and contributors",
+ "silvercircle _at_ gmail _dot_ com",
+ "2000-2010 Miranda Project and contributors. See readme.txt for more.",
+ "http://miranda.or.at",
+ UNICODE_AWARE,
+ DEFMOD_SRMESSAGE, // replace internal version (if any)
+ {0x6ca5f042, 0x7a7f, 0x47cc, { 0xa7, 0x15, 0xfc, 0x8c, 0x46, 0xfb, 0xf4, 0x34 }} //{6CA5F042-7A7F-47cc-A715-FC8C46FBF434}
+};
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ g_hInst = hinstDLL;
+ return TRUE;
+}
+
+extern "C" __declspec(dllexport) PLUGININFOEX *MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ CMimAPI::m_MimVersion = mirandaVersion;
+
+ if(WinVerMajor() < 5) {
+ MessageBox(0, _T("This version of tabSRMM requires Windows 2000 or later."), _T("tabSRMM"), MB_OK | MB_ICONERROR);
+ return(0);
+ }
+ if (mirandaVersion < PLUGIN_MAKE_VERSION(0, 8, 6, 0)) {
+ MessageBox(0, _T("This version of tabSRMM requires Miranda 0.8.5 or later. The plugin cannot be loaded."), _T("tabSRMM"), MB_OK | MB_ICONERROR);
+ return(0);
+ }
+ return &pluginInfo;
+}
+
+static const MUUID interfaces[] = {MIID_SRMM, MIID_CHAT, MIID_LAST};
+
+extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
+{
+ return interfaces;
+}
+
+extern "C" int __declspec(dllexport) Load(PLUGINLINK * link)
+{
+ pluginLink = link;
+
+ mir_getMMI(&mmi);
+ mir_getLI(&li);
+ mir_getTMI(&tmi);
+ mir_getLP(&pluginInfo);
+
+ CTranslator::preTranslateAll();
+
+ M = new CMimAPI();
+
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfDefault), &lfDefault, FALSE);
+
+ Chat_Load(pluginLink);
+
+ return LoadSendRecvMessageModule();
+}
+
+extern "C" int __declspec(dllexport) Unload(void)
+{
+ int iRet;
+#if defined(__USE_EX_HANDLERS)
+ __try {
+#endif
+ FreeLogFonts();
+ Chat_Unload();
+ iRet = SplitmsgShutdown();
+ Skin->setupTabCloseBitmap(true);
+ Skin->UnloadAeroTabs();
+ CleanTempFiles();
+ delete Skin;
+ DestroyServiceFunction(hTypingNotify);
+ delete sendLater;
+ delete sendQueue;
+ delete M;
+#if defined(__USE_EX_HANDLERS)
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"SHUTDOWN_STAGE_UNLOAD", false)) {
+ return(0);
+ }
+#endif
+ return iRet;
+}
+
+int _DebugTraceW(const wchar_t *fmt, ...)
+{
+ wchar_t debug[2048];
+ int ibsize = 2047;
+ SYSTEMTIME st;
+ va_list va;
+ char tszTime[50];
+ va_start(va, fmt);
+
+ GetLocalTime(&st);
+
+ mir_snprintf(tszTime, 50, "%02d.%02d.%04d - %02d:%02d:%02d.%04d: ", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
+
+
+ _vsnwprintf(debug, ibsize - 10, fmt, va);
+//#ifdef _DEBUG
+ OutputDebugStringW(debug);
+//#else
+ {
+ char szLogFileName[MAX_PATH], szDataPath[MAX_PATH];
+ FILE *f;
+
+ CallService(MS_DB_GETPROFILEPATH, MAX_PATH, (LPARAM)szDataPath);
+ mir_snprintf(szLogFileName, MAX_PATH, "%s\\%s", szDataPath, "tabsrmm_debug.log");
+ f = fopen(szLogFileName, "a+");
+ if (f) {
+ char *szDebug = M->utf8_encodeW(debug);
+ fputs(tszTime, f);
+ fputs(szDebug, f);
+ fputs("\n", f);
+ fclose(f);
+ if (szDebug)
+ mir_free(szDebug);
+ }
+ }
+//#endif
+ return 0;
+}
+
+int _DebugTraceA(const char *fmt, ...)
+{
+ char debug[2048];
+ int ibsize = 2047;
+ va_list va;
+ va_start(va, fmt);
+
+ lstrcpyA(debug, "TABSRMM: ");
+ _vsnprintf(&debug[9], ibsize - 10, fmt, va);
+#ifdef _DEBUG
+ OutputDebugStringA(debug);
+#else
+ {
+ char szLogFileName[MAX_PATH], szDataPath[MAX_PATH];
+ FILE *f;
+
+ CallService(MS_DB_GETPROFILEPATH, MAX_PATH, (LPARAM)szDataPath);
+ mir_snprintf(szLogFileName, MAX_PATH, "%s\\%s", szDataPath, "tabsrmm_debug.log");
+ f = fopen(szLogFileName, "a+");
+ if (f) {
+ fputs(debug, f);
+ fputs("\n", f);
+ fclose(f);
+ }
+ }
+#endif
+ return 0;
+}
+
+/*
+ * output a notification message.
+ * may accept a hContact to include the contacts nickname in the notification message...
+ * the actual message is using printf() rules for formatting and passing the arguments...
+ *
+ * can display the message either as systray notification (baloon popup) or using the
+ * popup plugin.
+ */
+
+int _DebugPopup(HANDLE hContact, const TCHAR *fmt, ...)
+{
+ va_list va;
+ TCHAR debug[1024];
+ int ibsize = 1023;
+
+ va_start(va, fmt);
+ _vsntprintf(debug, ibsize, fmt, va);
+
+ if (ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
+ MIRANDASYSTRAYNOTIFY tn;
+ TCHAR szTitle[128];
+
+ tn.szProto = NULL;
+ tn.cbSize = sizeof(tn);
+ mir_sntprintf(szTitle, safe_sizeof(szTitle), TranslateT("tabSRMM Message (%s)"), (hContact != 0) ? (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR) : TranslateT("Global"));
+ tn.tszInfoTitle = szTitle;
+ tn.tszInfo = debug;
+ tn.dwInfoFlags = NIIF_INFO;
+ tn.dwInfoFlags |= NIIF_INTERN_UNICODE;
+ tn.uTimeout = 1000 * 4;
+ CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM) & tn);
+ }
+ return 0;
+}
+
+INT_PTR CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ COLORREF url_visited = RGB(128, 0, 128);
+ COLORREF url_unvisited = RGB(0, 0, 255);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ char str[64];
+ TCHAR tStr[80];
+ char szVersion[512], *found = NULL, buildstr[50] = "";
+ UINT build_nr = 0;
+ DWORD v = pluginInfo.version;
+
+ mir_snprintf(str, sizeof(str), Translate("Built %s %s"), __DATE__, __TIME__);
+ SetDlgItemTextA(hwndDlg, IDC_BUILDTIME, str);
+
+ CallService(MS_SYSTEM_GETVERSIONTEXT, 500, (LPARAM)szVersion);
+ if ((found = strchr(szVersion, '#')) != NULL) {
+ build_nr = atoi(found + 1);
+ mir_snprintf(buildstr, 50, "[Build #%d]", build_nr);
+ }
+ TCHAR *szBuildstr = mir_a2t(buildstr);
+ mir_sntprintf(tStr, safe_sizeof(tStr), _T("TabSRMM\n%s %d.%d.%d.%d (Unicode) %s"),
+ _T("Version"), HIBYTE(HIWORD(v)), LOBYTE(HIWORD(v)), HIBYTE(LOWORD(v)), LOBYTE(LOWORD(v)),
+ szBuildstr);
+ SetDlgItemText(hwndDlg, IDC_HEADERBAR, tStr);
+ mir_free(szBuildstr);
+ }
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE));
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(SKINICON_EVENT_MESSAGE));
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_SUPPORT:
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://miranda.or.at/");
+ break;
+ case IDC_RESETWARNINGS:
+ M->WriteDword(SRMSGMOD_T, "cWarningsL", 0);
+ M->WriteDword(SRMSGMOD_T, "cWarningsH", 0);
+ break;
+ }
+ break;
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ SetTextColor((HDC)wParam, RGB(60, 60, 150));
+ SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
+ return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
+ default:
+ break;
+ }
+ return FALSE;
+}
diff --git a/plugins/TabSRMM/src/tabctrl.cpp b/plugins/TabSRMM/src/tabctrl.cpp
new file mode 100644
index 0000000000..2aadbd91f5
--- /dev/null
+++ b/plugins/TabSRMM/src/tabctrl.cpp
@@ -0,0 +1,1592 @@
+/* astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: tabctrl.cpp 12643 2010-09-09 03:57:16Z silvercircle $
+ *
+ * a custom tab control, skinable, aero support, single/multi row, button
+ * tabs support, proper rendering for bottom row tabs and more.
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+static WNDPROC OldTabControlClassProc;
+extern ButtonSet g_ButtonSet;
+
+static LRESULT CALLBACK TabControlSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+#define FIXED_TAB_SIZE 100
+
+/*
+ * register the new tab control as a window class (TSTabCtrlClass)
+ */
+
+int TSAPI RegisterTabCtrlClass(void)
+{
+ WNDCLASSEXA wc;
+ WNDCLASSEX wce;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = "TSTabCtrlClass";
+ wc.lpfnWndProc = TabControlSubclassProc;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(struct TabControlData *);
+ wc.hbrBackground = 0;
+ wc.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_PARENTDC;
+ RegisterClassExA(&wc);
+
+ ZeroMemory(&wce, sizeof(wce));
+ wce.cbSize = sizeof(wce);
+ wce.lpszClassName = _T("TSStatusBarClass");
+ wce.lpfnWndProc = StatusBarSubclassProc;
+ wce.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wce.cbWndExtra = sizeof(void*);
+ wce.hbrBackground = 0;
+ wce.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_PARENTDC;
+ RegisterClassEx(&wce);
+
+ ZeroMemory(&wce, sizeof(wce));
+ wce.cbSize = sizeof(wce);
+ wce.lpszClassName = _T("TS_SideBarClass");
+ wce.lpfnWndProc = CSideBar::wndProcStub;;
+ wce.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wce.cbWndExtra = sizeof(void*);
+ wce.hbrBackground = 0;
+ wce.style = CS_GLOBALCLASS;// | CS_DBLCLKS; // | CS_PARENTDC;
+ RegisterClassEx(&wce);
+
+ ZeroMemory(&wce, sizeof(wce));
+ wce.cbSize = sizeof(wce);
+ wce.lpszClassName = _T("TSHK");
+ wce.lpfnWndProc = HotkeyHandlerDlgProc;
+ wce.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wce.cbWndExtra = sizeof(void*);
+ wce.hbrBackground = 0;
+ wce.style = CS_GLOBALCLASS;// | CS_DBLCLKS; // | CS_PARENTDC;
+ RegisterClassEx(&wce);
+
+ return 0;
+}
+
+static int TabCtrl_TestForCloseButton(const TabControlData *tabdat, HWND hwnd, POINT& pt)
+{
+ TCHITTESTINFO tci = {0};
+ tci.pt.x = pt.x;
+ tci.pt.y = pt.y;
+ int iTab;
+
+ ScreenToClient(hwnd, &tci.pt);
+ iTab = TabCtrl_HitTest(hwnd, &tci);
+ if(iTab != -1) {
+ RECT rcTab;
+
+ if(tci.flags & TCHT_NOWHERE)
+ return(-1);
+
+ TabCtrl_GetItemRect(hwnd, iTab, &rcTab);
+ if(tabdat->dwStyle & TCS_BUTTONS) {
+ rcTab.right -= 1;
+ rcTab.left = rcTab.right - 18;
+ }
+ else {
+ rcTab.left = rcTab.right - 18;
+ rcTab.right -= 5;
+ }
+ rcTab.bottom -= 4;
+ rcTab.top += 4;
+ if(PtInRect(&rcTab, tci.pt))
+ return(iTab);
+ }
+ return(-1);
+}
+
+/*
+ * tabctrl helper function
+ * Finds leftmost down item.
+ */
+
+static UINT FindLeftDownItem(HWND hwnd)
+{
+ RECT rctLeft = {100000, 0, 0, 0}, rctCur;
+ int nCount = TabCtrl_GetItemCount(hwnd) - 1;
+ UINT nItem = 0;
+ int i;
+
+ for (i = 0;i < nCount;i++) {
+ TabCtrl_GetItemRect(hwnd, i, &rctCur);
+ if (rctCur.left > 0 && rctCur.left <= rctLeft.left) {
+ if (rctCur.bottom > rctLeft.bottom) {
+ rctLeft = rctCur;
+ nItem = i;
+ }
+ }
+ }
+ return nItem;
+}
+
+/*
+ * tab control color definitions, including the database setting key names
+ */
+
+static struct colOptions {
+ UINT defclr;
+ char *szKey;
+ char *szSkinnedKey;
+} tabcolors[] = {
+ COLOR_BTNTEXT, "tab_txt_normal", "S_tab_txt_normal",
+ COLOR_BTNTEXT, "tab_txt_active", "S_tab_txt_active",
+ COLOR_HOTLIGHT, "tab_txt_hottrack", "S_tab_txt_hottrack",
+ COLOR_HOTLIGHT, "tab_txt_unread", "S_tab_txt_unread",
+ COLOR_3DFACE, "tab_bg_normal", "tab_bg_normal",
+ COLOR_3DFACE, "tab_bg_active", "tab_bg_active",
+ COLOR_3DFACE, "tab_bg_hottrack", "tab_bg_hottrack",
+ COLOR_3DFACE, "tab_bg_unread", "tab_bg_unread",
+ 0, 0, NULL, NULL
+};
+
+/*
+ * hints for drawing functions
+ */
+
+#define HINT_ACTIVATE_RIGHT_SIDE 1
+#define HINT_ACTIVE_ITEM 2
+#define FLOAT_ITEM_HEIGHT_SHIFT 2
+#define ACTIVE_ITEM_HEIGHT_SHIFT 2
+#define SHIFT_FROM_CUT_TO_SPIN 4
+#define HINT_TRANSPARENT 16
+#define HINT_HOTTRACK 32
+
+static void TSAPI DrawCustomTabPage(HDC hdc, RECT& rcClient)
+{
+ HBRUSH brOld = reinterpret_cast<HBRUSH>(::SelectObject(hdc, CSkin::m_BrushFill));
+ HPEN hPen = ::CreatePen(PS_SOLID, 1, PluginConfig.m_cRichBorders);
+ HPEN hPenOld = reinterpret_cast<HPEN>(::SelectObject(hdc, hPen));
+ ::Rectangle(hdc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
+ ::SelectObject(hdc, hPenOld);
+ ::SelectObject(hdc, brOld);
+ ::DeleteObject(hPen);
+}
+
+void TSAPI FillTabBackground(const HDC hdc, int iStateId, const TWindowData* dat, RECT* rc)
+{
+ unsigned clrIndex;
+
+ if(dat && dat->mayFlashTab)
+ clrIndex = 7;
+ else
+ clrIndex = (iStateId == PBS_PRESSED ? 5 : (iStateId == PBS_HOT ? 6 : 4));
+
+ if(PluginConfig.tabConfig.colors[clrIndex] != PluginConfig.m_fillColor)
+ FillRect(hdc, rc, PluginConfig.tabConfig.m_brushes[clrIndex - 4]);
+ else
+ CSkin::FillBack(hdc, rc);
+}
+
+/*
+ * draws the item contents (icon and label)
+ * it obtains the label and icon handle directly from the message window data
+ * no image list is used and necessary, the message window dialog procedure has to provide a valid
+ * icon handle in dat->hTabIcon
+ */
+
+static void DrawItem(TabControlData *tabdat, HDC dc, RECT *rcItem, int nHint, int nItem, TWindowData* dat)
+{
+ int iSize = 16;
+ DWORD dwTextFlags = DT_SINGLELINE | DT_VCENTER/* | DT_NOPREFIX*/;
+ BOOL leftMost = FALSE;
+
+ if (dat) {
+ HICON hIcon;
+ COLORREF clr = 0;
+ HFONT oldFont;
+ DWORD dwStyle = tabdat->dwStyle;
+ int oldMode = 0;
+ unsigned clrIndex = 0;
+
+ InflateRect(rcItem, -2, -2);
+
+ if(dat->mayFlashTab)
+ clrIndex = 3;
+ else
+ clrIndex = (nHint & HINT_ACTIVE_ITEM ? 1 : (nHint & HINT_HOTTRACK ? 2 : 0));
+
+ clr = PluginConfig.tabConfig.colors[clrIndex];
+
+ oldMode = SetBkMode(dc, TRANSPARENT);
+
+ if (!(dwStyle & TCS_BOTTOM))
+ OffsetRect(rcItem, 0, 1);
+
+ if (dat->dwFlags & MWF_ERRORSTATE)
+ hIcon = PluginConfig.g_iconErr;
+ else if (dat->mayFlashTab)
+ hIcon = dat->iFlashIcon;
+ else {
+ if (dat->si && dat->iFlashIcon) {
+ int sizeX, sizeY;
+
+ hIcon = dat->iFlashIcon;
+ Utils::getIconSize(hIcon, sizeX, sizeY);
+ iSize = sizeX;
+ } else if (dat->hTabIcon == dat->hTabStatusIcon && dat->hXStatusIcon)
+ hIcon = dat->hXStatusIcon;
+ else
+ hIcon = dat->hTabIcon;
+ }
+
+
+ if (dat->mayFlashTab == FALSE || (dat->mayFlashTab == TRUE && dat->bTabFlash != 0) || !(dat->pContainer->dwFlagsEx & TCF_FLASHICON)) {
+ DWORD ix = rcItem->left + tabdat->m_xpad - 1;
+ DWORD iy = (rcItem->bottom + rcItem->top - iSize) / 2;
+ if (dat->dwFlagsEx & MWF_SHOW_ISIDLE && PluginConfig.m_IdleDetect)
+ CSkin::DrawDimmedIcon(dc, ix, iy, iSize, iSize, hIcon, 180);
+ else
+ DrawIconEx(dc, ix, iy, hIcon, iSize, iSize, 0, NULL, DI_NORMAL | DI_COMPAT);
+ }
+
+ rcItem->left += (iSize + 2 + tabdat->m_xpad);
+
+ if(tabdat->fCloseButton) {
+ if(tabdat->iHoveredCloseIcon != nItem)
+ CSkin::m_default_bf.SourceConstantAlpha = 150;
+
+ CMimAPI::m_MyAlphaBlend(dc, rcItem->right - 16 - tabdat->m_xpad, (rcItem->bottom + rcItem->top - 16) / 2, 16, 16, CSkin::m_tabCloseHDC,
+ 0, 0, 16, 16, CSkin::m_default_bf);
+
+ rcItem->right -= (18 + tabdat->m_xpad);
+ CSkin::m_default_bf.SourceConstantAlpha = 255;
+ }
+
+ if (dat->mayFlashTab == FALSE || (dat->mayFlashTab == TRUE && dat->bTabFlash != 0) || !(dat->pContainer->dwFlagsEx & TCF_FLASHLABEL)) {
+ oldFont = (HFONT)SelectObject(dc, (HFONT)SendMessage(tabdat->hwnd, WM_GETFONT, 0, 0));
+ if (tabdat->dwStyle & TCS_BUTTONS || !(tabdat->dwStyle & TCS_MULTILINE)) { // || (tabdat->m_moderntabs && leftMost)) {
+ rcItem->right -= tabdat->m_xpad;
+ dwTextFlags |= DT_WORD_ELLIPSIS;
+ }
+ CSkin::RenderText(dc, dwStyle & TCS_BUTTONS ? tabdat->hThemeButton : tabdat->hTheme, dat->newtitle, rcItem, dwTextFlags, CSkin::m_glowSize, clr);
+ SelectObject(dc, oldFont);
+ }
+ if (oldMode)
+ SetBkMode(dc, oldMode);
+ }
+}
+
+/*
+ * draws the item rect (the "tab") in *classic* style (no visual themes
+ */
+
+static RECT rcTabPage = {0};
+
+static void DrawItemRect(struct TabControlData *tabdat, HDC dc, RECT *rcItem, int nHint, int iItem, const TWindowData* dat)
+{
+ POINT pt;
+ DWORD dwStyle = tabdat->dwStyle;
+
+ rcItem->bottom -= 1;
+ if (rcItem->left >= 0) {
+
+ /*
+ * draw "button style" tabs... raised edge for hottracked, sunken edge for active (pushed)
+ * otherwise, they get a normal border
+ */
+
+ if (dwStyle & TCS_BUTTONS) {
+ BOOL bClassicDraw = (tabdat->m_VisualStyles == FALSE);
+
+ // draw frame controls for button or bottom tabs
+ if (dwStyle & TCS_BOTTOM)
+ rcItem->top++;
+
+ rcItem->right += 6;
+ if(tabdat->fAeroTabs) {
+ if(M->isAero()) {
+ InflateRect(rcItem, 2, 0);
+ FillRect(dc, rcItem, CSkin::m_BrushBack);
+ }
+ else if(dat) {
+ int iStateId = (nHint & HINT_ACTIVE_ITEM ? PBS_PRESSED : 0) | (nHint & HINT_HOTTRACK ? PBS_HOT : 0);
+
+ InflateRect(rcItem, 1, 0);
+ FillTabBackground(dc, iStateId, dat, rcItem);
+ }
+ CSkin::m_switchBarItem->setAlphaFormat(AC_SRC_ALPHA, nHint & HINT_ACTIVE_ITEM ? 255 : 200);
+ CSkin::m_switchBarItem->Render(dc, rcItem, true);
+
+
+ if(nHint & HINT_ACTIVE_ITEM || nHint & HINT_HOTTRACK) {
+ RECT rcGlow = *rcItem;
+
+ if(dwStyle & TCS_BOTTOM)
+ rcGlow.top++;
+ else
+ rcGlow.bottom--;
+
+ tabdat->helperGlowItem->setAlphaFormat(AC_SRC_ALPHA, nHint & HINT_ACTIVE_ITEM ? 200 : 150);
+ tabdat->helperGlowItem->Render(dc, &rcGlow, true);
+ }
+ }
+ else if(bClassicDraw) {
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item = nHint & HINT_ACTIVE_ITEM ? &SkinItems[ID_EXTBKBUTTONSPRESSED] : (nHint & HINT_HOTTRACK ? &SkinItems[ID_EXTBKBUTTONSMOUSEOVER] : &SkinItems[ID_EXTBKBUTTONSNPRESSED]);
+
+ if (!item->IGNORED) {
+ CSkin::SkinDrawBG(tabdat->hwnd, tabdat->pContainer->hwnd, tabdat->pContainer, rcItem, dc);
+ CSkin::DrawItem(dc, rcItem, item);
+ } else
+ goto b_nonskinned;
+ } else {
+b_nonskinned:
+ if (nHint & HINT_ACTIVE_ITEM)
+ DrawEdge(dc, rcItem, EDGE_ETCHED, BF_RECT | BF_SOFT);
+ else if (nHint & HINT_HOTTRACK)
+ DrawEdge(dc, rcItem, EDGE_BUMP, BF_RECT | BF_MONO | BF_SOFT);
+ else
+ DrawEdge(dc, rcItem, EDGE_RAISED, BF_RECT | BF_SOFT);
+ }
+ } else {
+ if(M->isAero() && !(dwStyle & TCS_BOTTOM))
+ FillRect(dc, rcItem, CSkin::m_BrushBack);
+ else
+ CSkin::FillBack(dc, rcItem);
+ CMimAPI::m_pfnDrawThemeBackground(tabdat->hThemeButton, dc, 1, nHint & HINT_ACTIVE_ITEM ? 3 : (nHint & HINT_HOTTRACK ? 2 : 1), rcItem, rcItem);
+ }
+ return;
+ }
+ SelectObject(dc, PluginConfig.tabConfig.m_hPenLight);
+
+ if (nHint & HINT_ACTIVE_ITEM) {
+ if (dwStyle & TCS_BOTTOM) {
+ if (!CSkin::m_skinEnabled)
+ CSkin::FillBack(dc, rcItem);
+ rcItem->bottom += 2;
+ } else {
+ rcItem->bottom += 2;
+ if (!CSkin::m_skinEnabled)
+ CSkin::FillBack(dc, rcItem);
+ rcItem->bottom--;
+ rcItem->top -= 2;
+ }
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item = &SkinItems[dwStyle & TCS_BOTTOM ? ID_EXTBKTABITEMACTIVEBOTTOM : ID_EXTBKTABITEMACTIVE];
+ if (!item->IGNORED) {
+ rcItem->left += item->MARGIN_LEFT;
+ rcItem->right -= item->MARGIN_RIGHT;
+ rcItem->top += item->MARGIN_TOP;
+ rcItem->bottom -= item->MARGIN_BOTTOM;
+ CSkin::DrawItem(dc, rcItem, item);
+ return;
+ }
+ }
+ }
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item = &SkinItems[dwStyle & TCS_BOTTOM ? (nHint & HINT_HOTTRACK ? ID_EXTBKTABITEMHOTTRACKBOTTOM : ID_EXTBKTABITEMBOTTOM) :
+ (nHint & HINT_HOTTRACK ? ID_EXTBKTABITEMHOTTRACK : ID_EXTBKTABITEM)];
+ if (!item->IGNORED) {
+ if (dwStyle & TCS_BOTTOM)
+ rcItem->top = (rcItem->top > rcTabPage.bottom + 5) ? --rcItem->top : rcItem->top;
+ else
+ rcItem->bottom++;
+ //rcItem->bottom = (rcItem->bottom < rcTabPage.top - 5) ? ++rcItem->bottom : rcItem->bottom;
+
+ rcItem->left += item->MARGIN_LEFT;
+ rcItem->right -= item->MARGIN_RIGHT;
+ CSkin::DrawItem(dc, rcItem, item);
+ return;
+ }
+ }
+ if (dwStyle & TCS_BOTTOM) {
+ MoveToEx(dc, rcItem->left, rcItem->top - (nHint & HINT_ACTIVE_ITEM ? 1 : 0), &pt);
+ LineTo(dc, rcItem->left, rcItem->bottom - 2);
+ LineTo(dc, rcItem->left + 2, rcItem->bottom);
+ SelectObject(dc, PluginConfig.tabConfig.m_hPenShadow);
+ LineTo(dc, rcItem->right - 3, rcItem->bottom);
+
+ LineTo(dc, rcItem->right - 1, rcItem->bottom - 2);
+ LineTo(dc, rcItem->right - 1, rcItem->top - 1);
+ MoveToEx(dc, rcItem->right - 2, rcItem->top, &pt);
+ SelectObject(dc, PluginConfig.tabConfig.m_hPenItemShadow);
+ LineTo(dc, rcItem->right - 2, rcItem->bottom - 1);
+ MoveToEx(dc, rcItem->right - 3, rcItem->bottom - 1, &pt);
+ LineTo(dc, rcItem->left + 2, rcItem->bottom - 1);
+ } else {
+ MoveToEx(dc, rcItem->left, rcItem->bottom, &pt);
+ LineTo(dc, rcItem->left, rcItem->top + 2);
+ LineTo(dc, rcItem->left + 2, rcItem->top);
+ LineTo(dc, rcItem->right - 2, rcItem->top);
+ SelectObject(dc, PluginConfig.tabConfig.m_hPenItemShadow);
+
+ MoveToEx(dc, rcItem->right - 2, rcItem->top + 1, &pt);
+ LineTo(dc, rcItem->right - 2, rcItem->bottom + 1);
+ SelectObject(dc, PluginConfig.tabConfig.m_hPenShadow);
+ MoveToEx(dc, rcItem->right - 1, rcItem->top + 2, &pt);
+ LineTo(dc, rcItem->right - 1, rcItem->bottom + 1);
+ }
+ }
+}
+
+static int DWordAlign(int n)
+{
+ int rem = n % 4;
+ if (rem)
+ n += (4 - rem);
+ return n;
+}
+
+static HRESULT DrawThemesPartWithAero(const TabControlData *tabdat, HDC hDC, int iPartId, int iStateId, LPRECT prcBox, TWindowData* dat)
+{
+ HRESULT hResult = 0;
+ bool fAero = M->isAero();
+
+ if(tabdat->fAeroTabs) {
+ if(tabdat->dwStyle & TCS_BOTTOM)
+ prcBox->top += (fAero ? 2 : iStateId == PBS_PRESSED ? (M->isVSThemed() ? 1 : -1) : 0);
+ else if (!fAero)
+ prcBox->bottom -= (iStateId == PBS_PRESSED ? (M->isVSThemed() ? 1 : -1) : 0);
+
+ if(fAero)
+ FillRect(hDC, prcBox, CSkin::m_BrushBack);
+ else if(dat)
+ FillTabBackground(hDC, iStateId, dat, prcBox);
+
+ tabdat->helperItem->setAlphaFormat(AC_SRC_ALPHA, iStateId == PBS_PRESSED ? 255 : (fAero ? 240 : 255));
+ tabdat->helperItem->Render(hDC, prcBox, true);
+ tabdat->helperGlowItem->setAlphaFormat(AC_SRC_ALPHA, iStateId == PBS_PRESSED ? 220 : 180);
+
+ if(iStateId != PBS_NORMAL)
+ tabdat->helperGlowItem->Render(hDC, prcBox, true);
+ }
+ else if(CMimAPI::m_pfnDrawThemeBackground) {
+ if (tabdat->hTheme != 0)
+ hResult = CMimAPI::m_pfnDrawThemeBackground(tabdat->hTheme, hDC, iPartId, iStateId, prcBox, NULL);
+ }
+
+ return hResult;
+}
+/*
+ * draws a theme part (identifier in uiPartNameID) using the given clipping rectangle
+ */
+
+static HRESULT DrawThemesPart(const TabControlData *tabdat, HDC hDC, int iPartId, int iStateId, LPRECT prcBox)
+{
+ HRESULT hResult = 0;
+
+ if (CMimAPI::m_pfnDrawThemeBackground == 0)
+ return 0;
+
+ if (tabdat->hTheme != 0)
+ hResult = CMimAPI::m_pfnDrawThemeBackground(tabdat->hTheme, hDC, iPartId, iStateId, prcBox, NULL);
+
+ return hResult;
+}
+
+/*
+ * draw a themed tab item. either a tab or the body pane
+ * handles image mirroring for tabs at the bottom
+ */
+
+static void DrawThemesXpTabItem(HDC pDC, int ixItem, RECT *rcItem, UINT uiFlag, struct TabControlData *tabdat, TWindowData* dat)
+{
+ BOOL bBody = (uiFlag & 1) ? TRUE : FALSE;
+ BOOL bSel = (uiFlag & 2) ? TRUE : FALSE;
+ BOOL bHot = (uiFlag & 4) ? TRUE : FALSE;
+ BOOL bBottom = (uiFlag & 8) ? TRUE : FALSE; // mirror
+ SIZE szBmp;
+ HDC dcMem;
+ HBITMAP bmpMem, pBmpOld;
+ RECT rcMem;
+ BITMAPINFO biOut;
+ BITMAPINFOHEADER *bihOut;
+ int nBmpWdtPS;
+ int nSzBuffPS;
+ LPBYTE pcImg = NULL, pcImg1 = NULL;
+ int nStart = 0, nLenSub = 0;
+ szBmp.cx = rcItem->right - rcItem->left;
+ szBmp.cy = rcItem->bottom - rcItem->top;
+
+ /*
+ * for top row tabs, it's easy. Just draw to the provided dc (it's a mem dc already)
+ */
+
+ if (!bBottom) {
+ if (bBody) {
+ if(PluginConfig.m_bIsVista) {
+ rcItem->right += 2; // hide right tab sheet shadow (only draw the actual border line)
+ rcItem->bottom += 1;
+ }
+ DrawThemesPart(tabdat, pDC, 9, 0, rcItem); // TABP_PANE id = 9
+ } else {
+ int iStateId = bSel ? 3 : (bHot ? 2 : 1); // leftmost item has different part id
+ DrawThemesPartWithAero(tabdat, pDC, rcItem->left < 20 ? 2 : 1, iStateId, rcItem, dat);
+ }
+ return;
+ }
+ else if(tabdat->fAeroTabs && !bBody) {
+ int iStateId = bSel ? 3 : (bHot ? 2 : 1); // leftmost item has different part id
+ DrawThemesPartWithAero(tabdat, pDC, rcItem->left < 20 ? 2 : 1, iStateId, rcItem, dat);
+ return;
+ }
+
+ /*
+ * remaining code is for bottom tabs only.
+ */
+
+ dcMem = CreateCompatibleDC(pDC);
+ bmpMem = CreateCompatibleBitmap(pDC, szBmp.cx, szBmp.cy);
+
+ pBmpOld = (HBITMAP)SelectObject(dcMem, bmpMem);
+
+ rcMem.left = rcMem.top = 0;
+ rcMem.right = szBmp.cx;
+ rcMem.bottom = szBmp.cy;
+
+ ZeroMemory(&biOut, sizeof(BITMAPINFO)); // Fill local pixel arrays
+ bihOut = &biOut.bmiHeader;
+
+ bihOut->biSize = sizeof(BITMAPINFOHEADER);
+ bihOut->biCompression = BI_RGB;
+ bihOut->biPlanes = 1;
+ bihOut->biBitCount = 24; // force as RGB: 3 bytes, 24 bits
+ bihOut->biWidth = szBmp.cx;
+ bihOut->biHeight = szBmp.cy;
+
+ nBmpWdtPS = DWordAlign(szBmp.cx * 3);
+ nSzBuffPS = ((nBmpWdtPS * szBmp.cy) / 8 + 2) * 8;
+
+ /*
+ * blit the background to the memory dc, so that transparent tabs will draw properly
+ * for bottom tabs, it's more complex, because the background part must not be mirrored
+ * the body part does not need that (filling with the background color is much faster
+ * and sufficient for the tab "page" part.
+ */
+
+ if (!bSel)
+ CSkin::FillBack(dcMem, &rcMem);
+ else {
+ /*
+ * mirror the background horizontally for bottom selected tabs (they can overwrite others)
+ * needed, because after drawing the theme part the images will again be mirrored
+ * to "flip" the tab item.
+ */
+ BitBlt(dcMem, 0, 0, szBmp.cx, szBmp.cy, pDC, rcItem->left, rcItem->top, SRCCOPY);
+
+ pcImg1 = (BYTE *)mir_alloc(nSzBuffPS);
+
+ if (pcImg1) {
+ GetDIBits(pDC, bmpMem, nStart, szBmp.cy - nLenSub, pcImg1, &biOut, DIB_RGB_COLORS);
+ bihOut->biHeight = -szBmp.cy; // to mirror bitmap is eough to use negative height between Get/SetDIBits
+ SetDIBits(pDC, bmpMem, nStart, szBmp.cy - nLenSub, pcImg1, &biOut, DIB_RGB_COLORS);
+ mir_free(pcImg1);
+ }
+ }
+
+ /*
+ * body may be *large* so rotating the final image can be very slow.
+ * workaround: draw the skin item (tab pane) into a small dc, rotate this (small) image and render
+ * it to the final DC with the IMG_RenderItem() routine.
+ */
+
+ if (bBody) {
+ HDC hdcTemp = CreateCompatibleDC(pDC);
+ HBITMAP hbmTemp = CreateCompatibleBitmap(pDC, 100, 50);
+ HBITMAP hbmTempOld = (HBITMAP)SelectObject(hdcTemp, hbmTemp);
+ RECT rcTemp = {0};
+
+ rcTemp.right = 100;
+ rcTemp.bottom = 50;
+
+ bihOut->biWidth = 100;
+ bihOut->biHeight = 50;
+
+ nBmpWdtPS = DWordAlign(100 * 3);
+ nSzBuffPS = ((nBmpWdtPS * 50) / 8 + 2) * 8;
+
+ CSkin::FillBack(hdcTemp, &rcTemp);
+ DrawThemesPart(tabdat, hdcTemp, 9, 0, &rcTemp); // TABP_PANE id = 9
+ pcImg = (BYTE *)mir_alloc(nSzBuffPS);
+ if (pcImg) { // get bits:
+ GetDIBits(hdcTemp, hbmTemp, nStart, 50 - nLenSub, pcImg, &biOut, DIB_RGB_COLORS);
+ bihOut->biHeight = -50;
+ SetDIBits(hdcTemp, hbmTemp, nStart, 50 - nLenSub, pcImg, &biOut, DIB_RGB_COLORS);
+ mir_free(pcImg);
+ }
+ CImageItem tempItem(10, 10, 10, 10, hdcTemp, 0, IMAGE_FLAG_DIVIDED | IMAGE_FILLSOLID,
+ GetSysColorBrush(COLOR_3DFACE), 255, 30, 80, 50, 100);
+
+ if(PluginConfig.m_bIsVista) { // hide right tab sheet shadow (only draw the actual border line)
+ rcItem->right += 2;
+ }
+
+ tempItem.Render(pDC, rcItem, true);
+ tempItem.Clear();
+ SelectObject(hdcTemp, hbmTempOld);
+ DeleteObject(hbmTemp);
+ DeleteDC(hdcTemp);
+
+ SelectObject(dcMem, pBmpOld);
+ DeleteObject(bmpMem);
+ DeleteDC(dcMem);
+ return;
+ } else {
+ int iStateId = bSel ? 3 : (bHot ? 2 : 1);
+ DrawThemesPart(tabdat, dcMem, rcItem->left < 20 ? 2 : 1, iStateId, &rcMem);
+ }
+
+ bihOut->biHeight = szBmp.cy;
+ pcImg = (BYTE *)mir_alloc(nSzBuffPS);
+
+ if (pcImg) { // get bits:
+ GetDIBits(pDC, bmpMem, nStart, szBmp.cy - nLenSub, pcImg, &biOut, DIB_RGB_COLORS);
+ bihOut->biHeight = -szBmp.cy;
+ SetDIBits(pDC, bmpMem, nStart, szBmp.cy - nLenSub, pcImg, &biOut, DIB_RGB_COLORS);
+ mir_free(pcImg);
+ }
+
+ /*
+ * finally, blit the result to the destination dc
+ */
+
+ BitBlt(pDC, rcItem->left, rcItem->top, szBmp.cx, szBmp.cy, dcMem, 0, 0, SRCCOPY);
+ SelectObject(dcMem, pBmpOld);
+ DeleteObject(bmpMem);
+ DeleteDC(dcMem);
+}
+
+static POINT ptMouseT = {0};
+
+static LRESULT CALLBACK TabControlSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct TabControlData *tabdat = 0;
+
+ tabdat = (struct TabControlData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (tabdat) {
+ if (tabdat->pContainer == NULL)
+ tabdat->pContainer = (TContainerData *)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
+ tabdat->dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ }
+
+ switch (msg) {
+ case WM_NCCREATE: {
+ WNDCLASSEXA wcl = {0};
+
+ wcl.cbSize = sizeof(wcl);
+ GetClassInfoExA(g_hInst, "SysTabControl32", &wcl);
+
+ tabdat = (struct TabControlData *)mir_alloc(sizeof(struct TabControlData));
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)tabdat);
+ ZeroMemory((void *)tabdat, sizeof(struct TabControlData));
+ tabdat->hwnd = hwnd;
+ tabdat->cx = GetSystemMetrics(SM_CXSMICON);
+ tabdat->cy = GetSystemMetrics(SM_CYSMICON);
+ tabdat->fTipActive = FALSE;
+ tabdat->iHoveredCloseIcon = -1;
+ SendMessage(hwnd, EM_THEMECHANGED, 0, 0);
+ OldTabControlClassProc = wcl.lpfnWndProc;
+ return TRUE;
+ }
+ case EM_THEMECHANGED:
+ tabdat->m_xpad = M->GetByte("x-pad", 3);
+ tabdat->m_VisualStyles = FALSE;
+ if (PluginConfig.m_bIsXP && M->isVSAPIState()) {
+ if (CMimAPI::m_pfnIsThemeActive != 0)
+ if (CMimAPI::m_pfnIsThemeActive()) {
+ tabdat->m_VisualStyles = TRUE;
+ if (tabdat->hTheme != 0 && CMimAPI::m_pfnCloseThemeData != 0) {
+ CMimAPI::m_pfnCloseThemeData(tabdat->hTheme);
+ CMimAPI::m_pfnCloseThemeData(tabdat->hThemeButton);
+ }
+ if (CMimAPI::m_pfnOpenThemeData != 0) {
+ if ((tabdat->hTheme = CMimAPI::m_pfnOpenThemeData(hwnd, L"TAB")) == 0 || (tabdat->hThemeButton = CMimAPI::m_pfnOpenThemeData(hwnd, L"BUTTON")) == 0)
+ tabdat->m_VisualStyles = FALSE;
+ }
+ }
+ }
+ return 0;
+ case EM_SEARCHSCROLLER: {
+ HWND hwndChild;
+ /*
+ * search the updown control (scroll arrows) to subclass it...
+ * the control is dynamically created and may not exist as long as it is
+ * not needed. So we have to search it everytime we need to paint. However,
+ * it is sufficient to search it once. So this message is called, whenever
+ * a new tab is inserted
+ */
+
+ if ((hwndChild = FindWindowEx(hwnd, 0, _T("msctls_updown32"), NULL)) != 0)
+ DestroyWindow(hwndChild);
+ return 0;
+ }
+ case EM_VALIDATEBOTTOM: {
+ BOOL bClassicDraw = (tabdat->m_VisualStyles == FALSE);
+ if ((tabdat->dwStyle & TCS_BOTTOM) && !bClassicDraw && PluginConfig.tabConfig.m_bottomAdjust != 0)
+ InvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ case EM_REFRESHWITHOUTCLIP:
+ if (TabCtrl_GetItemCount(hwnd) > 1)
+ return 0;
+ else {
+ tabdat->bRefreshWithoutClip = TRUE;
+ RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW | RDW_NOCHILDREN | RDW_INVALIDATE);
+ tabdat->bRefreshWithoutClip = FALSE;
+ return 0;
+ }
+ case TCM_INSERTITEM:
+ case TCM_DELETEITEM:
+ tabdat->iHoveredCloseIcon = -1;
+ if (!(tabdat->dwStyle & TCS_MULTILINE) || tabdat->dwStyle & TCS_BUTTONS) {
+ LRESULT result;
+ RECT rc;
+ int iTabs = TabCtrl_GetItemCount(hwnd);
+ if (iTabs >= 1 && msg == TCM_INSERTITEM) {
+ TabCtrl_GetItemRect(hwnd, 0, &rc);
+ TabCtrl_SetItemSize(hwnd, 10, rc.bottom - rc.top);
+ }
+ result = CallWindowProc(OldTabControlClassProc, hwnd, msg, wParam, lParam);
+ TabCtrl_GetItemRect(hwnd, 0, &rc);
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ return result;
+ }
+ break;
+ case WM_DESTROY:
+ if (tabdat) {
+ if (tabdat->hTheme != 0 && CMimAPI::m_pfnCloseThemeData != 0) {
+ CMimAPI::m_pfnCloseThemeData(tabdat->hTheme);
+ CMimAPI::m_pfnCloseThemeData(tabdat->hThemeButton);
+ }
+ }
+ break;
+ case WM_NCDESTROY:
+ if(tabdat) {
+ mir_free(tabdat);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0L);
+ }
+ break;
+ case WM_MBUTTONDOWN: {
+ POINT pt;
+ GetCursorPos(&pt);
+ SendMessage(GetParent(hwnd), DM_CLOSETABATMOUSE, 0, (LPARAM)&pt);
+ return 1;
+ }
+ case WM_SETCURSOR: {
+ POINT pt;
+
+ GetCursorPos(&pt);
+ SendMessage(GetParent(hwnd), msg, wParam, lParam);
+ if (abs(pt.x - ptMouseT.x) < 4 && abs(pt.y - ptMouseT.y) < 4)
+ return 1;
+ ptMouseT = pt;
+ if (tabdat->fTipActive) {
+ KillTimer(hwnd, TIMERID_HOVER_T);
+ CallService("mToolTip/HideTip", 0, 0);
+ tabdat->fTipActive = FALSE;
+ }
+ KillTimer(hwnd, TIMERID_HOVER_T);
+ if(tabdat->pContainer && (!tabdat->pContainer->SideBar->isActive() && (TabCtrl_GetItemCount(hwnd) > 1 || !(tabdat->pContainer->dwFlags & CNT_HIDETABS))))
+ SetTimer(hwnd, TIMERID_HOVER_T, 750, 0);
+ break;
+ }
+ case WM_SIZE: {
+ int iTabs = TabCtrl_GetItemCount(hwnd);
+
+ if (!tabdat->pContainer)
+ break;
+
+ if (!(tabdat->dwStyle & TCS_MULTILINE)) {
+ RECT rcClient, rc;
+ DWORD newItemSize;
+ if (iTabs > (tabdat->pContainer->dwFlags & CNT_HIDETABS ? 1 : 0)) {
+ GetClientRect(hwnd, &rcClient);
+ TabCtrl_GetItemRect(hwnd, iTabs - 1, &rc);
+ newItemSize = (rcClient.right - 6) - (tabdat->dwStyle & TCS_BUTTONS ? (iTabs) * 10 : 0);
+ newItemSize = newItemSize / iTabs;
+ if (newItemSize < PluginConfig.tabConfig.m_fixedwidth) {
+ TabCtrl_SetItemSize(hwnd, newItemSize, rc.bottom - rc.top);
+ } else {
+ TabCtrl_SetItemSize(hwnd, PluginConfig.tabConfig.m_fixedwidth, rc.bottom - rc.top);
+ }
+ SendMessage(hwnd, EM_SEARCHSCROLLER, 0, 0);
+ }
+ } else if (tabdat->dwStyle & TCS_BUTTONS && iTabs > 0) {
+ RECT rcClient, rcItem;
+ int nrTabsPerLine;
+ GetClientRect(hwnd, &rcClient);
+ TabCtrl_GetItemRect(hwnd, 0, &rcItem);
+ nrTabsPerLine = (rcClient.right) / PluginConfig.tabConfig.m_fixedwidth;
+ if (iTabs >= nrTabsPerLine && nrTabsPerLine > 0)
+ TabCtrl_SetItemSize(hwnd, ((rcClient.right - 6) / nrTabsPerLine) - (tabdat->dwStyle & TCS_BUTTONS ? 8 : 0), rcItem.bottom - rcItem.top);
+ else
+ TabCtrl_SetItemSize(hwnd, PluginConfig.tabConfig.m_fixedwidth, rcItem.bottom - rcItem.top);
+ }
+ break;
+ }
+ case WM_LBUTTONDBLCLK: {
+ POINT pt;
+ GetCursorPos(&pt);
+ SendMessage(GetParent(hwnd), DM_CLOSETABATMOUSE, 0, (LPARAM)&pt);
+ break;
+ }
+ case WM_RBUTTONDOWN:
+ KillTimer(hwnd, TIMERID_HOVER_T);
+ CallService("mToolTip/HideTip", 0, 0);
+ tabdat->fTipActive = FALSE;
+ break;
+
+ case WM_LBUTTONDOWN: {
+ TCHITTESTINFO tci = {0};
+
+ KillTimer(hwnd, TIMERID_HOVER_T);
+ CallService("mToolTip/HideTip", 0, 0);
+ tabdat->fTipActive = FALSE;
+
+ if (GetKeyState(VK_CONTROL) & 0x8000) {
+ tci.pt.x = (short)LOWORD(GetMessagePos());
+ tci.pt.y = (short)HIWORD(GetMessagePos());
+ if (DragDetect(hwnd, tci.pt) && TabCtrl_GetItemCount(hwnd) > 1) {
+ int i;
+ tci.flags = TCHT_ONITEM;
+
+ ScreenToClient(hwnd, &tci.pt);
+ i = TabCtrl_HitTest(hwnd, &tci);
+ if (i != -1) {
+ TCITEM tc;
+ struct TWindowData *dat = NULL;
+
+ tc.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwnd, i, &tc);
+ dat = (struct TWindowData *)GetWindowLongPtr((HWND)tc.lParam, GWLP_USERDATA);
+ if (dat) {
+ tabdat->bDragging = TRUE;
+ tabdat->iBeginIndex = i;
+ tabdat->hwndDrag = (HWND)tc.lParam;
+ tabdat->dragDat = dat;
+ tabdat->fSavePos = TRUE;
+ tabdat->himlDrag = ImageList_Create(16, 16, ILC_MASK | (PluginConfig.m_bIsXP ? ILC_COLOR32 : ILC_COLOR16), 1, 0);
+ ImageList_AddIcon(tabdat->himlDrag, dat->hTabIcon);
+ ImageList_BeginDrag(tabdat->himlDrag, 0, 8, 8);
+ ImageList_DragEnter(hwnd, tci.pt.x, tci.pt.y);
+ SetCapture(hwnd);
+ }
+ return TRUE;
+ }
+ }
+ }
+
+ if (GetKeyState(VK_MENU) & 0x8000) {
+ tci.pt.x = (short)LOWORD(GetMessagePos());
+ tci.pt.y = (short)HIWORD(GetMessagePos());
+ if (DragDetect(hwnd, tci.pt) && TabCtrl_GetItemCount(hwnd) > 1) {
+ int i;
+ tci.flags = TCHT_ONITEM;
+
+ ScreenToClient(hwnd, &tci.pt);
+ i = TabCtrl_HitTest(hwnd, &tci);
+ if (i != -1) {
+ TCITEM tc;
+ TWindowData *dat = NULL;
+
+ tc.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwnd, i, &tc);
+ dat = (TWindowData *)GetWindowLongPtr((HWND)tc.lParam, GWLP_USERDATA);
+ if (dat) {
+ tabdat->bDragging = TRUE;
+ tabdat->iBeginIndex = i;
+ tabdat->hwndDrag = (HWND)tc.lParam;
+ tabdat->dragDat = dat;
+ tabdat->himlDrag = ImageList_Create(16, 16, ILC_MASK | (PluginConfig.m_bIsXP ? ILC_COLOR32 : ILC_COLOR16), 1, 0);
+ tabdat->fSavePos = FALSE;
+ ImageList_AddIcon(tabdat->himlDrag, dat->hTabIcon);
+ ImageList_BeginDrag(tabdat->himlDrag, 0, 8, 8);
+ ImageList_DragEnter(hwnd, tci.pt.x, tci.pt.y);
+ SetCapture(hwnd);
+ }
+ return TRUE;
+ }
+ }
+ }
+ if(tabdat->fCloseButton) {
+ POINT pt;
+ GetCursorPos(&pt);
+
+ if(TabCtrl_TestForCloseButton(tabdat, hwnd, pt) != -1)
+ return(TRUE);
+ }
+ }
+ break;
+
+ case WM_CAPTURECHANGED: {
+ tabdat->bDragging = FALSE;
+ ImageList_DragLeave(hwnd);
+ ImageList_EndDrag();
+ if (tabdat->himlDrag) {
+ ImageList_RemoveAll(tabdat->himlDrag);
+ ImageList_Destroy(tabdat->himlDrag);
+ tabdat->himlDrag = 0;
+ }
+ }
+ break;
+
+ case WM_MOUSEMOVE: {
+ if (tabdat->bDragging) {
+ TCHITTESTINFO tci = {0};
+ tci.pt.x = (short)LOWORD(GetMessagePos());
+ tci.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(hwnd, &tci.pt);
+ ImageList_DragMove(tci.pt.x, tci.pt.y);
+ }
+ if(tabdat->fCloseButton) {
+ POINT pt;
+
+ GetCursorPos(&pt);
+ int iOldHovered = tabdat->iHoveredCloseIcon;
+ tabdat->iHoveredCloseIcon = TabCtrl_TestForCloseButton(tabdat, hwnd, pt);
+ if(tabdat->iHoveredCloseIcon != iOldHovered)
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+ }
+ break;
+
+ case WM_LBUTTONUP: {
+ CallWindowProc(OldTabControlClassProc, hwnd, msg, wParam, lParam);
+ if (tabdat->bDragging && ReleaseCapture()) {
+ TCHITTESTINFO tci = {0};
+ int i;
+ tci.pt.x = (short)LOWORD(GetMessagePos());
+ tci.pt.y = (short)HIWORD(GetMessagePos());
+ tci.flags = TCHT_ONITEM;
+ tabdat->bDragging = FALSE;
+ ImageList_DragLeave(hwnd);
+ ImageList_EndDrag();
+
+ ScreenToClient(hwnd, &tci.pt);
+ i = TabCtrl_HitTest(hwnd, &tci);
+ if (i != -1 && i != tabdat->iBeginIndex)
+ RearrangeTab(tabdat->hwndDrag, tabdat->dragDat, MAKELONG(i, 0xffff), tabdat->fSavePos);
+ tabdat->hwndDrag = (HWND) - 1;
+ tabdat->dragDat = NULL;
+ if (tabdat->himlDrag) {
+ ImageList_RemoveAll(tabdat->himlDrag);
+ ImageList_Destroy(tabdat->himlDrag);
+ tabdat->himlDrag = 0;
+ }
+ }
+ if(tabdat->fCloseButton) {
+ POINT pt;
+
+ GetCursorPos(&pt);
+ int iItem = TabCtrl_TestForCloseButton(tabdat, hwnd, pt);
+ if(iItem != -1)
+ SendMessage(GetParent(hwnd), DM_CLOSETABATMOUSE, 0, (LPARAM)&pt);
+ }
+ }
+ break;
+
+ case WM_ERASEBKGND:
+ if (tabdat->pContainer && (CSkin::m_skinEnabled || M->isAero()))
+ return TRUE;
+ return(0);
+ case WM_PAINT: {
+ PAINTSTRUCT ps;
+ HDC hdcreal, hdc;
+ RECT rectTemp, rctPage, rctActive, rcItem, rctClip, rctOrig;
+ RECT rectUpDn = {0, 0, 0, 0};
+ int nCount = TabCtrl_GetItemCount(hwnd), i;
+ TCITEM item = {0};
+ int iActive, hotItem;
+ POINT pt;
+ DWORD dwStyle = tabdat->dwStyle;
+ HPEN hPenOld = 0;
+ UINT uiFlags = 1;
+ UINT uiBottom = 0;
+ TCHITTESTINFO hti;
+ HBITMAP bmpMem, bmpOld;
+ DWORD cx, cy;
+ bool isAero = M->isAero();
+ HANDLE hpb = 0;
+ BOOL bClassicDraw = !isAero && (tabdat->m_VisualStyles == FALSE || CSkin::m_skinEnabled);
+ if(GetUpdateRect(hwnd, NULL, TRUE) == 0)
+ break;
+
+ item.mask = TCIF_PARAM;
+
+ tabdat->fAeroTabs = (CSkin::m_fAeroSkinsValid && (isAero || PluginConfig.m_fillColor)) ? TRUE : FALSE;
+ tabdat->fCloseButton = tabdat->pContainer ? (tabdat->pContainer->dwFlagsEx & TCF_CLOSEBUTTON ? TRUE : FALSE) : FALSE;
+
+ tabdat->helperDat = 0;
+
+ if(tabdat->fAeroTabs && tabdat->pContainer) {
+ TWindowData *dat = (TWindowData *)GetWindowLongPtr(tabdat->pContainer->hwndActive, GWLP_USERDATA);
+ if(dat) {
+ tabdat->helperDat = dat;
+ }
+ else
+ tabdat->fAeroTabs = 0;
+
+ tabdat->helperItem = (dwStyle & TCS_BOTTOM) ? CSkin::m_tabBottom : CSkin::m_tabTop;
+ tabdat->helperGlowItem = (dwStyle & TCS_BOTTOM) ? CSkin::m_tabGlowBottom : CSkin::m_tabGlowTop;
+ }
+ else
+ tabdat->fAeroTabs = FALSE;
+
+ hdcreal = BeginPaint(hwnd, &ps);
+
+ /*
+ * switchbar is active, don't paint a single pixel, the tab control won't be visible at all
+ * same when we have only ONE tab and do not want it to be visible because of the container
+ * option "Show tab bar only when needed".
+ */
+
+ if((tabdat->pContainer->dwFlags & CNT_SIDEBAR) || (nCount == 1 && tabdat->pContainer->dwFlags & CNT_HIDETABS)) {
+ if(nCount == 0)
+ FillRect(hdcreal, &ps.rcPaint, GetSysColorBrush(COLOR_3DFACE)); // avoid flickering/ugly black background during container creation
+ EndPaint(hwnd, &ps);
+ return(0);
+ }
+
+ GetClientRect(hwnd, &rctPage);
+ rctOrig = rctPage;
+ iActive = TabCtrl_GetCurSel(hwnd);
+ TabCtrl_GetItemRect(hwnd, iActive, &rctActive);
+ cx = rctPage.right - rctPage.left;
+ cy = rctPage.bottom - rctPage.top;
+
+ /*
+ * draw everything to a memory dc to avoid flickering
+ */
+
+ if(CMimAPI::m_haveBufferedPaint)
+ hpb = tabdat->hbp = CSkin::InitiateBufferedPaint(hdcreal, rctPage, hdc);
+ else {
+ hdc = CreateCompatibleDC(hdcreal);
+ bmpMem = tabdat->fAeroTabs ? CSkin::CreateAeroCompatibleBitmap(rctPage, hdcreal) : CreateCompatibleBitmap(hdcreal, cx, cy);
+ bmpOld = (HBITMAP)SelectObject(hdc, bmpMem);
+ }
+
+ if (nCount == 1 && tabdat->pContainer->dwFlags & CNT_HIDETABS)
+ rctClip = rctPage;
+
+ if (CSkin::m_skinEnabled)
+ CSkin::SkinDrawBG(hwnd, tabdat->pContainer->hwnd, tabdat->pContainer, &rctPage, hdc);
+ else
+ CSkin::FillBack(hdc, &rctPage);
+
+ if (dwStyle & TCS_BUTTONS) {
+ RECT rc1;
+ TabCtrl_GetItemRect(hwnd, nCount - 1, &rc1);
+ if (dwStyle & TCS_BOTTOM) {
+ rctPage.bottom = rc1.top;
+ uiBottom = 8;
+ } else {
+ rctPage.top = rc1.bottom + 2;
+ uiBottom = 0;
+ }
+ } else {
+ if (dwStyle & TCS_BOTTOM) {
+ rctPage.bottom = rctActive.top;
+ uiBottom = 8;
+ } else {
+ rctPage.top = rctActive.bottom;
+ uiBottom = 0;
+ }
+ }
+
+ if (nCount > 1 || !(tabdat->pContainer->dwFlags & CNT_HIDETABS)) {
+ rctClip = rctPage;
+ InflateRect(&rctClip, -tabdat->pContainer->tBorder, -tabdat->pContainer->tBorder);
+ }
+ else
+ ZeroMemory(&rctClip, sizeof(RECT));
+
+ hPenOld = (HPEN)SelectObject(hdc, PluginConfig.tabConfig.m_hPenLight);
+ /*
+ * visual style support
+ */
+
+ CopyRect(&rcTabPage, &rctPage);
+ if (!tabdat->bRefreshWithoutClip)
+ ExcludeClipRect(hdc, rctClip.left, rctClip.top, rctClip.right, rctClip.bottom);
+ else
+ ZeroMemory(&rctClip, sizeof(RECT));
+ if ((!bClassicDraw || PluginConfig.m_fillColor) && IntersectRect(&rectTemp, &rctPage, &ps.rcPaint) && !CSkin::m_skinEnabled) {
+ RECT rcClient = rctPage;
+ if (dwStyle & TCS_BOTTOM) {
+ rcClient.bottom = rctPage.bottom;
+ uiFlags |= uiBottom;
+ } else
+ rcClient.top = rctPage.top;
+ if(PluginConfig.m_fillColor)
+ DrawCustomTabPage(hdc, rcClient);
+ else
+ DrawThemesXpTabItem(hdc, -1, &rcClient, uiFlags, tabdat, 0); // TABP_PANE=9,0,'TAB'
+ if (tabdat->bRefreshWithoutClip)
+ goto skip_tabs;
+ } else {
+ if (IntersectRect(&rectTemp, &rctPage, &ps.rcPaint)) {
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item = &SkinItems[ID_EXTBKTABPAGE];
+
+ if (!item->IGNORED) {
+ DrawAlpha(hdc, &rctPage, item->COLOR, item->ALPHA, item->COLOR2, item->COLOR2_TRANSPARENT,
+ item->GRADIENT, item->CORNER, item->BORDERSTYLE, item->imageItem);
+ goto page_done;
+ }
+ }
+
+ if (tabdat->bRefreshWithoutClip)
+ goto skip_tabs;
+
+ if (dwStyle & TCS_BUTTONS) {
+ rectTemp = rctPage;
+ if (dwStyle & TCS_BOTTOM) {
+ rectTemp.top--;
+ rectTemp.bottom--;
+ } else {
+ rectTemp.bottom--;
+ rectTemp.top++;
+ }
+ if(PluginConfig.m_fillColor)
+ DrawCustomTabPage(hdc, rectTemp);
+ else {
+ MoveToEx(hdc, rectTemp.left, rectTemp.bottom, &pt);
+ LineTo(hdc, rectTemp.left, rectTemp.top + 1);
+ LineTo(hdc, rectTemp.right - 1, rectTemp.top + 1);
+ SelectObject(hdc, PluginConfig.tabConfig.m_hPenShadow);
+ LineTo(hdc, rectTemp.right - 1, rectTemp.bottom);
+ LineTo(hdc, rectTemp.left, rectTemp.bottom);
+ }
+ } else {
+ rectTemp = rctPage;
+ if(PluginConfig.m_fillColor)
+ DrawCustomTabPage(hdc, rectTemp);
+ else {
+ MoveToEx(hdc, rectTemp.left, rectTemp.bottom - 1, &pt);
+ LineTo(hdc, rectTemp.left, rectTemp.top);
+
+ if (dwStyle & TCS_BOTTOM) {
+ LineTo(hdc, rectTemp.right - 1, rectTemp.top);
+ SelectObject(hdc, PluginConfig.tabConfig.m_hPenShadow);
+ LineTo(hdc, rectTemp.right - 1, rectTemp.bottom - 1);
+ LineTo(hdc, rctActive.right, rectTemp.bottom - 1);
+ MoveToEx(hdc, rctActive.left - 2, rectTemp.bottom - 1, &pt);
+ LineTo(hdc, rectTemp.left - 1, rectTemp.bottom - 1);
+ SelectObject(hdc, PluginConfig.tabConfig.m_hPenItemShadow);
+ MoveToEx(hdc, rectTemp.right - 2, rectTemp.top + 1, &pt);
+ LineTo(hdc, rectTemp.right - 2, rectTemp.bottom - 2);
+ LineTo(hdc, rctActive.right, rectTemp.bottom - 2);
+ MoveToEx(hdc, rctActive.left - 2, rectTemp.bottom - 2, &pt);
+ LineTo(hdc, rectTemp.left, rectTemp.bottom - 2);
+ } else {
+ if (rctActive.left >= 0) {
+ LineTo(hdc, rctActive.left, rctActive.bottom);
+ if (IsRectEmpty(&rectUpDn))
+ MoveToEx(hdc, rctActive.right, rctActive.bottom, &pt);
+ else {
+ if (rctActive.right >= rectUpDn.left)
+ MoveToEx(hdc, rectUpDn.left - SHIFT_FROM_CUT_TO_SPIN + 2, rctActive.bottom + 1, &pt);
+ else
+ MoveToEx(hdc, rctActive.right, rctActive.bottom, &pt);
+ }
+ LineTo(hdc, rectTemp.right - 2, rctActive.bottom);
+ } else {
+ RECT rectItemLeftmost;
+ UINT nItemLeftmost = FindLeftDownItem(hwnd);
+ TabCtrl_GetItemRect(hwnd, nItemLeftmost, &rectItemLeftmost);
+ LineTo(hdc, rectTemp.right - 2, rctActive.bottom);
+ }
+ SelectObject(hdc, PluginConfig.tabConfig.m_hPenItemShadow);
+ LineTo(hdc, rectTemp.right - 2, rectTemp.bottom - 2);
+ LineTo(hdc, rectTemp.left, rectTemp.bottom - 2);
+
+ SelectObject(hdc, PluginConfig.tabConfig.m_hPenShadow);
+ MoveToEx(hdc, rectTemp.right - 1, rctActive.bottom, &pt);
+ LineTo(hdc, rectTemp.right - 1, rectTemp.bottom - 1);
+ LineTo(hdc, rectTemp.left - 2, rectTemp.bottom - 1);
+ }
+ }
+ }
+ }
+ }
+page_done:
+ /*
+ * if aero is active _and_ the infopanel is visible in the current window, we "flatten" out the top area
+ * of the tab page by overpainting it black (thus it will appear transparent)
+ */
+ if(isAero && tabdat->helperDat) {
+ RECT rcLog, rcPage;
+ POINT pt;
+
+ GetClientRect(hwnd, &rcPage);
+ if(dwStyle & TCS_BOTTOM) {
+ GetWindowRect(tabdat->helperDat->hwnd, &rcLog);
+ pt.y = rcLog.bottom;
+ pt.x = rcLog.left;
+ ScreenToClient(hwnd, &pt);
+ rcPage.top = pt.y + ((nCount > 1 || !(tabdat->helperDat->pContainer->dwFlags & CNT_HIDETABS)) ? tabdat->helperDat->pContainer->tBorder : 0);
+ FillRect(hdc, &rcPage, CSkin::m_BrushBack);
+ rcPage.top = 0;
+ }
+ GetWindowRect(GetDlgItem(tabdat->helperDat->hwnd, tabdat->helperDat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG), &rcLog);
+ pt.y = rcLog.top;
+ pt.x = rcLog.left;
+ ScreenToClient(hwnd, &pt);
+ rcPage.bottom = pt.y;
+ FillRect(hdc, &rcPage, CSkin::m_BrushBack);
+ }
+
+ uiFlags = 0;
+ /*
+ * figure out hottracked item (if any)
+ */
+
+ if (tabdat->bRefreshWithoutClip)
+ goto skip_tabs;
+
+ GetCursorPos(&hti.pt);
+ ScreenToClient(hwnd, &hti.pt);
+ hti.flags = 0;
+ hotItem = TabCtrl_HitTest(hwnd, &hti);
+ for (i = 0; i < nCount; i++) {
+ TWindowData* dat = 0;
+
+ if (i != iActive) {
+ TabCtrl_GetItem(hwnd, i, &item);
+ if(item.lParam)
+ dat = (TWindowData *)GetWindowLongPtr((HWND)item.lParam, GWLP_USERDATA);
+ TabCtrl_GetItemRect(hwnd, i, &rcItem);
+ if (!bClassicDraw && uiBottom) {
+ rcItem.top -= PluginConfig.tabConfig.m_bottomAdjust;
+ rcItem.bottom -= PluginConfig.tabConfig.m_bottomAdjust;
+ }
+ if (IntersectRect(&rectTemp, &rcItem, &ps.rcPaint) || bClassicDraw) {
+ int nHint = 0;
+ if (!bClassicDraw && !(dwStyle & TCS_BUTTONS)) {
+ DrawThemesXpTabItem(hdc, i, &rcItem, uiFlags | uiBottom | (i == hotItem ? 4 : 0), tabdat, dat);
+ DrawItem(tabdat, hdc, &rcItem, nHint | (i == hotItem ? HINT_HOTTRACK : 0), i, dat);
+ } else {
+ if(tabdat->fAeroTabs && !CSkin::m_skinEnabled && !(dwStyle & TCS_BUTTONS))
+ DrawThemesPartWithAero(tabdat, hdc, 0, (i == hotItem ? PBS_HOT : PBS_NORMAL), &rcItem, dat);
+ else
+ DrawItemRect(tabdat, hdc, &rcItem, nHint | (i == hotItem ? HINT_HOTTRACK : 0), i, dat);
+ DrawItem(tabdat, hdc, &rcItem, nHint | (i == hotItem ? HINT_HOTTRACK : 0), i, dat);
+ }
+ }
+ }
+ }
+ /*
+ * draw the active item
+ */
+ if (!bClassicDraw && uiBottom) {
+ rctActive.top -= PluginConfig.tabConfig.m_bottomAdjust;
+ rctActive.bottom -= PluginConfig.tabConfig.m_bottomAdjust;
+ }
+ if (rctActive.left >= 0) {
+ TWindowData* dat = 0;
+ int nHint = 0;
+
+ rcItem = rctActive;
+ TabCtrl_GetItem(hwnd, iActive, &item);
+ if(item.lParam)
+ dat = (TWindowData *)GetWindowLongPtr((HWND)item.lParam, GWLP_USERDATA);
+
+ if (!bClassicDraw && !(dwStyle & TCS_BUTTONS)) {
+ InflateRect(&rcItem, 2, 2);
+ DrawThemesXpTabItem(hdc, iActive, &rcItem, 2 | uiBottom, tabdat, dat);
+ DrawItem(tabdat, hdc, &rcItem, nHint | HINT_ACTIVE_ITEM, iActive, dat);
+ } else {
+ if (!(dwStyle & TCS_BUTTONS)) {
+ if (iActive == 0) {
+ rcItem.right += 2;
+ rcItem.left--;
+ } else
+ InflateRect(&rcItem, 2, 0);
+ }
+ if(tabdat->fAeroTabs && !CSkin::m_skinEnabled && !(dwStyle & TCS_BUTTONS)) {
+ if(dwStyle & TCS_BOTTOM)
+ rcItem.bottom+= 2;
+ else
+ rcItem.top-= 2;
+ DrawThemesPartWithAero(tabdat, hdc, 0, PBS_PRESSED, &rcItem, dat);
+ }
+ else
+ DrawItemRect(tabdat, hdc, &rcItem, HINT_ACTIVATE_RIGHT_SIDE | HINT_ACTIVE_ITEM | nHint, iActive, dat);
+ DrawItem(tabdat, hdc, &rcItem, HINT_ACTIVE_ITEM | nHint, iActive, dat);
+ }
+ }
+skip_tabs:
+ if (hPenOld)
+ SelectObject(hdc, hPenOld);
+
+ /*
+ * finally, bitblt the contents of the memory dc to the real dc
+ */
+ //if(!tabdat->pContainer->bSkinned)
+ if (!tabdat->bRefreshWithoutClip)
+ ExcludeClipRect(hdcreal, rctClip.left, rctClip.top, rctClip.right, rctClip.bottom);
+
+ if(hpb)
+ CSkin::FinalizeBufferedPaint(hpb, &rctOrig);
+ //CMimAPI::m_pfnEndBufferedPaint(hpb, TRUE);
+ else {
+ BitBlt(hdcreal, 0, 0, cx, cy, hdc, 0, 0, SRCCOPY);
+ SelectObject(hdc, bmpOld);
+ DeleteObject(bmpMem);
+ DeleteDC(hdc);
+ }
+ EndPaint(hwnd, &ps);
+ return 0;
+ }
+ case WM_TIMER: {
+ if (wParam == TIMERID_HOVER_T && M->GetByte("d_tooltips", 0)) {
+ POINT pt;
+ CLCINFOTIP ti = {0};
+ ti.cbSize = sizeof(ti);
+
+ KillTimer(hwnd, TIMERID_HOVER_T);
+ GetCursorPos(&pt);
+ if (abs(pt.x - ptMouseT.x) < 5 && abs(pt.y - ptMouseT.y) < 5) {
+ TCITEM item = {0};
+ int nItem = 0;
+ struct TWindowData *dat = 0;
+
+ ti.ptCursor = pt;
+ //ScreenToClient(hwnd, &pt);
+
+ item.mask = TCIF_PARAM;
+ nItem = GetTabItemFromMouse(hwnd, &pt);
+ if (nItem >= 0 && nItem < TabCtrl_GetItemCount(hwnd)) {
+ TabCtrl_GetItem(hwnd, nItem, &item);
+ /*
+ * get the message window data for the session to which this tab item belongs
+ */
+
+ if (IsWindow((HWND)item.lParam) && item.lParam != 0)
+ dat = (struct TWindowData *)GetWindowLongPtr((HWND)item.lParam, GWLP_USERDATA);
+ if (dat) {
+ tabdat->fTipActive = TRUE;
+ ti.isGroup = 0;
+ ti.hItem = dat->hContact;
+ ti.isTreeFocused = 0;
+ CallService("mToolTip/ShowTip", 0, (LPARAM)&ti);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case WM_MOUSEWHEEL: {
+ short amount = (short)(HIWORD(wParam));
+ if (lParam != -1)
+ break;
+ if (amount > 0)
+ SendMessage(GetParent(hwnd), DM_SELECTTAB, DM_SELECT_PREV, 0);
+ else if (amount < 0)
+ SendMessage(GetParent(hwnd), DM_SELECTTAB, DM_SELECT_NEXT, 0);
+ InvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ case WM_USER + 100: {
+ if (tabdat->fTipActive) {
+ tabdat->fTipActive = FALSE;
+ CallService("mToolTip/HideTip", 0, 0);
+ }
+ }
+ }
+ return CallWindowProc(OldTabControlClassProc, hwnd, msg, wParam, lParam);
+}
+
+/*
+ * load the tab control configuration data (colors, fonts, flags...
+ */
+
+void TSAPI ReloadTabConfig()
+{
+ NONCLIENTMETRICS nclim;
+ int i = 0;
+
+ PluginConfig.tabConfig.m_hPenLight = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT));
+ PluginConfig.tabConfig.m_hPenShadow = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DDKSHADOW));
+ PluginConfig.tabConfig.m_hPenItemShadow = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
+
+ nclim.cbSize = sizeof(nclim);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nclim, 0);
+ PluginConfig.tabConfig.m_hMenuFont = CreateFontIndirect(&nclim.lfMessageFont);
+
+ while (tabcolors[i].szKey != NULL) {
+ PluginConfig.tabConfig.colors[i] = M->GetDword(CSkin::m_skinEnabled ? tabcolors[i].szSkinnedKey : tabcolors[i].szKey, GetSysColor(tabcolors[i].defclr));
+ i++;
+ }
+ PluginConfig.tabConfig.m_brushes[0] = CreateSolidBrush(PluginConfig.tabConfig.colors[4]);
+ PluginConfig.tabConfig.m_brushes[1] = CreateSolidBrush(PluginConfig.tabConfig.colors[5]);
+ PluginConfig.tabConfig.m_brushes[2] = CreateSolidBrush(PluginConfig.tabConfig.colors[6]);
+ PluginConfig.tabConfig.m_brushes[3] = CreateSolidBrush(PluginConfig.tabConfig.colors[7]);
+
+ PluginConfig.tabConfig.m_bottomAdjust = (int)M->GetDword("bottomadjust", 0);
+ PluginConfig.tabConfig.m_fixedwidth = M->GetDword("fixedwidth", FIXED_TAB_SIZE);
+
+ PluginConfig.tabConfig.m_fixedwidth = (PluginConfig.tabConfig.m_fixedwidth < 60 ? 60 : PluginConfig.tabConfig.m_fixedwidth);
+}
+
+void TSAPI FreeTabConfig()
+{
+ int i;
+
+ if(PluginConfig.tabConfig.m_hPenItemShadow)
+ DeleteObject(PluginConfig.tabConfig.m_hPenItemShadow);
+
+ if(PluginConfig.tabConfig.m_hPenLight)
+ DeleteObject(PluginConfig.tabConfig.m_hPenLight);
+
+ if(PluginConfig.tabConfig.m_hPenShadow)
+ DeleteObject(PluginConfig.tabConfig.m_hPenShadow);
+
+ if(PluginConfig.tabConfig.m_hMenuFont)
+ DeleteObject(PluginConfig.tabConfig.m_hMenuFont);
+
+ for(i = 0; i < 4; i++) {
+ if(PluginConfig.tabConfig.m_brushes[i]) {
+ DeleteObject(PluginConfig.tabConfig.m_brushes[i]);
+ PluginConfig.tabConfig.m_brushes[i] = 0;
+ }
+ }
+ ZeroMemory(&PluginConfig.tabConfig, sizeof(myTabCtrl));
+}
+
+/*
+ * options dialog for setting up tab options
+ */
+
+static bool tconfig_init = false;
+
+INT_PTR CALLBACK DlgProcTabConfig(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG: {
+ tconfig_init = false;
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_USER + 100, 0, 0);
+ tconfig_init = true;
+ return TRUE;
+ }
+ case WM_USER + 100: {
+ DWORD dwFlags = M->GetDword("tabconfig", TCF_DEFAULT);
+ int i = 0;
+
+ SendDlgItemMessage(hwndDlg, IDC_TABBORDERSPIN, UDM_SETRANGE, 0, MAKELONG(10, 0));
+ SendDlgItemMessage(hwndDlg, IDC_TABBORDERSPIN, UDM_SETPOS, 0, (int)M->GetByte(CSkin::m_skinEnabled ? "S_tborder" : "tborder", 2));
+ SetDlgItemInt(hwndDlg, IDC_TABBORDER, (int)M->GetByte(CSkin::m_skinEnabled ? "S_tborder" : "tborder", 2), FALSE);;
+
+ SendDlgItemMessage(hwndDlg, IDC_BOTTOMTABADJUSTSPIN, UDM_SETRANGE, 0, MAKELONG(3, -3));
+ SendDlgItemMessage(hwndDlg, IDC_BOTTOMTABADJUSTSPIN, UDM_SETPOS, 0, PluginConfig.tabConfig.m_bottomAdjust);
+ SetDlgItemInt(hwndDlg, IDC_BOTTOMTABADJUST, PluginConfig.tabConfig.m_bottomAdjust, TRUE);
+
+ SendDlgItemMessage(hwndDlg, IDC_TABWIDTHSPIN, UDM_SETRANGE, 0, MAKELONG(400, 50));
+ SendDlgItemMessage(hwndDlg, IDC_TABWIDTHSPIN, UDM_SETPOS, 0, PluginConfig.tabConfig.m_fixedwidth);
+ SetDlgItemInt(hwndDlg, IDC_TABWIDTH, PluginConfig.tabConfig.m_fixedwidth, TRUE);
+
+ SendDlgItemMessage(hwndDlg, IDC_TABBORDERSPINOUTER, UDM_SETRANGE, 0, MAKELONG(50, 0));
+ SendDlgItemMessage(hwndDlg, IDC_TABBORDERSPINOUTERRIGHT, UDM_SETRANGE, 0, MAKELONG(50, 0));
+ SendDlgItemMessage(hwndDlg, IDC_TABBORDERSPINOUTERTOP, UDM_SETRANGE, 0, MAKELONG(40, 0));
+ SendDlgItemMessage(hwndDlg, IDC_TABBORDERSPINOUTERBOTTOM, UDM_SETRANGE, 0, MAKELONG(40, 0));
+
+ SendDlgItemMessage(hwndDlg, IDC_TABBORDERSPINOUTER, UDM_SETPOS, 0, (int)M->GetByte(CSkin::m_skinEnabled ? "S_tborder_outer_left" : "tborder_outer_left", 2));
+ SendDlgItemMessage(hwndDlg, IDC_TABBORDERSPINOUTERRIGHT, UDM_SETPOS, 0, (int)M->GetByte(CSkin::m_skinEnabled ? "S_tborder_outer_right" : "tborder_outer_right", 2));
+ SendDlgItemMessage(hwndDlg, IDC_TABBORDERSPINOUTERTOP, UDM_SETPOS, 0, (int)M->GetByte(CSkin::m_skinEnabled ? "S_tborder_outer_top" : "tborder_outer_top", 2));
+ SendDlgItemMessage(hwndDlg, IDC_TABBORDERSPINOUTERBOTTOM, UDM_SETPOS, 0, (int)M->GetByte(CSkin::m_skinEnabled ? "S_tborder_outer_bottom" : "tborder_outer_bottom", 2));
+
+ SendDlgItemMessage(hwndDlg, IDC_SPIN1, UDM_SETRANGE, 0, MAKELONG(10, 1));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN3, UDM_SETRANGE, 0, MAKELONG(10, 1));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN1, UDM_SETPOS, 0, (LPARAM)M->GetByte("y-pad", 3));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN3, UDM_SETPOS, 0, (LPARAM)M->GetByte("x-pad", 4));
+ SetDlgItemInt(hwndDlg, IDC_TABPADDING, (int)M->GetByte("y-pad", 3), FALSE);;
+ SetDlgItemInt(hwndDlg, IDC_HTABPADDING, (int)M->GetByte("x-pad", 4), FALSE);;
+ return 0;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ int i = 0;
+ BOOL translated;
+ int fixedWidth;
+
+ struct TContainerData *pContainer = pFirstContainer;
+
+ M->WriteByte(SRMSGMOD_T, "y-pad", (BYTE)(GetDlgItemInt(hwndDlg, IDC_TABPADDING, NULL, FALSE)));
+ M->WriteByte(SRMSGMOD_T, "x-pad", (BYTE)(GetDlgItemInt(hwndDlg, IDC_HTABPADDING, NULL, FALSE)));
+ M->WriteByte(SRMSGMOD_T, "tborder", (BYTE) GetDlgItemInt(hwndDlg, IDC_TABBORDER, &translated, FALSE));
+ M->WriteByte(SRMSGMOD_T, CSkin::m_skinEnabled ? "S_tborder_outer_left" : "tborder_outer_left", (BYTE) GetDlgItemInt(hwndDlg, IDC_TABBORDEROUTER, &translated, FALSE));
+ M->WriteByte(SRMSGMOD_T, CSkin::m_skinEnabled ? "S_tborder_outer_right" : "tborder_outer_right", (BYTE) GetDlgItemInt(hwndDlg, IDC_TABBORDEROUTERRIGHT, &translated, FALSE));
+ M->WriteByte(SRMSGMOD_T, CSkin::m_skinEnabled ? "S_tborder_outer_top" : "tborder_outer_top", (BYTE) GetDlgItemInt(hwndDlg, IDC_TABBORDEROUTERTOP, &translated, FALSE));
+ M->WriteByte(SRMSGMOD_T, CSkin::m_skinEnabled ? "S_tborder_outer_bottom" : "tborder_outer_bottom", (BYTE) GetDlgItemInt(hwndDlg, IDC_TABBORDEROUTERBOTTOM, &translated, FALSE));
+ M->WriteDword(SRMSGMOD_T, "bottomadjust", GetDlgItemInt(hwndDlg, IDC_BOTTOMTABADJUST, &translated, TRUE));
+
+ fixedWidth = GetDlgItemInt(hwndDlg, IDC_TABWIDTH, &translated, FALSE);
+ fixedWidth = (fixedWidth < 60 ? 60 : fixedWidth);
+ M->WriteDword(SRMSGMOD_T, "fixedwidth", fixedWidth);
+ FreeTabConfig();
+ ReloadTabConfig();
+ while (pContainer) {
+ TabCtrl_SetPadding(GetDlgItem(pContainer->hwnd, IDC_MSGTABS), GetDlgItemInt(hwndDlg, IDC_HTABPADDING, NULL, FALSE), GetDlgItemInt(hwndDlg, IDC_TABPADDING, NULL, FALSE));
+ RedrawWindow(GetDlgItem(pContainer->hwnd, IDC_MSGTABS), NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
+ pContainer = pContainer->pNextContainer;
+ }
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_TABWIDTH:
+ case IDC_TABPADDING:
+ case IDC_HTABPADDING:
+ case IDC_TABBORDER:
+ case IDC_TABBORDEROUTER:
+ case IDC_TABBORDEROUTERBOTTOM:
+ case IDC_TABBORDEROUTERRIGHT:
+ case IDC_TABBORDEROUTERTOP:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return TRUE;
+ break;
+
+ default:
+ break;
+
+ }
+ if(tconfig_init)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_DESTROY:
+ tconfig_init = false;
+ }
+ return FALSE;
+}
+
diff --git a/plugins/TabSRMM/src/taskbar.cpp b/plugins/TabSRMM/src/taskbar.cpp
new file mode 100644
index 0000000000..dfe645bd4a
--- /dev/null
+++ b/plugins/TabSRMM/src/taskbar.cpp
@@ -0,0 +1,956 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: taskbar.cpp 13178 2010-12-05 21:29:17Z silvercircle $
+ *
+ * Windows 7 taskbar integration
+ *
+ * - overlay icons
+ * - custom taskbar thumbnails for aero peek in tabbed containers
+ * - read Windows 7 task bar configuration from the registry.
+ */
+/**
+ * how it works:
+ *
+ * Because of the fact, the DWM does not talk to non-toplevel windows
+ * we need an invisible "proxy window" for each tab. This window is a very
+ * small and hidden toplevel tool window which is used to communicate
+ * with the dwm. Each proxy is associated with the client window (the "tab")
+ * and registers itself with the message container window via
+ * ITaskbarList3::RegisterTab().
+ *
+ * Instead of automatically created snapshots of the window content, we
+ * use custom generated thumbnails for the task bar buttons, including
+ * nickname, UID, status message and avatar. This makes the thumbnails
+ * easily recognizable.
+ *
+ * Thumbnails are generated "on request", only when the desktop window
+ * manager needs one.
+ *
+ * Each proxy window has a CThumbIM or CThumbMUC object which represents
+ * the actual thumbnail bitmap.
+ */
+
+#include "commonheaders.h"
+
+/**
+ * maps MUC event types to icon names for retrieving the "big" icons
+ * while generating task bar thumbnails.
+ * used by getMUCBigICon()
+ */
+
+/*
+struct TMUCLargeIconsMap {
+ UINT eventType;
+ char* szIconDesc;
+} MUCLargeIconMap[] = {
+ { GC_EVENT_NICK, "chat_nick" },
+ { GC_EVENT_PART, "chat_part" }
+};
+*/
+
+CTaskbarInteract* Win7Taskbar = 0;
+
+/**
+ * set the overlay icon for a task bar button. Used for typing notifications and incoming
+ * message indicator.
+ *
+ * @param hwndDlg HWND: container window handle
+ * @param lParam LPARAM: icon handle
+ * @return true if icon has been set and taskbar will accept it, false otherwise
+ */
+bool CTaskbarInteract::setOverlayIcon(HWND hwndDlg, LPARAM lParam) const
+{
+ if (m_pTaskbarInterface && m_isEnabled && m_fHaveLargeicons) {
+ m_pTaskbarInterface->SetOverlayIcon(hwndDlg,(HICON)lParam, NULL);
+ return(true);
+ }
+ return(false);
+}
+
+/**
+ * check the task bar status for "large icon mode".
+ * @return bool: true if large icons are in use, false otherwise
+ */
+bool CTaskbarInteract::haveLargeIcons()
+{
+ m_fHaveLargeicons = false;
+
+ if (m_pTaskbarInterface && m_isEnabled) {
+ HKEY hKey;
+ DWORD val = 1;
+ DWORD valGrouping = 2;
+ DWORD size = 4;
+ DWORD dwType = REG_DWORD;
+ /*
+ * check whether the taskbar is set to show large icons. This is necessary, because the method SetOverlayIcon()
+ * always returns S_OK, but the icon is simply ignored when using small taskbar icons.
+ * also, figure out the button grouping mode.
+ */
+ if(::RegOpenKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), &hKey) == ERROR_SUCCESS) {
+ ::RegQueryValueEx(hKey, _T("TaskbarSmallIcons"), 0, &dwType, (LPBYTE)&val, &size);
+ size = 4;
+ dwType = REG_DWORD;
+ /*
+ * this is the "grouping mode" setting for the task bar. 0 = always combine, no labels
+ */
+ ::RegQueryValueEx(hKey, _T("TaskbarGlomLevel"), 0, &dwType, (LPBYTE)&valGrouping, &size);
+ ::RegCloseKey(hKey);
+ }
+ m_fHaveLargeicons = (val ? false : true); // small icons in use, revert to default icon feedback
+ m_fHaveAlwaysGrouping = (valGrouping == 0 ? true : false);
+ }
+ return(m_fHaveLargeicons);
+}
+
+/**
+ * removes the overlay icon for the given container window
+ * @param hwndDlg HWND: window handle
+ */
+void CTaskbarInteract::clearOverlayIcon(HWND hwndDlg) const
+{
+ if (m_pTaskbarInterface && m_isEnabled)
+ m_pTaskbarInterface->SetOverlayIcon(hwndDlg, NULL, NULL);
+}
+
+LONG CTaskbarInteract::updateMetrics()
+{
+ m_IconSize = 32;
+
+ return(m_IconSize);
+}
+
+/**
+ * register a new task bar button ("tab") for the button group hwndContainer
+ * (one of the top level message windows)
+ * @param hwndTab proxy window handle
+ * @param hwndContainer a message container window
+ */
+void CTaskbarInteract::registerTab(const HWND hwndTab, const HWND hwndContainer) const
+{
+ if(m_isEnabled) {
+ m_pTaskbarInterface->RegisterTab(hwndTab, hwndContainer);
+ m_pTaskbarInterface->SetTabOrder(hwndTab, 0);
+ }
+}
+
+/**
+ * remove a previously registered proxy window. The destructor of the proxy
+ * window class is using this before destroying the proxy window itself.
+ * @param hwndTab proxy window handle
+ */
+void CTaskbarInteract::unRegisterTab(const HWND hwndTab) const
+{
+ if(m_isEnabled)
+ m_pTaskbarInterface->UnregisterTab(hwndTab);
+}
+
+/**
+ * set a tab as active. The active thumbnail will appear with a slightly
+ * different background and transparency.
+ *
+ * @param hwndTab window handle of the PROXY window to activate
+ * (don't use the real window handle of the message
+ * tab, because it is not a toplevel window).
+ * @param hwndGroup window group to which it belongs (usually, the
+ * container window handle).
+ */
+void CTaskbarInteract::SetTabActive(const HWND hwndTab, const HWND hwndGroup) const
+{
+ if(m_isEnabled)
+ m_pTaskbarInterface->SetTabActive(hwndTab, hwndGroup, 0);
+}
+
+/**
+ * create a proxy window object for the given session. Do NOT call this more than once
+ * per session and not outside of WM_INITDIALOG after most things are initialized.
+ * @param dat session window data
+ *
+ * static member function. Ignored when OS is not Windows 7 or global option for
+ * Windows 7 task bar support is diabled.
+ */
+void CProxyWindow::add(TWindowData *dat)
+{
+ if(PluginConfig.m_bIsWin7 && PluginConfig.m_useAeroPeek) // && (!CSkin::m_skinEnabled || M->GetByte("forceAeroPeek", 0)))
+ dat->pWnd = new CProxyWindow(dat);
+ else
+ dat->pWnd = 0;
+}
+
+/**
+ * This is called from the broadcasted WM_DWMCOMPOSITIONCHANGED event by all messages
+ * sessions. It checks and, if needed, destroys or creates a proxy object, based on
+ * the status of the DWM
+ * @param dat session window data
+ *
+ * static member function
+ */
+void CProxyWindow::verify(TWindowData *dat)
+{
+ if(PluginConfig.m_bIsWin7 && PluginConfig.m_useAeroPeek) {
+ if(0 == dat->pWnd) {
+ dat->pWnd = new CProxyWindow(dat);
+ if(dat->pWnd) {
+ dat->pWnd->updateIcon(dat->hTabStatusIcon);
+ dat->pWnd->updateTitle(dat->cache->getNick());
+ }
+ }
+ else
+ dat->pWnd->verifyDwmState();
+ }
+ /*
+ * this should not happens, but who knows...
+ */
+ else {
+ if(dat->pWnd) {
+ delete dat->pWnd;
+ dat->pWnd = 0;
+ }
+ }
+}
+
+/**
+ * create the proxy (toplevel) window required to show per tab thumbnails
+ * and previews for a message session.
+ * each tab has one invisible proxy window
+ */
+CProxyWindow::CProxyWindow(const TWindowData *dat)
+{
+ m_dat = dat;
+ m_hBigIcon = 0;
+ m_thumb = 0;
+
+ m_hwndProxy = ::CreateWindowEx(/*WS_EX_TOOLWINDOW | */WS_EX_NOACTIVATE, PROXYCLASSNAME, _T(""),
+ WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION, -32000, -32000, 10, 10, NULL, NULL, g_hInst, (LPVOID)this);
+
+#if defined(__LOGDEBUG_)
+ _DebugTraceW(_T("create proxy object for: %s"), m_dat->cache->getNick());
+#endif
+ Win7Taskbar->registerTab(m_hwndProxy, m_dat->pContainer->hwnd);
+ if(CMimAPI::m_pfnDwmSetWindowAttribute) {
+ BOOL fIconic = TRUE;
+ BOOL fHasIconicBitmap = TRUE;
+
+ CMimAPI::m_pfnDwmSetWindowAttribute(m_hwndProxy, DWMWA_FORCE_ICONIC_REPRESENTATION, &fIconic, sizeof(fIconic));
+ CMimAPI::m_pfnDwmSetWindowAttribute(m_hwndProxy, DWMWA_HAS_ICONIC_BITMAP, &fHasIconicBitmap, sizeof(fHasIconicBitmap));
+ }
+}
+
+CProxyWindow::~CProxyWindow()
+{
+ Win7Taskbar->unRegisterTab(m_hwndProxy);
+ ::DestroyWindow(m_hwndProxy);
+
+#if defined(__LOGDEBUG_)
+ _DebugTraceW(_T("destroy proxy object for: %s"), m_dat->cache->getNick());
+#endif
+ if(m_thumb) {
+ delete m_thumb;
+ m_thumb = 0;
+ }
+}
+
+/**
+ * verify status of DWM when system broadcasts a WM_DWMCOMPOSITIONCHANGED message
+ * delete thumbnails, if no longer needed
+ */
+void CProxyWindow::verifyDwmState()
+{
+ if(!M->isDwmActive()) {
+ if(m_thumb) {
+ delete m_thumb;
+ m_thumb = 0;
+ }
+ }
+ else {
+ /*
+ * force thumbnail recreation
+ */
+ m_width = 0;
+ m_height = 0;
+ }
+}
+
+/**
+ * send a thumbnail to the DWM. If required, refresh it first.
+ * called by WM_DWMSENDICONICTHUMBNAIL handler.
+ *
+ * @param width thumbnail width as requested by DWM via lParam
+ * @param height thumbnail height as requested by DWM via lParam
+ */
+void CProxyWindow::sendThumb(LONG width, LONG height)
+{
+ if(0 == m_thumb) {
+ m_width = width;
+ m_height = height;
+ if(m_dat->bType == SESSIONTYPE_IM)
+ m_thumb = new CThumbIM(this);
+ else
+ m_thumb = new CThumbMUC(this);
+ }
+ else if(width != m_width || height != m_height || !m_thumb->isValid()) {
+ m_width = width;
+ m_height = height;
+ m_thumb->update();
+ }
+ if(m_thumb)
+ CMimAPI::m_pfnDwmSetIconicThumbnail(m_hwndProxy, m_thumb->getHBM(), DWM_SIT_DISPLAYFRAME);
+}
+
+/**
+ * send a live preview image of a given message session to the DWM.
+ * called by WM_DWMSENDICONICLIVEPREVIEWBITMAP on DWM's request.
+ *
+ * The bitmap can be deleted after submitting it, because the DWM
+ * will cache a copy of it (and re-request it when its own bitmap cache
+ * was purged).
+ */
+void CProxyWindow::sendPreview()
+{
+ POINT pt = {0};
+ RECT rcContainer;
+ HDC hdc, dc;
+ FORMATRANGE fr = {0};
+ int twips = (int)(15.0f / PluginConfig.g_DPIscaleY);
+ RECT rcTemp;
+ RECT rcRich, rcLog;
+ bool fIsChat = m_dat->bType == SESSIONTYPE_IM ? false : true;
+ TWindowData* dat_active = reinterpret_cast<TWindowData *>(::GetWindowLongPtr(m_dat->pContainer->hwndActive, GWLP_USERDATA));
+
+ if(m_thumb && dat_active) {
+ HWND hwndRich = ::GetDlgItem(m_dat->hwnd, fIsChat ? IDC_CHAT_LOG : IDC_LOG);
+ LONG cx, cy;
+ POINT ptOrigin = {0}, ptBottom;
+
+ if(m_dat->dwFlags & MWF_NEEDCHECKSIZE) {
+ RECT rcClient;
+
+ ::SendMessage(m_dat->pContainer->hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rcClient);
+ ::MoveWindow(m_dat->hwnd, rcClient.left, rcClient.top, (rcClient.right - rcClient.left), (rcClient.bottom - rcClient.top), FALSE);
+ ::SendMessage(m_dat->hwnd, WM_SIZE, 0, 0);
+ ::SendMessage(m_dat->hwnd, DM_FORCESCROLL, 0, 0);
+ }
+ /*
+ * a minimized container has a null rect as client area, so do not use it
+ * use the last known client area size instead.
+ */
+
+ if(!::IsIconic(m_dat->pContainer->hwnd)) {
+ ::GetWindowRect(m_dat->pContainer->hwndActive, &rcLog);
+ ::GetClientRect(m_dat->pContainer->hwnd, &rcContainer);
+ pt.x = rcLog.left;
+ pt.y = rcLog.top;
+ ::ScreenToClient(m_dat->pContainer->hwnd, &pt);
+ }
+ else {
+ rcLog = m_dat->pContainer->rcLogSaved;
+ rcContainer = m_dat->pContainer->rcSaved;
+ pt = m_dat->pContainer->ptLogSaved;
+ }
+
+ ::GetWindowRect(::GetDlgItem(m_dat->pContainer->hwndActive, dat_active->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG), &rcTemp);
+ ptBottom.x = rcTemp.left;
+ ptBottom.y = rcTemp.bottom;
+ ::ScreenToClient(m_dat->pContainer->hwnd, &ptBottom);
+
+ cx = rcLog.right - rcLog.left;
+ cy = rcLog.bottom - rcLog.top;
+ rcRich.left = 0;
+ rcRich.top = 0;
+ rcRich.right = cx;
+ rcRich.bottom = ptBottom.y - pt.y;
+
+ dc = ::GetDC(m_dat->hwnd);
+ hdc = ::CreateCompatibleDC(dc);
+ HBITMAP hbm = CSkin::CreateAeroCompatibleBitmap(rcContainer, hdc);
+ HBITMAP hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(hdc, hbm));
+
+ HBRUSH brb = ::CreateSolidBrush(RGB(20, 20, 20));
+ ::FillRect(hdc, &rcContainer, brb);
+ ::DeleteObject(brb);
+ CImageItem::SetBitmap32Alpha(hbm, 100);
+
+ LRESULT first = ::SendMessage(hwndRich, EM_CHARFROMPOS, 0, reinterpret_cast<LPARAM>(&ptOrigin));
+
+ /*
+ * paint the content of the message log control into a separate bitmap without
+ * transparency
+ */
+ HDC hdcRich = ::CreateCompatibleDC(dc);
+ HBITMAP hbmRich = CSkin::CreateAeroCompatibleBitmap(rcRich, hdcRich);
+ HBITMAP hbmRichOld = reinterpret_cast<HBITMAP>(::SelectObject(hdcRich, hbmRich));
+
+ COLORREF clr = fIsChat ? M->GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR) : m_dat->pContainer->theme.inbg;
+ HBRUSH br = ::CreateSolidBrush(clr);
+ ::FillRect(hdcRich, &rcRich, br);
+ ::DeleteObject(br);
+
+ if(m_dat->hwndIEView)
+ ::SendMessage(m_dat->hwndIEView, WM_PRINT, reinterpret_cast<WPARAM>(hdcRich), PRF_CLIENT | PRF_NONCLIENT);
+ else if(m_dat->hwndHPP) {
+ CSkin::RenderText(hdcRich, m_dat->hTheme, CTranslator::get(CTranslator::GEN_AEROPEEK_NOHPP),
+ &rcRich, DT_VCENTER | DT_CENTER | DT_WORDBREAK, 10, m_dat->pContainer->theme.fontColors[MSGFONTID_MYMSG], false);
+ }
+ else {
+ rcRich.right *= twips;
+ rcRich.bottom *= twips;
+
+ fr.hdc = hdcRich;
+ fr.hdcTarget = hdcRich;
+ fr.rc = rcRich;
+ fr.rcPage = rcRich;
+ fr.chrg.cpMax = -1;
+ fr.chrg.cpMin = first;
+
+ ::SendMessage(hwndRich, EM_FORMATRANGE, 1, reinterpret_cast<LPARAM>(&fr));
+ }
+
+ ::SelectObject(hdcRich, hbmRichOld);
+ CImageItem::SetBitmap32Alpha(hbmRich, 255);
+ ::SelectObject(hdcRich, hbmRich);
+ ::BitBlt(hdc, pt.x, pt.y, cx, cy, hdcRich, 0, 0, SRCCOPY);
+ ::SelectObject(hdcRich, hbmRichOld);
+ ::DeleteObject(hbmRich);
+ ::DeleteDC(hdcRich);
+
+ ::SelectObject(hdc, hbmOld);
+ ::DeleteDC(hdc);
+ if(CSkin::m_skinEnabled && CSkin::m_frameSkins) {
+ pt.x = CSkin::m_SkinnedFrame_left;
+ pt.y = CSkin::m_SkinnedFrame_caption + CSkin::m_SkinnedFrame_bottom;
+ }
+ else
+ pt.x = pt.y = 0;
+ CMimAPI::m_pfnDwmSetIconicLivePreviewBitmap(m_hwndProxy, hbm, &pt, m_dat->pContainer->dwFlags & CNT_CREATE_MINIMIZED ? 0 : DWM_SIT_DISPLAYFRAME);
+ ::ReleaseDC(m_dat->hwnd, dc);
+ ::DeleteObject(hbm);
+ }
+}
+
+/**
+ * set the large icon for the thumbnail. This is mostly used by group chats
+ * to indicate last active event in the session.
+ *
+ * hIcon may be 0 to remove a custom big icon. In that case, the renderer
+ * will try to figure out a suitable one, based on session data.
+ *
+ * @param hIcon icon handle (should be a 32x32 icon)
+ * @param fInvalidate invalidate the thumbnail (default value = true)
+ */
+void CProxyWindow::setBigIcon(const HICON hIcon, bool fInvalidate)
+{
+ m_hBigIcon = hIcon;
+ if(fInvalidate)
+ Invalidate();
+}
+
+/**
+ * set a overlay icon for the thumbnail. This is mostly used by group chats
+ * to indicate last active event in the session.
+ *
+ * hIcon may be 0 to remove a custom overlay icon.
+ *
+ * @param hIcon icon handle (should be a 16x16 icon)
+ * @param fInvalidate invalidate the thumbnail (default value = true)
+ */
+void CProxyWindow::setOverlayIcon(const HICON hIcon, bool fInvalidate)
+{
+ m_hOverlayIcon = hIcon;
+ if(fInvalidate)
+ Invalidate();
+}
+
+/**
+ * update the (small) thumbnail icon in front of the title string
+ * @param hIcon new icon handle
+ */
+void CProxyWindow::updateIcon(const HICON hIcon) const
+{
+ if(m_hwndProxy && hIcon)
+ ::SendMessage(m_hwndProxy, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hIcon));
+}
+
+/**
+ * set the task bar button ("tab") active. This activates the proxy
+ * window as a sub-window of the (top level) container window.
+ * This is called whenever the active message tab or window changes
+ */
+void CProxyWindow::activateTab() const
+{
+ Win7Taskbar->SetTabActive(m_hwndProxy, m_dat->pContainer->hwnd);
+}
+/**
+ * invalidate the thumbnail, it will be recreated at the next request
+ * by the DWM
+ *
+ * this is called from several places whenever a relevant information,
+ * represented in a thumbnail image, has changed.
+ *
+ * also tell the DWM that it must request a new thumb.
+ */
+void CProxyWindow::Invalidate() const
+{
+ if(m_thumb) {
+ m_thumb->setValid(false);
+ /*
+ * tell the DWM to request a new thumbnail for the proxy window m_hwnd
+ * when it needs one.
+ */
+ CMimAPI::m_pfnDwmInvalidateIconicBitmaps(m_hwndProxy);
+ }
+}
+
+/**
+ * update the thumb title string (usually, the nickname)
+ * @param tszTitle: new title string
+ */
+void CProxyWindow::updateTitle(const TCHAR *tszTitle) const
+{
+ if(m_hwndProxy && tszTitle)
+ ::SetWindowText(m_hwndProxy, tszTitle);
+}
+
+/**
+ * stub window procedure for the custom proxy window class
+ * just initialize GWLP_USERDATA and call the object's method
+ *
+ * static member function
+ */
+LRESULT CALLBACK CProxyWindow::stubWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CProxyWindow* pWnd = reinterpret_cast<CProxyWindow *>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
+
+ if(pWnd)
+ return(pWnd->wndProc(hWnd, msg, wParam, lParam));
+
+ switch(msg) {
+ case WM_NCCREATE: {
+ CREATESTRUCT *cs = reinterpret_cast<CREATESTRUCT *>(lParam);
+ CProxyWindow *pWnd = reinterpret_cast<CProxyWindow *>(cs->lpCreateParams);
+ ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<UINT_PTR>(pWnd));
+ return(pWnd->wndProc(hWnd, msg, wParam, lParam));
+ }
+ default:
+ break;
+ }
+ return(::DefWindowProc(hWnd, msg, wParam, lParam));
+}
+
+/**
+ * window procedure for the proxy window
+ */
+LRESULT CALLBACK CProxyWindow::wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+
+#if defined(__LOGDEBUG_)
+ case WM_NCCREATE:
+ _DebugTraceW(_T("create proxy WINDOW for: %s"), m_dat->cache->getNick());
+ break;
+#endif
+ case WM_CLOSE: {
+ TContainerData* pC = m_dat->pContainer;
+
+ if(m_dat->hwnd != pC->hwndActive)
+ SendMessage(m_dat->hwnd, WM_CLOSE, 1, 3);
+ else
+ SendMessage(m_dat->hwnd, WM_CLOSE, 1, 2);
+ if(!IsIconic(pC->hwnd))
+ SetForegroundWindow(pC->hwnd);
+ return(0);
+ }
+
+ /*
+ * proxy window was activated by clicking on the thumbnail. Send this
+ * to the real message window.
+ */
+ case WM_ACTIVATE:
+ if(WA_ACTIVE == wParam) {
+ if(IsWindow(m_dat->hwnd))
+ ::PostMessage(m_dat->hwnd, DM_ACTIVATEME, 0, 0);
+ return(0); // no default processing, avoid flickering.
+ }
+ break;
+
+ case WM_NCDESTROY:
+ ::SetWindowLongPtr(hWnd, GWLP_USERDATA, 0);
+#if defined(__LOGDEBUG_)
+ _DebugTraceW(_T("destroy proxy WINDOW for: %s"), m_dat->cache->getNick());
+#endif
+ break;
+
+ case WM_DWMSENDICONICTHUMBNAIL:
+ sendThumb(HIWORD(lParam), LOWORD(lParam));
+ return(0);
+
+ case WM_DWMSENDICONICLIVEPREVIEWBITMAP:
+ sendPreview();
+ return(0);
+
+ default:
+ break;
+ }
+ return(::DefWindowProc(hWnd, msg, wParam, lParam));
+}
+
+/**
+ * base thumbnail class. Create the background and common parts for a
+ * thumbnail
+ *
+ * @param _p owner proxy window object
+ * @return
+ */
+CThumbBase::CThumbBase(const CProxyWindow* _p)
+{
+ m_pWnd = _p;
+ m_hbmThumb = 0;
+ renderBase();
+}
+
+/**
+ * render base for a thumbnail. This creates the background, the large icon
+ * and the basic status mode text. It also divides the thumbnail rectangle
+ * into a few content rectangles used later by the content renderer.
+ */
+void CThumbBase::renderBase()
+{
+ HICON hIcon = 0;
+ HBRUSH brBack;
+ LONG lIconSize = 32;
+
+ m_width = m_pWnd->getWidth();
+ m_height = m_pWnd->getHeight();
+ m_dat = m_pWnd->getDat();
+ m_dtFlags = 0;
+ m_hOldFont = 0;
+
+#if defined(__LOGDEBUG_)
+ _DebugTraceW(_T("refresh base (background) with %d, %d"), m_width, m_height);
+#endif
+
+ m_rc.right = m_width;
+ m_rc.bottom = m_height;
+ m_rc.left = m_rc.top = 0;
+
+ if(m_hbmThumb) {
+ ::DeleteObject(m_hbmThumb);
+ m_hbmThumb = 0;
+ }
+
+ HDC dc = ::GetDC(m_pWnd->getHwnd());
+ m_hdc = ::CreateCompatibleDC(dc);
+
+ m_hbmThumb = CSkin::CreateAeroCompatibleBitmap(m_rc, m_hdc);
+ m_hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(m_hdc, m_hbmThumb));
+ ReleaseDC(m_pWnd->getHwnd(), dc);
+
+ brBack = ::CreateSolidBrush(m_dat->dwUnread ? RGB(80, 60, 60) : RGB(60, 60, 60));
+ ::FillRect(m_hdc, &m_rc, brBack);
+ ::DeleteObject(brBack);
+
+ ::SelectObject(m_hdc, m_hbmOld);
+ CImageItem::SetBitmap32Alpha(m_hbmThumb, m_dat->dwUnread ? 110 : 60);
+ m_hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(m_hdc, m_hbmThumb));
+
+ SetBkMode(m_hdc, TRANSPARENT);
+
+ m_hOldFont = reinterpret_cast<HFONT>(::SelectObject(m_hdc, CInfoPanel::m_ipConfig.hFonts[IPFONTID_STATUS]));
+ ::GetTextExtentPoint32A(m_hdc, "A", 1, &m_sz);
+
+ InflateRect(&m_rc, -3, -3);
+
+ setupRect();
+ hIcon = m_pWnd->getBigIcon();
+
+ if(0 == hIcon) {
+ if(m_dat->dwUnread) {
+ if(PluginConfig.g_IconMsgEventBig)
+ hIcon = PluginConfig.g_IconMsgEventBig;
+ else {
+ hIcon = PluginConfig.g_IconMsgEvent;
+ lIconSize = 16;
+ }
+ }
+ else {
+ hIcon = reinterpret_cast<HICON>(LoadSkinnedProtoIconBig(m_dat->cache->getActiveProto(), m_dat->cache->getActiveStatus()));
+ if(0 == hIcon || reinterpret_cast<HICON>(CALLSERVICE_NOTFOUND) == hIcon) {
+ hIcon = reinterpret_cast<HICON>(LoadSkinnedProtoIcon(m_dat->cache->getActiveProto(), m_dat->cache->getActiveStatus()));
+ lIconSize = 16;
+ }
+ }
+ }
+ ::DrawIconEx(m_hdc, m_rcIcon.right / 2 - lIconSize / 2, m_rcIcon.top, hIcon, lIconSize, lIconSize, 0, 0, DI_NORMAL);
+ hIcon = m_pWnd->getOverlayIcon();
+ if(hIcon)
+ ::DrawIconEx(m_hdc, m_rcIcon.right - 16, m_rcIcon.top + 16, hIcon, 16, 16, 0, 0, DI_NORMAL);
+
+ m_rcIcon.top += (lIconSize + 3);
+ CSkin::RenderText(m_hdc, m_dat->hTheme, m_dat->szStatus, &m_rcIcon, m_dtFlags | DT_CENTER | DT_WORD_ELLIPSIS, 10, 0, true);
+ if(m_dat->dwUnread && SESSIONTYPE_IM == m_dat->bType) {
+ wchar_t tszTemp[30];
+
+ m_rcIcon.top += m_sz.cy;
+ mir_sntprintf(tszTemp, 30, CTranslator::get(CTranslator::GEN_TASKBAR_STRING_UNREAD), m_dat->dwUnread);
+ CSkin::RenderText(m_hdc, m_dat->hTheme, tszTemp, &m_rcIcon, m_dtFlags | DT_CENTER | DT_WORD_ELLIPSIS, 10, 0, true);
+ }
+ m_rcIcon= m_rcTop;
+ m_rcIcon.top += 2;
+ m_rcIcon.left = m_rc.right / 3;
+ m_cx = m_rcIcon.right - m_rcIcon.left;
+ m_cy = m_rcIcon.bottom - m_rcIcon.top;
+}
+
+/**
+ * divide space into content rectangles for normal thumbnails
+ */
+void CThumbBase::setupRect()
+{
+ if(SESSIONTYPE_IM == m_pWnd->getDat()->bType) {
+ m_rcTop = m_rc;
+ m_rcBottom = m_rc;
+ m_rcBottom.top = m_rc.bottom - ( 2 * (m_rcBottom.bottom / 5)) - 2;
+ m_rcTop.bottom = m_rcBottom.top - 2;
+
+ m_rcIcon = m_rcTop;
+ m_rcIcon.right = m_rc.right / 3;
+ }
+ else {
+ m_rcTop = m_rc;
+ m_rcBottom = m_rc;
+ m_rcBottom.top = m_rc.bottom - ( 2 * (m_rcBottom.bottom / 5)) - 2;
+ m_rcTop.bottom = m_rcBottom.top - 2;
+
+ m_rcIcon = m_rcTop;
+ m_rcIcon.right = m_rc.left + 42;
+ }
+}
+
+/**
+ * destroy the thumbnail object. Just delete the bitmap we cached
+ * @return
+ */
+CThumbBase::~CThumbBase()
+{
+ if(m_hbmThumb) {
+ ::DeleteObject(m_hbmThumb);
+ m_hbmThumb = 0;
+ m_isValid = false;
+ }
+#if defined(__LOGDEBUG_)
+ _DebugTraceW(_T("destroy CThumbBase"));
+#endif
+}
+
+/**
+ * create a IM session thumbnail. base class will create the
+ * bitmap and render the background.
+ *
+ * @param _p our owner (CProxyWindow object)
+ */
+CThumbIM::CThumbIM(const CProxyWindow* _p) : CThumbBase(_p)
+{
+ renderContent();
+ setValid(true);
+}
+
+/**
+ * update the thumbnail, render everything and set it valid
+ */
+void CThumbIM::update()
+{
+ renderBase();
+ renderContent();
+ setValid(true);
+}
+
+/**
+ * render the content for an IM chat session thumbnail
+ * m_hdc etc. must already be initialized (done by the constructor)
+ * background had been already rendered
+ */
+void CThumbIM::renderContent()
+{
+ HBITMAP hbmAvatar, hbmOldAv;
+ double dNewWidth = 0.0, dNewHeight = 0.0;
+ bool fFree = false;
+ HRGN hRgn = 0;
+ HDC dc;
+ const wchar_t* tszStatusMsg = 0;
+
+ hbmAvatar = (m_dat->ace && m_dat->ace->hbmPic) ? m_dat->ace->hbmPic : PluginConfig.g_hbmUnknown;
+ Utils::scaleAvatarHeightLimited(hbmAvatar, dNewWidth, dNewHeight, m_rcIcon.bottom - m_rcIcon.top);
+
+ HBITMAP hbmResized = CSkin::ResizeBitmap(hbmAvatar, dNewWidth, dNewHeight, fFree);
+
+ dc = CreateCompatibleDC(m_hdc);
+ hbmOldAv = reinterpret_cast<HBITMAP>(::SelectObject(dc, hbmResized));
+
+ LONG xOff = m_rcIcon.right - (LONG)dNewWidth - 2;
+ LONG yOff = (m_cy - (LONG)dNewHeight) / 2 + m_rcIcon.top;
+
+ hRgn = ::CreateRectRgn(xOff - 1, yOff - 1, xOff + (LONG)dNewWidth + 2, yOff + (LONG)dNewHeight + 2);
+ CSkin::m_default_bf.SourceConstantAlpha = 150;
+ CMimAPI::m_MyAlphaBlend(m_hdc, xOff, yOff, (LONG)dNewWidth, (LONG)dNewHeight, dc, 0, 0, (LONG)dNewWidth, (LONG)dNewHeight, CSkin::m_default_bf);
+ CSkin::m_default_bf.SourceConstantAlpha = 255;
+ ::FrameRgn(m_hdc, hRgn, reinterpret_cast<HBRUSH>(::GetStockObject(BLACK_BRUSH)), 1, 1);
+
+ ::DeleteObject(hRgn);
+ ::SelectObject(dc, hbmOldAv);
+
+ if(hbmResized != hbmAvatar)
+ ::DeleteObject(hbmResized);
+
+ ::DeleteDC(dc);
+ m_rcBottom.bottom -= 16;
+
+ /*
+ * status message and bottom line (either UID or nick name, depending on
+ * task bar grouping mode). For chat rooms, it is the topic.
+ */
+ if((m_rcBottom.bottom - m_rcBottom.top) < 2 * m_sz.cy)
+ m_dtFlags |= DT_SINGLELINE;
+
+ m_rcBottom.bottom -= ((m_rcBottom.bottom - m_rcBottom.top) % m_sz.cy); // adjust to a multiple of line height
+
+ if(0 == (tszStatusMsg = m_dat->cache->getStatusMsg()))
+ tszStatusMsg = CTranslator::get(CTranslator::GEN_NO_STATUS);
+
+ CSkin::RenderText(m_hdc, m_dat->hTheme, tszStatusMsg, &m_rcBottom, DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | m_dtFlags, 10, 0, true);
+ m_rcBottom.bottom = m_rc.bottom;
+ m_rcBottom.top = m_rcBottom.bottom - m_sz.cy - 2;
+ CSkin::RenderText(m_hdc, m_dat->hTheme, Win7Taskbar->haveAlwaysGroupingMode() ? m_dat->cache->getUIN() : m_dat->cache->getNick(),
+ &m_rcBottom, m_dtFlags | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS, 10, 0, true);
+
+ /*
+ * finalize it
+ * do NOT delete the bitmap, the dwm will need the handle
+ * m_hbm is deleted when a new thumbnail is generated on dwm's request.
+ * this is not a leak!
+ */
+ if(m_hOldFont)
+ ::SelectObject(m_hdc, m_hOldFont);
+
+ ::SelectObject(m_hdc, m_hbmOld);
+ ::DeleteDC(m_hdc);
+}
+
+/**
+ * create a MUC session thumbnail. base class will create the
+ * bitmap and render the background.
+ *
+ * @param _p our owner (CProxyWindow object)
+ * @return
+ */
+CThumbMUC::CThumbMUC(const CProxyWindow* _p) : CThumbBase(_p)
+{
+ renderContent();
+ setValid(true);
+}
+
+/**
+ * update an invalidated thumbnail
+ */
+void CThumbMUC::update()
+{
+ renderBase();
+ renderContent();
+ setValid(true);
+}
+
+/**
+ * render content area for a MUC thumbnail
+ */
+void CThumbMUC::renderContent()
+{
+ if(m_dat->si) {
+ const MODULEINFO* mi = MM_FindModule(m_dat->si->pszModule);
+ wchar_t szTemp[250];
+ const wchar_t* szStatusMsg = 0;
+
+ if(mi) {
+ if(m_dat->dwUnread) {
+ mir_sntprintf(szTemp, 30, CTranslator::get(CTranslator::GEN_TASKBAR_STRING_UNREAD), m_dat->dwUnread);
+ CSkin::RenderText(m_hdc, m_dat->hTheme, szTemp, &m_rcIcon, m_dtFlags | DT_SINGLELINE | DT_RIGHT, 10, 0, true);
+ m_rcIcon.top += m_sz.cy;
+ }
+ if(m_dat->si->iType != GCW_SERVER) {
+ wchar_t* _p = NULL;
+ if ( m_dat->si->ptszStatusbarText )
+ _p = wcschr(m_dat->si->ptszStatusbarText, ']');
+ if( _p ) {
+ _p++;
+ wchar_t _t = *_p;
+ *_p = 0;
+ mir_sntprintf(szTemp, SIZEOF(szTemp), CTranslator::get(CTranslator::GEN_TASKBAR_STRING_CHAT_ROOM), m_dat->si->ptszStatusbarText);
+ *_p = _t;
+ }
+ else
+ mir_sntprintf(szTemp, SIZEOF(szTemp), CTranslator::get(CTranslator::GEN_TASKBAR_STRING_CHAT_ROOM), L"");
+ CSkin::RenderText(m_hdc, m_dat->hTheme, szTemp, &m_rcIcon, m_dtFlags | DT_SINGLELINE | DT_RIGHT, 10, 0, true);
+ m_rcIcon.top += m_sz.cy;
+ mir_sntprintf(szTemp, SIZEOF(szTemp), CTranslator::get(CTranslator::GEN_TASKBAR_STRING_USERS), m_dat->si->nUsersInNicklist);
+ CSkin::RenderText(m_hdc, m_dat->hTheme, szTemp, &m_rcIcon, m_dtFlags | DT_SINGLELINE | DT_RIGHT, 10, 0, true);
+ }
+ else {
+ mir_sntprintf(szTemp, SIZEOF(szTemp), CTranslator::get(CTranslator::GEN_TASKBAR_STRING_SERVER_WINDOW));
+ CSkin::RenderText(m_hdc, m_dat->hTheme, szTemp, &m_rcIcon, m_dtFlags | DT_SINGLELINE | DT_RIGHT, 10, 0, true);
+ if(mi->tszIdleMsg[0] && _tcslen(mi->tszIdleMsg) > 2) {
+ m_rcIcon.top += m_sz.cy;
+ CSkin::RenderText(m_hdc, m_dat->hTheme, &mi->tszIdleMsg[2], &m_rcIcon, m_dtFlags | DT_SINGLELINE | DT_RIGHT, 10, 0, true);
+ }
+ }
+ }
+
+ if((m_rcBottom.bottom - m_rcBottom.top) < 2 * m_sz.cy)
+ m_dtFlags |= DT_SINGLELINE;
+
+ m_rcBottom.bottom -= ((m_rcBottom.bottom - m_rcBottom.top) % m_sz.cy); // adjust to a multiple of line height
+
+ if(m_dat->si->iType != GCW_SERVER) {
+ if(0 == (szStatusMsg = m_dat->si->ptszTopic))
+ szStatusMsg = CTranslator::get(CTranslator::GEN_MUC_NO_TOPIC);
+ }
+ else if(mi) {
+ mir_sntprintf(szTemp, SIZEOF(szTemp), CTranslator::get(CTranslator::MUC_SBAR_ON_SERVER), m_dat->szMyNickname, mi->ptszModDispName, L"");
+ szStatusMsg = szTemp;
+ }
+
+ CSkin::RenderText(m_hdc, m_dat->hTheme, szStatusMsg, &m_rcBottom, DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | m_dtFlags, 10, 0, true);
+ }
+ /*
+ * finalize it
+ * do NOT delete the bitmap, the dwm will need the handle
+ * m_hbm is deleted when a new thumbnail is generated on dwm's request.
+ * this is not a leak!
+ */
+ if(m_hOldFont)
+ ::SelectObject(m_hdc, m_hOldFont);
+
+ ::SelectObject(m_hdc, m_hbmOld);
+ ::DeleteDC(m_hdc);
+}
diff --git a/plugins/TabSRMM/src/templates.cpp b/plugins/TabSRMM/src/templates.cpp
new file mode 100644
index 0000000000..74000f7e11
--- /dev/null
+++ b/plugins/TabSRMM/src/templates.cpp
@@ -0,0 +1,391 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: templates.cpp 13034 2010-10-24 20:39:04Z silvercircle $
+ *
+ * Simple editor for the message log templates
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+/*
+* hardcoded default set of templates for both LTR and RTL.
+* cannot be changed and may be used at any time to "revert" to a working layout
+*/
+
+char *TemplateNames[] = {
+ "Message In",
+ "Message Out",
+ "Group In (Start)",
+ "Group Out (Start)",
+ "Group In (Inner)",
+ "Group Out (Inner)",
+ "Status change",
+ "Error message"
+};
+
+TTemplateSet LTR_Default = { TRUE,
+ _T("%I %S %N %?&D%\\&E%\\!, %\\T%\\!: %?n%?S %?T%?|%M"),
+ _T("%I %S %N %?&D%\\&E%\\!, %\\T%\\!: %?n%?S %?T%?|%M"),
+ _T("%I %S %N %?&D%\\&E%\\!, %\\T%\\!: %?n%?S %?T%?|%M"),
+ _T("%I %S %N %?&D%\\&E%\\!, %\\T%\\!: %?n%?S %?T%?|%M"),
+ _T("%S %T%|%M"),
+ _T("%S %T%|%M"),
+ _T("%I %S %&D, %&T, %N %M%! "),
+ _T("%I%S %D, %T, %e%l%M"),
+ "Default LTR"
+ };
+
+TTemplateSet RTL_Default = { TRUE,
+ _T("%I %S %N %D%n%S %T%|%M"),
+ _T("%I %S %N %D%n%S %T%|%M"),
+ _T("%I %S %N %D%n%S %T%|%M"),
+ _T("%I %S %N %D%n%S %T%|%M"),
+ _T("%S %T%|%M"),
+ _T("%S %T%|%M"),
+ _T("%I%S %D, %T, %N %M%! "),
+ _T("%I%S %D, %T, %e%l%M"),
+ "Default RTL"
+ };
+
+TTemplateSet LTR_Active, RTL_Active;
+static int helpActive = 0;
+
+
+/*
+* loads template set overrides from hContact into the given set of already existing
+* templates
+*/
+
+static void LoadTemplatesFrom(TTemplateSet *tSet, HANDLE hContact, int rtl)
+{
+ DBVARIANT dbv = {0};
+ int i;
+
+ for (i = 0; i <= TMPL_ERRMSG; i++) {
+ if (M->GetTString(hContact, rtl ? RTLTEMPLATES_MODULE : TEMPLATES_MODULE, TemplateNames[i], &dbv))
+ continue;
+ if (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR)
+ mir_sntprintf(tSet->szTemplates[i], TEMPLATE_LENGTH, _T("%s"), dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+}
+
+void LoadDefaultTemplates()
+{
+ int i;
+
+ LTR_Active = LTR_Default;
+ RTL_Active = RTL_Default;
+
+ if (M->GetByte(RTLTEMPLATES_MODULE, "setup", 0) < 2) {
+ for (i = 0; i <= TMPL_ERRMSG; i++)
+ M->WriteTString(NULL, RTLTEMPLATES_MODULE, TemplateNames[i], RTL_Default.szTemplates[i]);
+ M->WriteByte(RTLTEMPLATES_MODULE, "setup", 2);
+ }
+ if (M->GetByte(TEMPLATES_MODULE, "setup", 0) < 2) {
+ for (i = 0; i <= TMPL_ERRMSG; i++)
+ M->WriteTString(NULL, TEMPLATES_MODULE, TemplateNames[i], LTR_Default.szTemplates[i]);
+ M->WriteByte(TEMPLATES_MODULE, "setup", 2);
+ }
+ LoadTemplatesFrom(&LTR_Active, (HANDLE)0, 0);
+ LoadTemplatesFrom(&RTL_Active, (HANDLE)0, 1);
+}
+
+INT_PTR CALLBACK DlgProcTemplateEditor(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct TWindowData *dat = 0;
+ TemplateEditorInfo *teInfo = 0;
+ TTemplateSet *tSet;
+ int i;
+ dat = (struct TWindowData *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ /*
+ * since this dialog needs a struct MessageWindowData * but has no container, we can store
+ * the extended info struct in pContainer *)
+ */
+ if (dat) {
+ teInfo = (TemplateEditorInfo *)dat->pContainer;
+ tSet = teInfo->rtl ? dat->pContainer->rtl_templates : dat->pContainer->ltr_templates;
+ }
+
+ switch (msg) {
+ case WM_INITDIALOG: {
+ TemplateEditorNew *teNew = (TemplateEditorNew *)lParam;
+ COLORREF url_visited = RGB(128, 0, 128);
+ COLORREF url_unvisited = RGB(0, 0, 255);
+ dat = (struct TWindowData *) malloc(sizeof(struct TWindowData));
+
+ TranslateDialogDefault(hwndDlg);
+
+ ZeroMemory((void *) dat, sizeof(struct TWindowData));
+ dat->pContainer = (struct TContainerData *)malloc(sizeof(struct TContainerData));
+ ZeroMemory((void *)dat->pContainer, sizeof(struct TContainerData));
+ teInfo = (TemplateEditorInfo *)dat->pContainer;
+ ZeroMemory((void *)teInfo, sizeof(TemplateEditorInfo));
+ teInfo->hContact = teNew->hContact;
+ teInfo->rtl = teNew->rtl;
+ teInfo->hwndParent = teNew->hwndParent;
+
+ LoadOverrideTheme(dat->pContainer);
+ /*
+ * set hContact to the first found contact so that we can use the Preview window properly
+ * also, set other parameters needed by the streaming function to display events
+ */
+
+ SendDlgItemMessage(hwndDlg, IDC_PREVIEW, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_LINK);
+ SendDlgItemMessage(hwndDlg, IDC_PREVIEW, EM_SETEDITSTYLE, SES_EXTENDBACKCOLOR, SES_EXTENDBACKCOLOR);
+ SendDlgItemMessage(hwndDlg, IDC_PREVIEW, EM_EXLIMITTEXT, 0, 0x80000000);
+
+ dat->hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ dat->szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)dat->hContact, 0);
+ while(dat->szProto == 0 && dat->hContact != 0) {
+ dat->hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)dat->hContact, 0);
+ dat->szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)dat->hContact, 0);
+ }
+ dat->dwFlags = dat->pContainer->theme.dwFlags;
+
+ dat->cache = CContactCache::getContactCache(dat->hContact);
+ dat->cache->updateState();
+ dat->cache->updateUIN();
+ dat->cache->updateStats(TSessionStats::INIT_TIMER);
+ GetMYUIN(dat);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) dat);
+ ShowWindow(hwndDlg, SW_SHOW);
+ SendDlgItemMessage(hwndDlg, IDC_EDITTEMPLATE, EM_LIMITTEXT, (WPARAM)TEMPLATE_LENGTH - 1, 0);
+ SetWindowText(hwndDlg, CTranslator::getOpt(CTranslator::OPT_TEMP_TITLE));
+ Utils::enableDlgControl(hwndDlg, IDC_SAVETEMPLATE, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_REVERT, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_FORGET, FALSE);
+ for (i = 0; i <= TMPL_ERRMSG; i++) {
+ SendDlgItemMessageA(hwndDlg, IDC_TEMPLATELIST, LB_ADDSTRING, 0, (LPARAM)Translate(TemplateNames[i]));
+ SendDlgItemMessage(hwndDlg, IDC_TEMPLATELIST, LB_SETITEMDATA, i, (LPARAM)i);
+ }
+ Utils::enableDlgControl(teInfo->hwndParent, IDC_MODIFY, FALSE);
+ Utils::enableDlgControl(teInfo->hwndParent, IDC_RTLMODIFY, FALSE);
+
+ SendDlgItemMessage(hwndDlg, IDC_COLOR1, CPM_SETCOLOUR, 0, M->GetDword("cc1", SRMSGDEFSET_BKGCOLOUR));
+ SendDlgItemMessage(hwndDlg, IDC_COLOR2, CPM_SETCOLOUR, 0, M->GetDword("cc2", SRMSGDEFSET_BKGCOLOUR));
+ SendDlgItemMessage(hwndDlg, IDC_COLOR3, CPM_SETCOLOUR, 0, M->GetDword("cc3", SRMSGDEFSET_BKGCOLOUR));
+ SendDlgItemMessage(hwndDlg, IDC_COLOR4, CPM_SETCOLOUR, 0, M->GetDword("cc4", SRMSGDEFSET_BKGCOLOUR));
+ SendDlgItemMessage(hwndDlg, IDC_COLOR5, CPM_SETCOLOUR, 0, M->GetDword("cc5", SRMSGDEFSET_BKGCOLOUR));
+ SendMessage(GetDlgItem(hwndDlg, IDC_EDITTEMPLATE), EM_SETREADONLY, TRUE, 0);
+ return(TRUE);
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ case IDC_RESETALLTEMPLATES:
+ if (MessageBox(0, CTranslator::getOpt(CTranslator::OPT_TEMP_RESET),
+ CTranslator::getOpt(CTranslator::OPT_TEMP_TITLE), MB_YESNO | MB_ICONQUESTION) == IDYES) {
+ M->WriteByte(teInfo->rtl ? RTLTEMPLATES_MODULE : TEMPLATES_MODULE, "setup", 0);
+ LoadDefaultTemplates();
+ MessageBox(0, CTranslator::getOpt(CTranslator::OPT_TEMP_WASRESET),
+ CTranslator::getOpt(CTranslator::OPT_TEMP_TITLE), MB_OK);
+ DestroyWindow(hwndDlg);
+ }
+ break;
+ case IDC_TEMPLATELIST:
+ switch (HIWORD(wParam)) {
+ case LBN_DBLCLK: {
+ LRESULT iIndex = SendDlgItemMessage(hwndDlg, IDC_TEMPLATELIST, LB_GETCURSEL, 0, 0);
+ if (iIndex != LB_ERR) {
+ SetDlgItemText(hwndDlg, IDC_EDITTEMPLATE, tSet->szTemplates[iIndex]);
+ teInfo->inEdit = iIndex;
+ teInfo->changed = FALSE;
+ teInfo->selchanging = FALSE;
+ SetFocus(GetDlgItem(hwndDlg, IDC_EDITTEMPLATE));
+ SendMessage(GetDlgItem(hwndDlg, IDC_EDITTEMPLATE), EM_SETREADONLY, FALSE, 0);
+ }
+ break;
+ }
+ case LBN_SELCHANGE: {
+ LRESULT iIndex = SendDlgItemMessage(hwndDlg, IDC_TEMPLATELIST, LB_GETCURSEL, 0, 0);
+ teInfo->selchanging = TRUE;
+ if (iIndex != LB_ERR) {
+ SetDlgItemText(hwndDlg, IDC_EDITTEMPLATE, tSet->szTemplates[iIndex]);
+ teInfo->inEdit = iIndex;
+ teInfo->changed = FALSE;
+ }
+ SendMessage(GetDlgItem(hwndDlg, IDC_EDITTEMPLATE), EM_SETREADONLY, TRUE, 0);
+ break;
+ }
+ }
+ break;
+ case IDC_VARIABLESHELP:
+ CallService(MS_UTILS_OPENURL, 0, (LPARAM)"http://wiki.miranda.or.at/TabSRMM/Templates");
+ break;
+ case IDC_EDITTEMPLATE:
+ if (HIWORD(wParam) == EN_CHANGE) {
+ if (!teInfo->selchanging) {
+ teInfo->changed = TRUE;
+ teInfo->updateInfo[teInfo->inEdit] = TRUE;
+ Utils::enableDlgControl(hwndDlg, IDC_SAVETEMPLATE, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_FORGET, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_TEMPLATELIST, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_REVERT, TRUE);
+ }
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_TEMPLATELIST), NULL, FALSE);
+ }
+ break;
+ case IDC_SAVETEMPLATE: {
+ TCHAR newTemplate[TEMPLATE_LENGTH + 2];
+
+ GetWindowText(GetDlgItem(hwndDlg, IDC_EDITTEMPLATE), newTemplate, TEMPLATE_LENGTH);
+ CopyMemory(tSet->szTemplates[teInfo->inEdit], newTemplate, sizeof(TCHAR) * TEMPLATE_LENGTH);
+ teInfo->changed = FALSE;
+ teInfo->updateInfo[teInfo->inEdit] = FALSE;
+ Utils::enableDlgControl(hwndDlg, IDC_SAVETEMPLATE, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_FORGET, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_TEMPLATELIST, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_REVERT, FALSE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_TEMPLATELIST), NULL, FALSE);
+ M->WriteTString(teInfo->hContact, teInfo->rtl ? RTLTEMPLATES_MODULE : TEMPLATES_MODULE, TemplateNames[teInfo->inEdit], newTemplate);
+ SendMessage(GetDlgItem(hwndDlg, IDC_EDITTEMPLATE), EM_SETREADONLY, TRUE, 0);
+ break;
+ }
+ case IDC_FORGET: {
+ teInfo->changed = FALSE;
+ teInfo->updateInfo[teInfo->inEdit] = FALSE;
+ teInfo->selchanging = TRUE;
+ SetDlgItemText(hwndDlg, IDC_EDITTEMPLATE, tSet->szTemplates[teInfo->inEdit]);
+ SetFocus(GetDlgItem(hwndDlg, IDC_EDITTEMPLATE));
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_TEMPLATELIST), NULL, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_SAVETEMPLATE, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_FORGET, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_TEMPLATELIST, TRUE);
+ Utils::enableDlgControl(hwndDlg, IDC_REVERT, FALSE);
+ teInfo->selchanging = FALSE;
+ SendMessage(GetDlgItem(hwndDlg, IDC_EDITTEMPLATE), EM_SETREADONLY, TRUE, 0);
+ break;
+ }
+ case IDC_REVERT: {
+ teInfo->changed = FALSE;
+ teInfo->updateInfo[teInfo->inEdit] = FALSE;
+ teInfo->selchanging = TRUE;
+ CopyMemory(tSet->szTemplates[teInfo->inEdit], LTR_Default.szTemplates[teInfo->inEdit], sizeof(TCHAR) * TEMPLATE_LENGTH);
+ SetDlgItemText(hwndDlg, IDC_EDITTEMPLATE, tSet->szTemplates[teInfo->inEdit]);
+ DBDeleteContactSetting(teInfo->hContact, teInfo->rtl ? RTLTEMPLATES_MODULE : TEMPLATES_MODULE, TemplateNames[teInfo->inEdit]);
+ SetFocus(GetDlgItem(hwndDlg, IDC_EDITTEMPLATE));
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_TEMPLATELIST), NULL, FALSE);
+ teInfo->selchanging = FALSE;
+ Utils::enableDlgControl(hwndDlg, IDC_SAVETEMPLATE, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_REVERT, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_FORGET, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_TEMPLATELIST, TRUE);
+ SendMessage(GetDlgItem(hwndDlg, IDC_EDITTEMPLATE), EM_SETREADONLY, TRUE, 0);
+ break;
+ }
+ case IDC_UPDATEPREVIEW:
+ SendMessage(hwndDlg, DM_UPDATETEMPLATEPREVIEW, 0, 0);
+ break;
+ }
+ break;
+ case WM_DRAWITEM: {
+ DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *) lParam;
+ int iItem = dis->itemData;
+ HBRUSH bkg, oldBkg;
+ SetBkMode(dis->hDC, TRANSPARENT);
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_WINDOW));
+ if (dis->itemState & ODS_SELECTED) {
+ if (teInfo->updateInfo[iItem] == TRUE) {
+ bkg = CreateSolidBrush(RGB(255, 0, 0));
+ oldBkg = (HBRUSH)SelectObject(dis->hDC, bkg);
+ FillRect(dis->hDC, &dis->rcItem, bkg);
+ SelectObject(dis->hDC, oldBkg);
+ DeleteObject(bkg);
+ } else
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT));
+
+ SetTextColor(dis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ } else {
+ if (teInfo->updateInfo[iItem] == TRUE)
+ SetTextColor(dis->hDC, RGB(255, 0, 0));
+ else
+ SetTextColor(dis->hDC, GetSysColor(COLOR_WINDOWTEXT));
+ }
+ char *pszName = Translate(TemplateNames[iItem]);
+ TextOutA(dis->hDC, dis->rcItem.left, dis->rcItem.top, pszName, lstrlenA(pszName));
+ return(TRUE);
+ }
+ case DM_UPDATETEMPLATEPREVIEW: {
+ DBEVENTINFO dbei = {0};
+ int iIndex = SendDlgItemMessage(hwndDlg, IDC_TEMPLATELIST, LB_GETCURSEL, 0, 0);
+ TCHAR szTemp[TEMPLATE_LENGTH + 2];
+
+ if (teInfo->changed) {
+ CopyMemory(szTemp, tSet->szTemplates[teInfo->inEdit], TEMPLATE_LENGTH * sizeof(TCHAR));
+ GetDlgItemText(hwndDlg, IDC_EDITTEMPLATE, tSet->szTemplates[teInfo->inEdit], TEMPLATE_LENGTH);
+ }
+ dbei.szModule = dat->szProto;
+ dbei.timestamp = time(NULL);
+ dbei.eventType = (iIndex == 6) ? EVENTTYPE_STATUSCHANGE : EVENTTYPE_MESSAGE;
+ dbei.eventType = (iIndex == 7) ? EVENTTYPE_ERRMSG : dbei.eventType;
+ if (dbei.eventType == EVENTTYPE_ERRMSG)
+ dbei.szModule = "Sample error message";
+ dbei.cbSize = sizeof(dbei);
+ dbei.pBlob = (iIndex == 6) ? (BYTE *)"is now offline (was online)" : (BYTE *)"The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.";
+ dbei.cbBlob = lstrlenA((char *)dbei.pBlob) + 1;
+ dbei.flags = (iIndex == 1 || iIndex == 3 || iIndex == 5) ? DBEF_SENT : 0;
+ dbei.flags |= (teInfo->rtl ? DBEF_RTL : 0);
+ dat->lastEventTime = (iIndex == 4 || iIndex == 5) ? time(NULL) - 1 : 0;
+ dat->iLastEventType = MAKELONG(dbei.flags, dbei.eventType);
+ SetWindowText(GetDlgItem(hwndDlg, IDC_PREVIEW), _T(""));
+ dat->dwFlags = MWF_LOG_ALL;
+ dat->dwFlags = (teInfo->rtl ? dat->dwFlags | MWF_LOG_RTL : dat->dwFlags & ~MWF_LOG_RTL);
+ dat->dwFlags = (iIndex == 0 || iIndex == 1) ? dat->dwFlags & ~MWF_LOG_GROUPMODE : dat->dwFlags | MWF_LOG_GROUPMODE;
+ mir_sntprintf(dat->szMyNickname, safe_sizeof(dat->szMyNickname), _T("My Nickname"));
+ StreamInEvents(hwndDlg, 0, 1, 1, &dbei);
+ SendDlgItemMessage(hwndDlg, IDC_PREVIEW, EM_SETSEL, -1, -1);
+ if (teInfo->changed)
+ CopyMemory(tSet->szTemplates[teInfo->inEdit], szTemp, TEMPLATE_LENGTH * sizeof(TCHAR));
+ break;
+ }
+ case WM_DESTROY:
+ Utils::enableDlgControl(teInfo->hwndParent, IDC_MODIFY, TRUE);
+ Utils::enableDlgControl(teInfo->hwndParent, IDC_RTLMODIFY, TRUE);
+ if (dat->pContainer)
+ free(dat->pContainer);
+ if (dat)
+ free(dat);
+
+ M->WriteDword(SRMSGMOD_T, "cc1", SendDlgItemMessage(hwndDlg, IDC_COLOR1, CPM_GETCOLOUR, 0, 0));
+ M->WriteDword(SRMSGMOD_T, "cc2", SendDlgItemMessage(hwndDlg, IDC_COLOR2, CPM_GETCOLOUR, 0, 0));
+ M->WriteDword(SRMSGMOD_T, "cc3", SendDlgItemMessage(hwndDlg, IDC_COLOR3, CPM_GETCOLOUR, 0, 0));
+ M->WriteDword(SRMSGMOD_T, "cc4", SendDlgItemMessage(hwndDlg, IDC_COLOR4, CPM_GETCOLOUR, 0, 0));
+ M->WriteDword(SRMSGMOD_T, "cc5", SendDlgItemMessage(hwndDlg, IDC_COLOR5, CPM_GETCOLOUR, 0, 0));
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+ break;
+ }
+ return(FALSE);
+}
diff --git a/plugins/TabSRMM/src/themeio.cpp b/plugins/TabSRMM/src/themeio.cpp
new file mode 100644
index 0000000000..a331d921c1
--- /dev/null
+++ b/plugins/TabSRMM/src/themeio.cpp
@@ -0,0 +1,474 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: themeio.cpp 13412 2011-03-08 19:13:11Z george.hazan $
+ *
+ * Import and export theme settings between files and the database
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+
+#define CURRENT_THEME_VERSION 5
+#define THEME_COOKIE 25099837
+
+extern char *TemplateNames[];
+extern TTemplateSet LTR_Active, RTL_Active;
+
+
+static struct _tagExtSettings {
+ char* szIniSection;
+ char* szIniName;
+ char* szDbModule;
+ char* szDbSetting;
+ DWORD dwDef;
+} _extSettings[12] = {
+ "Message Log", "BackgroundColor", FONTMODULE, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR,
+ "Message Log", "IncomingBG", FONTMODULE, "inbg", SRMSGDEFSET_BKGINCOLOUR,
+ "Message Log", "OutgoingBG", FONTMODULE, "outbg", SRMSGDEFSET_BKGOUTCOLOUR,
+ "Message Log", "OldIncomingBG", FONTMODULE, "oldinbg", SRMSGDEFSET_BKGINCOLOUR,
+ "Message Log", "OldOutgoingBG", FONTMODULE, "oldoutbg", SRMSGDEFSET_BKGOUTCOLOUR,
+ "Message Log", "StatusBG", FONTMODULE, "statbg", SRMSGDEFSET_BKGCOLOUR,
+ "Message Log", "InputBG", FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR,
+ "Message Log", "HgridColor", FONTMODULE, "hgrid", SRMSGDEFSET_BKGCOLOUR,
+ "Message Log", "DWFlags", SRMSGMOD_T, "mwflags", MWF_LOG_DEFAULT,
+ "Chat", "UserListBG", "Chat", "ColorNicklistBG", SRMSGDEFSET_BKGCOLOUR,
+ "Message Log", "LeftIndent", SRMSGMOD_T, "IndentAmount", 20,
+ "Message Log", "RightIndent", SRMSGMOD_T, "RightIndent", 20,
+};
+
+/**
+ * new in TabSRMM3 / theme version 5
+ * don't read these values from themes with version < 5
+ */
+static struct _tagExtSettings_v5 {
+ char* szIniSection;
+ char* szIniName;
+ char* szDbModule;
+ char* szDbSetting;
+ DWORD dwDef;
+} _extSettings_v5[18] = {
+ "CommonClrs", "IP_High", FONTMODULE, "ipfieldsbgHigh", 0xf0f0f0,
+ "CommonClrs", "IP_Low", FONTMODULE, "ipfieldsbg", 0x62caff,
+ "CommonClrs", "TB_High", FONTMODULE, "tbBgHigh", 0,
+ "CommonClrs", "TB_Low", FONTMODULE, "tbBgLow", 0,
+ "CommonClrs", "FillColor", FONTMODULE, "fillColor", 0,
+ "CommonClrs", "RichBorders", FONTMODULE, "cRichBorders", 0,
+ "CommonClrs", "GenericTxt", FONTMODULE, "genericTxtClr", RGB(20, 20, 20),
+ "AeroMode", "Style", SRMSGMOD_T, "aerostyle", CSkin::AERO_EFFECT_MILK,
+ "AeroMode", "AeroGlowColor", FONTMODULE, "aeroGlow", RGB(40, 40, 255),
+
+ "Colored Tabs", "NormalText", SRMSGMOD_T, "tab_txt_normal", RGB(1, 1, 1),
+ "Colored Tabs", "ActiveText", SRMSGMOD_T, "tab_txt_active", RGB(1, 1, 1),
+ "Colored Tabs", "HottrackText", SRMSGMOD_T, "tab_txt_hottrack", RGB(1, 1, 1),
+ "Colored Tabs", "UnreadText", SRMSGMOD_T, "tab_txt_unread", RGB(1, 1, 1),
+
+ "Colored Tabs", "NormalBG", SRMSGMOD_T, "tab_bg_normal", 0xf0f0f0,
+ "Colored Tabs", "ActiveBG", SRMSGMOD_T, "tab_bg_active", 0xf0f0f0,
+ "Colored Tabs", "HottrackBG", SRMSGMOD_T, "tab_bg_hottrack", 0xf0f0f0,
+ "Colored Tabs", "UnreadBG", SRMSGMOD_T, "tab_bg_unread", 0xf0f0f0,
+ "Chat", "Background", FONTMODULE, SRMSGSET_BKGCOLOUR_MUC, SRMSGDEFSET_BKGCOLOUR
+};
+
+/*
+ * this loads a font definition from an INI file.
+ * i = font number
+ * szKey = ini section (e.g. [Font10])
+ * *lf = pointer to a LOGFONT structure which will receive the font definition
+ * *colour = pointer to a COLORREF which will receive the color of the font definition
+*/
+static void TSAPI LoadLogfontFromINI(int i, char *szKey, LOGFONTA *lf, COLORREF *colour, const char *szIniFilename)
+{
+ int style;
+ char bSize;
+
+ if (colour)
+ *colour = GetPrivateProfileIntA(szKey, "Color", 0, szIniFilename);
+
+ if (lf) {
+ HDC hdc = GetDC(NULL);
+ if (i == H_MSGFONTID_DIVIDERS)
+ lf->lfHeight = 5;
+ else {
+ bSize = (char)GetPrivateProfileIntA(szKey, "Size", -12, szIniFilename);
+ if (bSize > 0)
+ lf->lfHeight = -MulDiv(bSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ else
+ lf->lfHeight = bSize;
+ }
+
+ ReleaseDC(NULL, hdc);
+
+ lf->lfWidth = 0;
+ lf->lfEscapement = 0;
+ lf->lfOrientation = 0;
+ style = (int)GetPrivateProfileIntA(szKey, "Style", 0, szIniFilename);
+ lf->lfWeight = style & FONTF_BOLD ? FW_BOLD : FW_NORMAL;
+ lf->lfItalic = style & FONTF_ITALIC ? 1 : 0;
+ lf->lfUnderline = style & FONTF_UNDERLINE ? 1 : 0;
+ lf->lfStrikeOut = 0;
+ if (i == MSGFONTID_SYMBOLS_IN || i == MSGFONTID_SYMBOLS_OUT)
+ lf->lfCharSet = SYMBOL_CHARSET;
+ else
+ lf->lfCharSet = (BYTE)GetPrivateProfileIntA(szKey, "Set", DEFAULT_CHARSET, szIniFilename);
+ lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf->lfQuality = DEFAULT_QUALITY;
+ lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ if (i == MSGFONTID_SYMBOLS_IN || i == MSGFONTID_SYMBOLS_OUT) {
+ lstrcpynA(lf->lfFaceName, "Webdings", LF_FACESIZE);
+ lf->lfCharSet = SYMBOL_CHARSET;
+ } else
+ GetPrivateProfileStringA(szKey, "Face", "Tahoma", lf->lfFaceName, LF_FACESIZE - 1, szIniFilename);
+
+ /*
+ * filter out font attributes from the message input area font
+ * (can be disabled by db tweak)
+ */
+ if(!strcmp(szKey, "Font16") && M->GetByte(0, SRMSGMOD_T, "inputFontFix", 1) == 1) {
+ lf->lfWeight = FW_NORMAL;
+ lf->lfItalic = 0;
+ lf->lfUnderline = 0;
+ lf->lfStrikeOut = 0;
+ }
+ }
+}
+
+static struct _tagFontBlocks {
+ char *szModule;
+ int iFirst;
+ int iCount;
+ char *szIniTemp;
+ char *szBLockname;
+} fontBlocks[] = {
+ FONTMODULE, 0, MSGDLGFONTCOUNT, "Font%d", "StdFonts",
+ FONTMODULE, 100, IPFONTCOUNT, "IPFont%d", "MiscFonts",
+ CHAT_FONTMODULE, 0, CHATFONTCOUNT, "ChatFont%d", "ChatFonts",
+ NULL, 0, 0, NULL
+};
+
+int TSAPI CheckThemeVersion(const TCHAR *szIniFilename)
+{
+ int cookie = GetPrivateProfileInt(_T("TabSRMM Theme"), _T("Cookie"), 0, szIniFilename);
+ int version = GetPrivateProfileInt(_T("TabSRMM Theme"), _T("Version"), 0, szIniFilename);
+
+ if (version >= CURRENT_THEME_VERSION && cookie == THEME_COOKIE)
+ return 1;
+ return 0;
+}
+
+void TSAPI WriteThemeToINI(const TCHAR *szIniFilenameT, struct TWindowData *dat)
+{
+ int i, n = 0;
+ DBVARIANT dbv;
+ char szBuf[100], szTemp[100], szAppname[100];
+ COLORREF def;
+ char *szIniFilename = mir_u2a(szIniFilenameT);
+
+ WritePrivateProfileStringA("TabSRMM Theme", "Version", _itoa(CURRENT_THEME_VERSION, szBuf, 10), szIniFilename);
+ WritePrivateProfileStringA("TabSRMM Theme", "Cookie", _itoa(THEME_COOKIE, szBuf, 10), szIniFilename);
+
+ while (fontBlocks[n].szModule) {
+ int firstIndex = fontBlocks[n].iFirst;
+ char *szModule = fontBlocks[n].szModule;
+ WritePrivateProfileStringA(fontBlocks[n].szBLockname, "Valid", "1", szIniFilename);
+ for (i = 0; i < fontBlocks[n].iCount; i++) {
+ sprintf(szTemp, "Font%d", firstIndex + i);
+ sprintf(szAppname, fontBlocks[n].szIniTemp, firstIndex + i);
+ if (!DBGetContactSettingString(NULL, szModule, szTemp, &dbv)) {
+ WritePrivateProfileStringA(szAppname, "Face", dbv.pszVal, szIniFilename);
+ DBFreeVariant(&dbv);
+ }
+ sprintf(szTemp, "Font%dCol", firstIndex + i);
+ WritePrivateProfileStringA(szAppname, "Color", _itoa(M->GetDword(szModule, szTemp, 0), szBuf, 10), szIniFilename);
+ sprintf(szTemp, "Font%dSty", firstIndex + i);
+ WritePrivateProfileStringA(szAppname, "Style", _itoa(M->GetByte(szModule, szTemp, 0), szBuf, 10), szIniFilename);
+ sprintf(szTemp, "Font%dSize", firstIndex + i);
+ WritePrivateProfileStringA(szAppname, "Size", _itoa(M->GetByte(szModule, szTemp, 0), szBuf, 10), szIniFilename);
+ sprintf(szTemp, "Font%dSet", firstIndex + i);
+ WritePrivateProfileStringA(szAppname, "Set", _itoa(M->GetByte(szModule, szTemp, 0), szBuf, 10), szIniFilename);
+ }
+ n++;
+ }
+ def = SRMSGDEFSET_BKGCOLOUR;
+
+ for(i = 0; i < safe_sizeof(_extSettings); i++) {
+ WritePrivateProfileStringA(_extSettings[i].szIniSection, _extSettings[i].szIniName,
+ _itoa(M->GetDword(_extSettings[i].szDbModule, _extSettings[i].szDbSetting, _extSettings[i].dwDef), szBuf, 10), szIniFilename);
+ }
+
+ for(i = 0; i < safe_sizeof(_extSettings_v5); i++) {
+ WritePrivateProfileStringA(_extSettings_v5[i].szIniSection, _extSettings_v5[i].szIniName,
+ _itoa(M->GetDword(_extSettings_v5[i].szDbModule, _extSettings_v5[i].szDbSetting, _extSettings_v5[i].dwDef), szBuf, 10), szIniFilename);
+ }
+
+ WritePrivateProfileStringA("Message Log", "VGrid", _itoa(M->GetByte("wantvgrid", 0), szBuf, 10), szIniFilename);
+ WritePrivateProfileStringA("Message Log", "ExtraMicroLF", _itoa(M->GetByte("extramicrolf", 0), szBuf, 10), szIniFilename);
+
+ for (i = 0; i <= TMPL_ERRMSG; i++) {
+ char *encoded;
+ if (dat == 0)
+ encoded = M->utf8_encodeW(LTR_Active.szTemplates[i]);
+ else
+ encoded = M->utf8_encodeW(dat->pContainer->ltr_templates->szTemplates[i]);
+ WritePrivateProfileStringA("Templates", TemplateNames[i], encoded, szIniFilename);
+ mir_free(encoded);
+ if (dat == 0)
+ encoded = M->utf8_encodeW(RTL_Active.szTemplates[i]);
+ else
+ encoded = M->utf8_encodeW(dat->pContainer->rtl_templates->szTemplates[i]);
+ WritePrivateProfileStringA("RTLTemplates", TemplateNames[i], encoded, szIniFilename);
+ mir_free(encoded);
+ }
+ for (i = 0; i < CUSTOM_COLORS; i++) {
+ sprintf(szTemp, "cc%d", i + 1);
+ if (dat == 0)
+ WritePrivateProfileStringA("Custom Colors", szTemp, _itoa(M->GetDword(szTemp, 0), szBuf, 10), szIniFilename);
+ else
+ WritePrivateProfileStringA("Custom Colors", szTemp, _itoa(dat->pContainer->theme.custom_colors[i], szBuf, 10), szIniFilename);
+ }
+ for (i = 0; i <= 7; i++)
+ WritePrivateProfileStringA("Nick Colors", _itoa(i, szBuf, 10), _itoa(g_Settings.nickColors[i], szTemp, 10), szIniFilename);
+
+ mir_free(szIniFilename);
+}
+
+void TSAPI ReadThemeFromINI(const TCHAR *szIniFilenameT, TContainerData *dat, int noAdvanced, DWORD dwFlags)
+{
+ char szBuf[512], szTemp[100], szAppname[100];
+ int i, n = 0;
+ int version;
+ COLORREF def;
+ char *szIniFilename = mir_u2a(szIniFilenameT);
+ char szTemplateBuffer[TEMPLATE_LENGTH * 3 + 2];
+ char bSize = 0;
+ HDC hdc;
+ int charset;
+
+ if ((version = GetPrivateProfileIntA("TabSRMM Theme", "Version", 0, szIniFilename)) == 0) // no version number.. assume 1
+ version = 1;
+
+ if (dat == 0) {
+ hdc = GetDC(NULL);
+
+ while (fontBlocks[n].szModule && (dwFlags & THEME_READ_FONTS)) {
+ char *szModule = fontBlocks[n].szModule;
+ int firstIndex = fontBlocks[n].iFirst;
+
+ if (n != 1 && !(dwFlags & THEME_READ_FONTS)) {
+ n++;
+ continue;
+ }
+ if (GetPrivateProfileIntA(fontBlocks[n].szBLockname, "Valid", 0, szIniFilename) == 0 && n != 0) {
+ n++;
+ continue;
+ }
+ for (i = 0; i < fontBlocks[n].iCount; i++) {
+ sprintf(szTemp, "Font%d", firstIndex + i);
+ sprintf(szAppname, fontBlocks[n].szIniTemp, firstIndex + i);
+ if (GetPrivateProfileStringA(szAppname, "Face", "Verdana", szBuf, sizeof(szBuf), szIniFilename) != 0) {
+ if (i == MSGFONTID_SYMBOLS_IN || i == MSGFONTID_SYMBOLS_OUT)
+ lstrcpynA(szBuf, "Arial", sizeof(szBuf));
+ DBWriteContactSettingString(NULL, szModule, szTemp, szBuf);
+ }
+
+ sprintf(szTemp, "Font%dCol", firstIndex + i);
+ M->WriteDword(szModule, szTemp, GetPrivateProfileIntA(szAppname, "Color", GetSysColor(COLOR_WINDOWTEXT), szIniFilename));
+
+ sprintf(szTemp, "Font%dSty", firstIndex + i);
+ M->WriteByte(szModule, szTemp, (BYTE)(GetPrivateProfileIntA(szAppname, "Style", 0, szIniFilename)));
+
+ sprintf(szTemp, "Font%dSize", firstIndex + i);
+ bSize = (char)GetPrivateProfileIntA(szAppname, "Size", -10, szIniFilename);
+ if (bSize > 0)
+ bSize = -MulDiv(bSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ M->WriteByte(szModule, szTemp, bSize);
+
+ sprintf(szTemp, "Font%dSet", firstIndex + i);
+ charset = GetPrivateProfileIntA(szAppname, "Set", 0, szIniFilename);
+ if (i == MSGFONTID_SYMBOLS_IN || i == MSGFONTID_SYMBOLS_OUT)
+ charset = 0;
+ M->WriteByte(szModule, szTemp, (BYTE)charset);
+ }
+ n++;
+ }
+ def = SRMSGDEFSET_BKGCOLOUR;
+ ReleaseDC(NULL, hdc);
+
+ if (dwFlags & THEME_READ_FONTS) {
+ COLORREF defclr;
+
+ for(i = 0; i < safe_sizeof(_extSettings); i++) {
+ M->WriteDword(_extSettings[i].szDbModule, _extSettings[i].szDbSetting,
+ GetPrivateProfileIntA(_extSettings[i].szIniSection, _extSettings[i].szIniName, _extSettings[i].dwDef, szIniFilename));
+ }
+
+ if(version >= 5) {
+ for(i = 0; i < safe_sizeof(_extSettings_v5); i++) {
+ M->WriteDword(_extSettings_v5[i].szDbModule, _extSettings_v5[i].szDbSetting,
+ GetPrivateProfileIntA(_extSettings_v5[i].szIniSection, _extSettings_v5[i].szIniName, _extSettings_v5[i].dwDef, szIniFilename));
+ }
+ }
+
+ M->WriteByte(SRMSGMOD_T, "wantvgrid", (BYTE)(GetPrivateProfileIntA("Message Log", "VGrid", 0, szIniFilename)));
+ M->WriteByte(SRMSGMOD_T, "extramicrolf", (BYTE)(GetPrivateProfileIntA("Message Log", "ExtraMicroLF", 0, szIniFilename)));
+
+ for (i = 0; i < CUSTOM_COLORS; i++) {
+ sprintf(szTemp, "cc%d", i + 1);
+ if (dat == 0)
+ M->WriteDword(SRMSGMOD_T, szTemp, GetPrivateProfileIntA("Custom Colors", szTemp, RGB(224, 224, 224), szIniFilename));
+ else
+ dat->theme.custom_colors[i] = GetPrivateProfileIntA("Custom Colors", szTemp, RGB(224, 224, 224), szIniFilename);
+ }
+ for (i = 0; i <= 7; i++) {
+ if (i == 5)
+ defclr = GetSysColor(COLOR_HIGHLIGHT);
+ else if (i == 6)
+ defclr = GetSysColor(COLOR_HIGHLIGHTTEXT);
+ else
+ defclr = g_Settings.crUserListColor;
+ g_Settings.nickColors[i] = GetPrivateProfileIntA("Nick Colors", _itoa(i, szTemp, 10), defclr, szIniFilename);
+ sprintf(szTemp, "NickColor%d", i);
+ M->WriteDword("Chat", szTemp, g_Settings.nickColors[i]);
+ }
+ }
+ } else {
+ HDC hdc = GetDC(NULL);
+ int SY = GetDeviceCaps(hdc, LOGPIXELSY);
+ ReleaseDC(NULL, hdc);
+ if (!noAdvanced) {
+ for (i = 0; i < MSGDLGFONTCOUNT; i++) {
+ _snprintf(szTemp, 20, "Font%d", i);
+ LoadLogfontFromINI(i, szTemp, &dat->theme.logFonts[i], &dat->theme.fontColors[i], szIniFilename);
+ wsprintfA(dat->theme.rtfFonts + (i * RTFCACHELINESIZE), "\\f%u\\cf%u\\b%d\\i%d\\ul%d\\fs%u", i, i, dat->theme.logFonts[i].lfWeight >= FW_BOLD ? 1 : 0, dat->theme.logFonts[i].lfItalic, dat->theme.logFonts[i].lfUnderline, 2 * abs(dat->theme.logFonts[i].lfHeight) * 74 / SY);
+ }
+ wsprintfA(dat->theme.rtfFonts + (MSGDLGFONTCOUNT * RTFCACHELINESIZE), "\\f%u\\cf%u\\b%d\\i%d\\ul%d\\fs%u", MSGDLGFONTCOUNT, MSGDLGFONTCOUNT, 0, 0, 0, 0);
+ }
+ dat->theme.bg = GetPrivateProfileIntA("Message Log", "BackgroundColor", RGB(224, 224, 224), szIniFilename);
+ dat->theme.inbg = GetPrivateProfileIntA("Message Log", "IncomingBG", RGB(224, 224, 224), szIniFilename);
+ dat->theme.outbg = GetPrivateProfileIntA("Message Log", "OutgoingBG", RGB(224, 224, 224), szIniFilename);
+
+ dat->theme.oldinbg = GetPrivateProfileIntA("Message Log", "OldIncomingBG", RGB(224, 224, 224), szIniFilename);
+ dat->theme.oldoutbg = GetPrivateProfileIntA("Message Log", "OldOutgoingBG", RGB(224, 224, 224), szIniFilename);
+ dat->theme.statbg = GetPrivateProfileIntA("Message Log", "StatusBG", RGB(224, 224, 224), szIniFilename);
+
+ dat->theme.inputbg = GetPrivateProfileIntA("Message Log", "InputBG", RGB(224, 224, 224), szIniFilename);
+ dat->theme.hgrid = GetPrivateProfileIntA("Message Log", "HgridColor", RGB(224, 224, 224), szIniFilename);
+ dat->theme.dwFlags = GetPrivateProfileIntA("Message Log", "DWFlags", MWF_LOG_DEFAULT, szIniFilename);
+ M->WriteByte(SRMSGMOD_T, "wantvgrid", (BYTE)(GetPrivateProfileIntA("Message Log", "VGrid", 0, szIniFilename)));
+ M->WriteByte(SRMSGMOD_T, "extramicrolf", (BYTE)(GetPrivateProfileIntA("Message Log", "ExtraMicroLF", 0, szIniFilename)));
+
+ dat->theme.left_indent = GetPrivateProfileIntA("Message Log", "LeftIndent", 0, szIniFilename);
+ dat->theme.right_indent = GetPrivateProfileIntA("Message Log", "RightIndent", 0, szIniFilename);
+
+ for (i = 0; i < CUSTOM_COLORS; i++) {
+ sprintf(szTemp, "cc%d", i + 1);
+ if (dat == 0)
+ M->WriteDword(SRMSGMOD_T, szTemp, GetPrivateProfileIntA("Custom Colors", szTemp, RGB(224, 224, 224), szIniFilename));
+ else
+ dat->theme.custom_colors[i] = GetPrivateProfileIntA("Custom Colors", szTemp, RGB(224, 224, 224), szIniFilename);
+ }
+ }
+
+ if (version >= 3) {
+ if (!noAdvanced && dwFlags & THEME_READ_TEMPLATES) {
+ for (i = 0; i <= TMPL_ERRMSG; i++) {
+ wchar_t *decoded = 0;
+
+ GetPrivateProfileStringA("Templates", TemplateNames[i], "[undef]", szTemplateBuffer, TEMPLATE_LENGTH * 3, szIniFilename);
+
+ if (strcmp(szTemplateBuffer, "[undef]")) {
+ if (dat == 0)
+ DBWriteContactSettingStringUtf(NULL, TEMPLATES_MODULE, TemplateNames[i], szTemplateBuffer);
+ decoded = M->utf8_decodeW(szTemplateBuffer);
+ if (dat == 0)
+ mir_sntprintf(LTR_Active.szTemplates[i], TEMPLATE_LENGTH, L"%s", decoded);
+ else
+ mir_sntprintf(dat->ltr_templates->szTemplates[i], TEMPLATE_LENGTH, L"%s", decoded);
+ mir_free(decoded);
+ }
+
+ GetPrivateProfileStringA("RTLTemplates", TemplateNames[i], "[undef]", szTemplateBuffer, TEMPLATE_LENGTH * 3, szIniFilename);
+
+ if (strcmp(szTemplateBuffer, "[undef]")) {
+ if (dat == 0)
+ DBWriteContactSettingStringUtf(NULL, RTLTEMPLATES_MODULE, TemplateNames[i], szTemplateBuffer);
+ decoded = M->utf8_decodeW(szTemplateBuffer);
+ if (dat == 0)
+ mir_sntprintf(RTL_Active.szTemplates[i], TEMPLATE_LENGTH, L"%s", decoded);
+ else
+ mir_sntprintf(dat->rtl_templates->szTemplates[i], TEMPLATE_LENGTH, L"%s", decoded);
+ mir_free(decoded);
+ }
+ }
+ }
+ }
+ if (PluginConfig.m_chat_enabled)
+ LoadGlobalSettings();
+ mir_free(szIniFilename);
+}
+
+/*
+ * iMode = 0 - GetOpenFilename, otherwise, GetSaveAs...
+ */
+
+const TCHAR* TSAPI GetThemeFileName(int iMode)
+{
+ static TCHAR szFilename[MAX_PATH];
+ OPENFILENAME ofn = {0};
+ TCHAR szInitialDir[MAX_PATH];
+
+ mir_sntprintf(szInitialDir, MAX_PATH, _T("%s"), M->getSkinPath());
+
+ szFilename[0] = 0;
+
+ TCHAR filter[MAX_PATH];
+ mir_sntprintf(filter, SIZEOF(filter), _T("%s%c*.tabsrmm%c%c"), TranslateT("tabSRMM themes"), 0, 0, 0);
+ ofn.lpstrFilter = filter;
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = 0;
+ ofn.lpstrFile = szFilename;
+ ofn.lpstrInitialDir = szInitialDir;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.Flags = OFN_HIDEREADONLY | OFN_DONTADDTORECENT;
+ ofn.lpstrDefExt = _T("tabsrmm");
+ if (!iMode) {
+ if (GetOpenFileName(&ofn))
+ return szFilename;
+ else
+ return NULL;
+ } else {
+ if (GetSaveFileName(&ofn))
+ return szFilename;
+ else
+ return NULL;
+ }
+}
+
diff --git a/plugins/TabSRMM/src/themes.cpp b/plugins/TabSRMM/src/themes.cpp
new file mode 100644
index 0000000000..65c1ec8e2f
--- /dev/null
+++ b/plugins/TabSRMM/src/themes.cpp
@@ -0,0 +1,2871 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: themes.cpp 12512 2010-08-28 22:03:43Z silvercircle $
+ *
+ * Implements the skinning engine and most parts of the aero support in
+ * tabSRMM 3.x+
+ *
+ */
+
+#include "commonheaders.h"
+#include <stdexcept>
+#pragma hdrstop
+
+static SKINDESC my_default_skin[] = {
+ IDR_SKIN_AERO, _T("tabskin_aero.png"),
+ IDR_SKIN_AERO_GLOW, _T("tabskin_aero_glow.png"),
+ IDR_SKIN_AERO_SWITCHBAR, _T("tabskin_aero_button.png"),
+ IDR_SKIN_LOGO, _T("unknown.png")
+};
+
+CSkin* Skin = 0;
+
+
+static void __inline gradientVertical(UCHAR *ubRedFinal, UCHAR *ubGreenFinal, UCHAR *ubBlueFinal,
+ ULONG ulBitmapHeight, UCHAR ubRed, UCHAR ubGreen, UCHAR ubBlue, UCHAR ubRed2,
+ UCHAR ubGreen2, UCHAR ubBlue2, DWORD FLG_GRADIENT, BOOL transparent, UINT32 y, UCHAR *ubAlpha);
+
+static void __inline gradientHorizontal(UCHAR *ubRedFinal, UCHAR *ubGreenFinal, UCHAR *ubBlueFinal,
+ ULONG ulBitmapWidth, UCHAR ubRed, UCHAR ubGreen, UCHAR ubBlue, UCHAR ubRed2,
+ UCHAR ubGreen2, UCHAR ubBlue2, DWORD FLG_GRADIENT, BOOL transparent, UINT32 x, UCHAR *ubAlpha);
+
+
+UINT nextButtonID;
+ButtonSet g_ButtonSet = {0};
+
+#define NR_MAXSKINICONS 100
+
+/*
+ * initialize static class data
+*/
+
+int CSkin::m_bAvatarBorderType = 0;
+COLORREF CSkin::m_avatarBorderClr = 0;
+COLORREF CSkin::m_tmp_tb_low = 0, CSkin::m_tmp_tb_high = 0;
+COLORREF CSkin::m_sideBarContainerBG;
+BLENDFUNCTION CSkin::m_default_bf = {0}; // a global blend function, used in various places
+ // when you use it, reset SourceConstantAlpha to 255 and
+ // the blending mode to AC_SRC_ALPHA.
+
+bool CSkin::m_bClipBorder = false, CSkin::m_DisableScrollbars = false,
+ CSkin::m_skinEnabled = false, CSkin::m_frameSkins = false;
+
+char CSkin::m_SkinnedFrame_left = 0, CSkin::m_SkinnedFrame_right = 0,
+ CSkin::m_SkinnedFrame_bottom = 0, CSkin::m_SkinnedFrame_caption = 0;
+
+char CSkin::m_realSkinnedFrame_left = 0;
+char CSkin::m_realSkinnedFrame_right = 0;
+char CSkin::m_realSkinnedFrame_bottom = 0;
+char CSkin::m_realSkinnedFrame_caption = 0;
+
+int CSkin::m_titleBarLeftOff = 0, CSkin::m_titleButtonTopOff = 0, CSkin::m_captionOffset = 0, CSkin::m_captionPadding = 0,
+ CSkin::m_titleBarRightOff = 0, CSkin::m_sidebarTopOffset = 0, CSkin::m_sidebarBottomOffset = 0, CSkin::m_bRoundedCorner = 0;
+
+CImageItem* CSkin::m_switchBarItem = 0,
+ *CSkin::m_tabTop = 0,
+ *CSkin::m_tabBottom = 0,
+ *CSkin::m_tabGlowTop = 0,
+ *CSkin::m_tabGlowBottom = 0;
+
+bool CSkin::m_fAeroSkinsValid = false;
+
+SIZE CSkin::m_titleBarButtonSize = {0};
+
+COLORREF CSkin::m_ContainerColorKey = 0, CSkin::m_dwmColorRGB = 0, CSkin::m_DefaultFontColor = 0;
+HBRUSH CSkin::m_ContainerColorKeyBrush = 0, CSkin::m_MenuBGBrush = 0;
+
+HPEN CSkin::m_SkinLightShadowPen = 0, CSkin::m_SkinDarkShadowPen = 0;
+
+HICON CSkin::m_closeIcon = 0, CSkin::m_maxIcon = 0, CSkin::m_minIcon = 0;
+
+UINT CSkin::m_aeroEffect = 0;
+DWORD CSkin::m_glowSize = 0;
+HBRUSH CSkin::m_BrushBack = 0, CSkin::m_BrushFill = 0;
+
+HBITMAP CSkin::m_tabCloseBitmap = 0, CSkin::m_tabCloseOldBitmap = 0;
+HDC CSkin::m_tabCloseHDC = 0;
+
+/*
+ * aero effects
+ */
+
+AeroEffect CSkin::m_currentAeroEffect;
+AeroEffect* CSkin::m_pCurrentAeroEffect = 0;
+
+AeroEffect CSkin::m_aeroEffects[AERO_EFFECT_LAST] = {
+ {
+ _T("No effect"), 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0
+ },
+ {
+ _T("Milky Glass"),
+ 0xf5f5f5, /* base color */
+ 0xaaaaaa, /* gradient color */
+ 70, /* base alpha */
+ 0, /* final alpha */
+ CORNER_ALL, /* corner type */
+ GRADIENT_TB + 1, /* gradient type */
+ 8, /* corner radius */
+ 8, /* glow size (0 means no glowing text, colors can be used) */
+ 0, /* background color (black = transparency) */
+ 0xf0f0f0, /* toolbar first color (if 0, use custom gradient color) */
+ 0, /* toolbar 2nd gradient color (0 = use aero theme color, -1 = use custom gradient color */
+ AeroEffectCallback_Milk /* callback function to render the effect */
+ },
+ {
+ _T("Carbon"),
+ 0xf0f0f0,
+ 0x000000,
+ 75,
+ 0,
+ CORNER_ALL,
+ GRADIENT_TB + 1,
+ 6,
+ 8,
+ 0,
+ 0xf0f0f0,
+ 0,
+ AeroEffectCallback_Carbon
+ },
+ {
+ _T("Semi transparent, custom colors"),
+ 0xffffff,
+ 0x444444,
+ 60,
+ 0,
+ CORNER_ALL,
+ GRADIENT_TB + 1,
+ 6,
+ 0,
+ 0x0,
+ 0xf0f0f0,
+ 0,
+ AeroEffectCallback_Solid
+ },
+ {
+ _T("Silver shadow"),
+ 0xffffff,
+ 0xa0a0a0,
+ 80,
+ 220,
+ 0,
+ GRADIENT_TB + 1,
+ 1,
+ 0,
+ 0xc0c0c0,
+ 0xf0f0f0,
+ 0x707070,
+ AeroEffectCallback_Solid
+ },
+ {
+ _T("Custom (use own gradient colors)"),
+ 0xffffff,
+ 0xa0a0a0,
+ 80,
+ 220,
+ 0,
+ GRADIENT_TB + 1,
+ 1,
+ 0,
+ 0xc0c0c0,
+ -1,
+ -1,
+ AeroEffectCallback_Solid
+ }
+};
+
+/*
+ * definition of the availbale skin items
+ */
+
+CSkinItem SkinItems[] = {
+ {_T("Container"), "TSKIN_Container", ID_EXTBKCONTAINER,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Toolbar"), "TSKIN_Container", ID_EXTBKBUTTONBAR,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("{-}Buttonpressed"), "TSKIN_BUTTONSPRESSED", ID_EXTBKBUTTONSPRESSED,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Buttonnotpressed"), "TSKIN_BUTTONSNPRESSED", ID_EXTBKBUTTONSNPRESSED,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Buttonmouseover"), "TSKIN_BUTTONSMOUSEOVER", ID_EXTBKBUTTONSMOUSEOVER,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Infopanelfield"), "TSKIN_INFOPANELFIELD", ID_EXTBKINFOPANEL,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Titlebutton"), "TSKIN_TITLEBUTTON", ID_EXTBKTITLEBUTTON,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Titlebuttonmouseover"), "TSKIN_TITLEBUTTONHOVER", ID_EXTBKTITLEBUTTONMOUSEOVER,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Titlebuttonpressed"), "TSKIN_TITLEBUTTONPRESSED", ID_EXTBKTITLEBUTTONPRESSED,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Tabpage"), "TSKIN_TABPAGE", ID_EXTBKTABPAGE,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Tabitem"), "TSKIN_TABITEM", ID_EXTBKTABITEM,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Tabitem_active"), "TSKIN_TABITEMACTIVE", ID_EXTBKTABITEMACTIVE,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Tabitem_bottom"), "TSKIN_TABITEMBOTTOM", ID_EXTBKTABITEMBOTTOM,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Tabitem_active_bottom"), "TSKIN_TABITEMACTIVEBOTTOM", ID_EXTBKTABITEMACTIVEBOTTOM,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Frame"), "TSKIN_FRAME", ID_EXTBKFRAME,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("MessageLog"), "TSKIN_MLOG", ID_EXTBKHISTORY,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("InputArea"), "TSKIN_INPUT", ID_EXTBKINPUTAREA,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("FrameInactive"), "TSKIN_FRAMEINACTIVE", ID_EXTBKFRAMEINACTIVE,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Tabitem_hottrack"), "TSKIN_TABITEMHOTTRACK", ID_EXTBKTABITEMHOTTRACK,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Tabitem_hottrack_bottom"), "TSKIN_TABITEMHOTTRACKBOTTOM", ID_EXTBKTABITEMHOTTRACKBOTTOM,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Statusbarpanel"), "TSKIN_STATUSBARPANEL", ID_EXTBKSTATUSBARPANEL,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Statusbar"), "TSKIN_STATUSBAR", ID_EXTBKSTATUSBAR,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("Userlist"), "TSKIN_USERLIST", ID_EXTBKUSERLIST,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {_T("InfoPanelBackground"), "TSKIN_INFOPANELBG", ID_EXTBKINFOPANELBG,
+ 8, CLCDEFAULT_CORNER,
+ 0xf0f0f0, 0x42b1ff, 1, CLCDEFAULT_TEXTCOLOR, 40, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE, 0, 0
+ }, {_T("Sidebar Background"), "TSKIN_SIDEBARBG", ID_EXTBKSIDEBARBG,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ 0xb2e1ff, 0xb2e1ff, 1, CLCDEFAULT_TEXTCOLOR, 40, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE, 0, 0
+ }
+};
+
+static CSkinItem _defInfoPanel = {
+ _T("InfoPanelBackground"), "TSKIN_INFOPANELBG", ID_EXTBKINFOPANELBG,
+ 8, CLCDEFAULT_CORNER,
+ 0xf0f0f0, 0x62caff, 0, CLCDEFAULT_TEXTCOLOR, 255, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE, 0, 0
+};
+
+static BYTE __inline percent_to_byte(UINT32 percent)
+{
+ return(BYTE)((FLOAT)(((FLOAT) percent) / 100) * 255);
+}
+
+static COLORREF __inline revcolref(COLORREF colref)
+{
+ return RGB(GetBValue(colref), GetGValue(colref), GetRValue(colref));
+}
+
+static DWORD __inline argb_from_cola(COLORREF col, UINT32 alpha)
+{
+ return((BYTE) percent_to_byte(alpha) << 24 | col);
+}
+
+
+void TSAPI DrawAlpha(HDC hDC, PRECT rc, DWORD clr_base, int alpha, DWORD clr_dest, BYTE clr_dest_trans, BYTE bGradient,
+ BYTE bCorner, DWORD dwRadius, CImageItem *imageItem)
+{
+ HBRUSH BrMask;
+ HBRUSH holdbrush;
+ HDC hdc;
+ BLENDFUNCTION bf;
+ HBITMAP hbitmap;
+ HBITMAP holdbitmap;
+ BITMAPINFO bmi;
+ VOID *pvBits;
+ UINT32 x, y;
+ ULONG ulBitmapWidth, ulBitmapHeight;
+ UCHAR ubAlpha = 0xFF;
+ UCHAR ubRedFinal = 0xFF;
+ UCHAR ubGreenFinal = 0xFF;
+ UCHAR ubBlueFinal = 0xFF;
+ UCHAR ubRed;
+ UCHAR ubGreen;
+ UCHAR ubBlue;
+ UCHAR ubRed2;
+ UCHAR ubGreen2;
+ UCHAR ubBlue2;
+
+ int realx;
+
+ FLOAT fAlphaFactor;
+ LONG realHeight = (rc->bottom - rc->top);
+ LONG realWidth = (rc->right - rc->left);
+ LONG realHeightHalf = realHeight >> 1;
+
+ if (rc == NULL || CMimAPI::m_MyGradientFill == 0 || CMimAPI::m_MyAlphaBlend == 0)
+ return;
+
+ if (imageItem) {
+ imageItem->Render(hDC, rc, false);
+ return;
+ }
+
+ if (rc->right < rc->left || rc->bottom < rc->top || (realHeight <= 0) || (realWidth <= 0))
+ return;
+
+ /*
+ * use GDI fast gradient drawing when no corner radi exist
+ */
+
+ if (bCorner == 0 && dwRadius == 0) {
+ GRADIENT_RECT grect;
+ TRIVERTEX tvtx[2];
+ int orig = 1, dest = 0;
+
+ if (bGradient & GRADIENT_LR || bGradient & GRADIENT_TB) {
+ orig = 0;
+ dest = 1;
+ }
+
+ tvtx[0].x = rc->left;
+ tvtx[0].y = rc->top;
+ tvtx[1].x = rc->right;
+ tvtx[1].y = rc->bottom;
+
+ tvtx[orig].Red = (COLOR16)GetRValue(clr_base) << 8;
+ tvtx[orig].Blue = (COLOR16)GetBValue(clr_base) << 8;
+ tvtx[orig].Green = (COLOR16)GetGValue(clr_base) << 8;
+ tvtx[orig].Alpha = (COLOR16) alpha << 8;
+
+ tvtx[dest].Red = (COLOR16)GetRValue(clr_dest) << 8;
+ tvtx[dest].Blue = (COLOR16)GetBValue(clr_dest) << 8;
+ tvtx[dest].Green = (COLOR16)GetGValue(clr_dest) << 8;
+ tvtx[dest].Alpha = (COLOR16) alpha << 8;
+
+ grect.UpperLeft = 0;
+ grect.LowerRight = 1;
+
+ CMimAPI::m_MyGradientFill(hDC, tvtx, 2, &grect, 1, (bGradient & GRADIENT_TB || bGradient & GRADIENT_BT) ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H);
+ return;
+ }
+
+ hdc = CreateCompatibleDC(hDC);
+ if (!hdc)
+ return;
+
+ ZeroMemory(&bmi, sizeof(BITMAPINFO));
+
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+
+ if (bGradient & GRADIENT_ACTIVE && (bGradient & GRADIENT_LR || bGradient & GRADIENT_RL)) {
+ bmi.bmiHeader.biWidth = ulBitmapWidth = realWidth;
+ bmi.bmiHeader.biHeight = ulBitmapHeight = 1;
+ } else if (bGradient & GRADIENT_ACTIVE && (bGradient & GRADIENT_TB || bGradient & GRADIENT_BT)) {
+ bmi.bmiHeader.biWidth = ulBitmapWidth = 1;
+ bmi.bmiHeader.biHeight = ulBitmapHeight = realHeight;
+ } else {
+ bmi.bmiHeader.biWidth = ulBitmapWidth = 1;
+ bmi.bmiHeader.biHeight = ulBitmapHeight = 1;
+ }
+
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = ulBitmapWidth * ulBitmapHeight * 4;
+
+ if (ulBitmapWidth <= 0 || ulBitmapHeight <= 0)
+ return;
+
+ hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0);
+ if (hbitmap == NULL || pvBits == NULL) {
+ DeleteDC(hdc);
+ return;
+ }
+
+ holdbitmap = (HBITMAP)SelectObject(hdc, hbitmap);
+
+ // convert basecolor to RGB and then merge alpha so its ARGB
+ clr_base = argb_from_cola(revcolref(clr_base), alpha);
+ clr_dest = argb_from_cola(revcolref(clr_dest), alpha);
+
+ ubRed = (UCHAR)(clr_base >> 16);
+ ubGreen = (UCHAR)(clr_base >> 8);
+ ubBlue = (UCHAR) clr_base;
+
+ ubRed2 = (UCHAR)(clr_dest >> 16);
+ ubGreen2 = (UCHAR)(clr_dest >> 8);
+ ubBlue2 = (UCHAR) clr_dest;
+
+ //DRAW BASE - make corner space 100% transparent
+ for (y = 0; y < ulBitmapHeight; y++) {
+ for (x = 0 ; x < ulBitmapWidth ; x++) {
+ if (bGradient & GRADIENT_ACTIVE) {
+ if (bGradient & GRADIENT_LR || bGradient & GRADIENT_RL) {
+ realx = x + realHeightHalf;
+ realx = (ULONG) realx > ulBitmapWidth ? ulBitmapWidth : realx;
+ gradientHorizontal(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapWidth, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, realx, &ubAlpha);
+ } else if (bGradient & GRADIENT_TB || bGradient & GRADIENT_BT)
+ gradientVertical(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapHeight, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, y, &ubAlpha);
+
+ fAlphaFactor = (float) ubAlpha / (float) 0xff;
+ ((UINT32 *) pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor));
+ } else {
+ ubAlpha = percent_to_byte(alpha);
+ ubRedFinal = ubRed;
+ ubGreenFinal = ubGreen;
+ ubBlueFinal = ubBlue;
+ fAlphaFactor = (float) ubAlpha / (float) 0xff;
+
+ ((UINT32 *) pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor));
+ }
+ }
+ }
+ bf.BlendOp = AC_SRC_OVER;
+ bf.BlendFlags = 0;
+ bf.SourceConstantAlpha = (UCHAR)(clr_base >> 24);
+ bf.AlphaFormat = AC_SRC_ALPHA; // so it will use our specified alpha value
+
+ CMimAPI::m_MyAlphaBlend(hDC, rc->left + realHeightHalf, rc->top, (realWidth - realHeightHalf * 2), realHeight, hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf);
+
+ SelectObject(hdc, holdbitmap);
+ DeleteObject(hbitmap);
+
+ // corners
+ BrMask = CreateSolidBrush(RGB(0xFF, 0x00, 0xFF));
+ {
+ bmi.bmiHeader.biWidth = ulBitmapWidth = realHeightHalf;
+ bmi.bmiHeader.biHeight = ulBitmapHeight = realHeight;
+ bmi.bmiHeader.biSizeImage = ulBitmapWidth * ulBitmapHeight * 4;
+
+ if (ulBitmapWidth <= 0 || ulBitmapHeight <= 0) {
+ DeleteDC(hdc);
+ DeleteObject(BrMask);
+ return;
+ }
+
+ // TL+BL CORNER
+ hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0);
+
+ if (hbitmap == 0 || pvBits == NULL) {
+ DeleteObject(BrMask);
+ DeleteDC(hdc);
+ return;
+ }
+
+ holdbrush = (HBRUSH)SelectObject(hdc, BrMask);
+ holdbitmap = (HBITMAP)SelectObject(hdc, hbitmap);
+ RoundRect(hdc, -1, -1, ulBitmapWidth * 2 + 1, (realHeight + 1), dwRadius, dwRadius);
+
+ for (y = 0; y < ulBitmapHeight; y++) {
+ for (x = 0; x < ulBitmapWidth; x++) {
+ if (((((UINT32 *) pvBits)[x + y * ulBitmapWidth]) << 8) == 0xFF00FF00 || (y < ulBitmapHeight >> 1 && !(bCorner & CORNER_BL && bCorner & CORNER_ACTIVE)) || (y > ulBitmapHeight >> 2 && !(bCorner & CORNER_TL && bCorner & CORNER_ACTIVE))) {
+ if (bGradient & GRADIENT_ACTIVE) {
+ if (bGradient & GRADIENT_LR || bGradient & GRADIENT_RL)
+ gradientHorizontal(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, realWidth, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, x, &ubAlpha);
+ else if (bGradient & GRADIENT_TB || bGradient & GRADIENT_BT)
+ gradientVertical(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapHeight, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, y, &ubAlpha);
+
+ fAlphaFactor = (float) ubAlpha / (float) 0xff;
+ ((UINT32 *) pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor));
+ } else {
+ ubAlpha = percent_to_byte(alpha);
+ ubRedFinal = ubRed;
+ ubGreenFinal = ubGreen;
+ ubBlueFinal = ubBlue;
+ fAlphaFactor = (float) ubAlpha / (float) 0xff;
+
+ ((UINT32 *) pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor));
+ }
+ }
+ }
+ }
+ CMimAPI::m_MyAlphaBlend(hDC, rc->left, rc->top, ulBitmapWidth, ulBitmapHeight, hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf);
+ SelectObject(hdc, holdbitmap);
+ DeleteObject(hbitmap);
+
+ // TR+BR CORNER
+ hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0);
+
+ //SelectObject(hdc, BrMask); // already BrMask?
+ holdbitmap = (HBITMAP)SelectObject(hdc, hbitmap);
+ RoundRect(hdc, -1 - ulBitmapWidth, -1, ulBitmapWidth + 1, (realHeight + 1), dwRadius, dwRadius);
+
+ for (y = 0; y < ulBitmapHeight; y++) {
+ for (x = 0; x < ulBitmapWidth; x++) {
+ if (((((UINT32 *) pvBits)[x + y * ulBitmapWidth]) << 8) == 0xFF00FF00 || (y < ulBitmapHeight >> 1 && !(bCorner & CORNER_BR && bCorner & CORNER_ACTIVE)) || (y > ulBitmapHeight >> 1 && !(bCorner & CORNER_TR && bCorner & CORNER_ACTIVE))) {
+ if (bGradient & GRADIENT_ACTIVE) {
+ if (bGradient & GRADIENT_LR || bGradient & GRADIENT_RL) {
+ realx = x + realWidth;
+ realx = realx > realWidth ? realWidth : realx;
+ gradientHorizontal(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, realWidth, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, realx, &ubAlpha);
+ } else if (bGradient & GRADIENT_TB || bGradient & GRADIENT_BT)
+ gradientVertical(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapHeight, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, y, &ubAlpha);
+
+ fAlphaFactor = (float) ubAlpha / (float) 0xff;
+ ((UINT32 *) pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor));
+ } else {
+ ubAlpha = percent_to_byte(alpha);
+ ubRedFinal = ubRed;
+ ubGreenFinal = ubGreen;
+ ubBlueFinal = ubBlue;
+ fAlphaFactor = (float) ubAlpha / (float) 0xff;
+
+ ((UINT32 *) pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor));
+ }
+ }
+ }
+ }
+ CMimAPI::m_MyAlphaBlend(hDC, rc->right - realHeightHalf, rc->top, ulBitmapWidth, ulBitmapHeight, hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf);
+ }
+ SelectObject(hdc, holdbitmap);
+ DeleteObject(hbitmap);
+ SelectObject(hdc, holdbrush);
+ DeleteObject(BrMask);
+ DeleteDC(hdc);
+}
+
+void __inline gradientHorizontal(UCHAR *ubRedFinal, UCHAR *ubGreenFinal, UCHAR *ubBlueFinal, ULONG ulBitmapWidth, UCHAR ubRed, UCHAR ubGreen, UCHAR ubBlue, UCHAR ubRed2, UCHAR ubGreen2, UCHAR ubBlue2, DWORD FLG_GRADIENT, BOOL transparent, UINT32 x, UCHAR *ubAlpha)
+{
+ FLOAT fSolidMulti, fInvSolidMulti;
+
+ // solid to transparent
+ if (transparent) {
+ *ubAlpha = (UCHAR)((float) x / (float) ulBitmapWidth * 255);
+ *ubAlpha = FLG_GRADIENT & GRADIENT_LR ? 0xFF - (*ubAlpha) : (*ubAlpha);
+ *ubRedFinal = ubRed;
+ *ubGreenFinal = ubGreen;
+ *ubBlueFinal = ubBlue;
+ } else { // solid to solid2
+ if (FLG_GRADIENT & GRADIENT_LR) {
+ fSolidMulti = ((float) x / (float) ulBitmapWidth);
+ fInvSolidMulti = 1 - fSolidMulti;
+ } else {
+ fInvSolidMulti = ((float) x / (float) ulBitmapWidth);
+ fSolidMulti = 1 - fInvSolidMulti;
+ }
+
+ *ubRedFinal = (UCHAR)((((float) ubRed * (float) fInvSolidMulti)) + (((float) ubRed2 * (float) fSolidMulti)));
+ *ubGreenFinal = (UCHAR)((UCHAR)(((float) ubGreen * (float) fInvSolidMulti)) + (((float) ubGreen2 * (float) fSolidMulti)));
+ *ubBlueFinal = (UCHAR)((((float) ubBlue * (float) fInvSolidMulti)) + (UCHAR)(((float) ubBlue2 * (float) fSolidMulti)));
+
+ *ubAlpha = 0xFF;
+ }
+}
+
+void __inline gradientVertical(UCHAR *ubRedFinal, UCHAR *ubGreenFinal, UCHAR *ubBlueFinal, ULONG ulBitmapHeight, UCHAR ubRed, UCHAR ubGreen, UCHAR ubBlue, UCHAR ubRed2, UCHAR ubGreen2, UCHAR ubBlue2, DWORD FLG_GRADIENT, BOOL transparent, UINT32 y, UCHAR *ubAlpha)
+{
+ FLOAT fSolidMulti, fInvSolidMulti;
+
+ // solid to transparent
+ if (transparent) {
+ *ubAlpha = (UCHAR)((float) y / (float) ulBitmapHeight * 255);
+ *ubAlpha = FLG_GRADIENT & GRADIENT_BT ? 0xFF - *ubAlpha : *ubAlpha;
+ *ubRedFinal = ubRed;
+ *ubGreenFinal = ubGreen;
+ *ubBlueFinal = ubBlue;
+ } else { // solid to solid2
+ if (FLG_GRADIENT & GRADIENT_BT) {
+ fSolidMulti = ((float) y / (float) ulBitmapHeight);
+ fInvSolidMulti = 1 - fSolidMulti;
+ } else {
+ fInvSolidMulti = ((float) y / (float) ulBitmapHeight);
+ fSolidMulti = 1 - fInvSolidMulti;
+ }
+
+ *ubRedFinal = (UCHAR)((((float) ubRed * (float) fInvSolidMulti)) + (((float) ubRed2 * (float) fSolidMulti)));
+ *ubGreenFinal = (UCHAR)((((float) ubGreen * (float) fInvSolidMulti)) + (((float) ubGreen2 * (float) fSolidMulti)));
+ *ubBlueFinal = (UCHAR)(((float) ubBlue * (float) fInvSolidMulti)) + (UCHAR)(((float) ubBlue2 * (float) fSolidMulti));
+
+ *ubAlpha = 0xFF;
+ }
+}
+
+/**
+ * Renders the image item to the given target device context and rectangle
+ *
+ * @param hdc HDC: target device context
+ * @param rc RECT *: client rectangle inside the target DC.
+ * @param fIgnoreGlyph: bool: will ignore any glyph item. Set it to true when
+ * using this function from _outside_ a skin
+ */
+void __fastcall CImageItem::Render(const HDC hdc, const RECT *rc, bool fIgnoreGlyph) const
+{
+ BYTE l = m_bLeft, r = m_bRight, t = m_bTop, b = m_bBottom;
+ LONG width = rc->right - rc->left;
+ LONG height = rc->bottom - rc->top;
+ BOOL isGlyph = ((m_dwFlags & IMAGE_GLYPH) && Skin->haveGlyphItem());
+ BOOL fCleanUp = TRUE;
+ HDC hdcSrc = 0;
+ HBITMAP hbmOld;
+ LONG srcOrigX = isGlyph ? m_glyphMetrics[0] : 0;
+ LONG srcOrigY = isGlyph ? m_glyphMetrics[1] : 0;
+
+ if (CMimAPI::m_MyAlphaBlend == 0)
+ return;
+
+ if (m_hdc == 0) {
+ hdcSrc = CreateCompatibleDC(hdc);
+ hbmOld = (HBITMAP)SelectObject(hdcSrc, isGlyph ? Skin->getGlyphItem()->getHbm() : m_hbm);
+ } else {
+ if(fIgnoreGlyph)
+ hdcSrc = m_hdc;
+ else
+ hdcSrc = isGlyph ? Skin->getGlyphItem()->getDC() : m_hdc;
+ fCleanUp = FALSE;
+ }
+
+ if (m_dwFlags & IMAGE_FLAG_DIVIDED) {
+ // top 3 items
+
+ CMimAPI::m_MyAlphaBlend(hdc, rc->left, rc->top, l, t, hdcSrc, srcOrigX, srcOrigY, l, t, m_bf);
+ CMimAPI::m_MyAlphaBlend(hdc, rc->left + l, rc->top, width - l - r, t, hdcSrc, srcOrigX + l, srcOrigY, m_inner_width, t, m_bf);
+ CMimAPI::m_MyAlphaBlend(hdc, rc->right - r, rc->top, r, t, hdcSrc, srcOrigX + (m_width - r), srcOrigY, r, t, m_bf);
+
+ // middle 3 items
+
+ CMimAPI::m_MyAlphaBlend(hdc, rc->left, rc->top + t, l, height - t - b, hdcSrc, srcOrigX, srcOrigY + t, l, m_inner_height, m_bf);
+
+ if ((m_dwFlags & IMAGE_FILLSOLID) && m_fillBrush) {
+ RECT rcFill;
+ rcFill.left = rc->left + l;
+ rcFill.top = rc->top + t;
+ rcFill.right = rc->right - r;
+ rcFill.bottom = rc->bottom - b;
+ FillRect(hdc, &rcFill, m_fillBrush);
+ } else
+ CMimAPI::m_MyAlphaBlend(hdc, rc->left + l, rc->top + t, width - l - r, height - t - b, hdcSrc, srcOrigX + l, srcOrigY + t, m_inner_width, m_inner_height, m_bf);
+
+ CMimAPI::m_MyAlphaBlend(hdc, rc->right - r, rc->top + t, r, height - t - b, hdcSrc, srcOrigX + (m_width - r), srcOrigY + t, r, m_inner_height, m_bf);
+
+ // bottom 3 items
+
+ CMimAPI::m_MyAlphaBlend(hdc, rc->left, rc->bottom - b, l, b, hdcSrc, srcOrigX, srcOrigY + (m_height - b), l, b, m_bf);
+ CMimAPI::m_MyAlphaBlend(hdc, rc->left + l, rc->bottom - b, width - l - r, b, hdcSrc, srcOrigX + l, srcOrigY + (m_height - b), m_inner_width, b, m_bf);
+ CMimAPI::m_MyAlphaBlend(hdc, rc->right - r, rc->bottom - b, r, b, hdcSrc, srcOrigX + (m_width - r), srcOrigY + (m_height - b), r, b, m_bf);
+ } else {
+ switch (m_bStretch) {
+ case IMAGE_STRETCH_H:
+ // tile image vertically, stretch to width
+ {
+ LONG top = rc->top;
+
+ do {
+ if (top + m_height <= rc->bottom) {
+ CMimAPI::m_MyAlphaBlend(hdc, rc->left, top, width, m_height, hdcSrc, srcOrigX, srcOrigY, m_width, m_height, m_bf);
+ top += m_height;
+ } else {
+ CMimAPI::m_MyAlphaBlend(hdc, rc->left, top, width, rc->bottom - top, hdcSrc, srcOrigX, srcOrigY, m_width, rc->bottom - top, m_bf);
+ break;
+ }
+ } while (TRUE);
+ break;
+ }
+ case IMAGE_STRETCH_V:
+ // tile horizontally, stretch to height
+ {
+ LONG left = rc->left;
+
+ do {
+ if (left + m_width <= rc->right) {
+ CMimAPI::m_MyAlphaBlend(hdc, left, rc->top, m_width, height, hdcSrc, srcOrigX, srcOrigY, m_width, m_height, m_bf);
+ left += m_width;
+ } else {
+ CMimAPI::m_MyAlphaBlend(hdc, left, rc->top, rc->right - left, height, hdcSrc, srcOrigX, srcOrigY, rc->right - left, m_height, m_bf);
+ break;
+ }
+ } while (TRUE);
+ break;
+ }
+ case IMAGE_STRETCH_B:
+ // stretch the image in both directions...
+ CMimAPI::m_MyAlphaBlend(hdc, rc->left, rc->top, width, height, hdcSrc, srcOrigX, srcOrigY, m_width, m_height, m_bf);
+ break;
+ /*
+ case IMAGE_STRETCH_V:
+ // stretch vertically, draw 3 horizontal tiles...
+ AlphaBlend(hdc, rc->left, rc->top, l, height, item->hdc, 0, 0, l, item->height, item->bf);
+ AlphaBlend(hdc, rc->left + l, rc->top, width - l - r, height, item->hdc, l, 0, item->inner_width, item->height, item->bf);
+ AlphaBlend(hdc, rc->right - r, rc->top, r, height, item->hdc, item->width - r, 0, r, item->height, item->bf);
+ break;
+ case IMAGE_STRETCH_H:
+ // stretch horizontally, draw 3 vertical tiles...
+ AlphaBlend(hdc, rc->left, rc->top, width, t, item->hdc, 0, 0, item->width, t, item->bf);
+ AlphaBlend(hdc, rc->left, rc->top + t, width, height - t - b, item->hdc, 0, t, item->width, item->inner_height, item->bf);
+ AlphaBlend(hdc, rc->left, rc->bottom - b, width, b, item->hdc, 0, item->height - b, item->width, b, item->bf);
+ break;
+ */
+ default:
+ break;
+ }
+ }
+ if (fCleanUp) {
+ SelectObject(hdcSrc, hbmOld);
+ DeleteDC(hdcSrc);
+ }
+}
+
+static CSkinItem StatusItem_Default = {
+ _T("Container"), "EXBK_Offline", ID_EXTBKCONTAINER,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+};
+
+static struct {
+ TCHAR *szIniKey, *szIniName;
+ char *szSetting;
+ unsigned int size;
+ int defaultval;
+} _tagSettings[] = {
+ _T("Global"), _T("SbarHeight"), "S_sbarheight", 1, 22,
+ _T("ClientArea"), _T("Left"), "S_tborder_outer_left", 1, 0,
+ _T("ClientArea"), _T("Right"), "S_tborder_outer_right", 1, 0,
+ _T("ClientArea"), _T("Top"), "S_tborder_outer_top", 1, 0,
+ _T("ClientArea"), _T("Bottom"), "S_tborder_outer_bottom", 1, 0,
+ _T("ClientArea"), _T("Inner"), "S_tborder", 1, 0,
+ _T("Global"), _T("TabTextNormal"), "S_tab_txt_normal", 5, 0,
+ _T("Global"), _T("TabTextActive"), "S_tab_txt_active", 5, 0,
+ _T("Global"), _T("TabTextUnread"), "S_tab_txt_unread", 5, 0,
+ _T("Global"), _T("TabTextHottrack"), "S_tab_txt_hottrack", 5, 0,
+ NULL, NULL, NULL, 0, 0
+};
+
+void CImageItem::Create(const TCHAR *szImageFile)
+{
+ HBITMAP hbm = LoadPNG(szImageFile);
+ BITMAP bm;
+
+ m_hdc = 0;
+ m_hbmOld = 0;
+ m_hbm = 0;
+
+ if (hbm) {
+ m_hbm = hbm;
+ m_bf.BlendFlags = 0;
+ m_bf.BlendOp = AC_SRC_OVER;
+ m_bf.AlphaFormat = 0;
+
+ GetObject(hbm, sizeof(bm), &bm);
+ if (bm.bmBitsPixel == 32 && m_dwFlags & IMAGE_PERPIXEL_ALPHA) {
+ CImageItem::PreMultiply(m_hbm, 1);
+ m_bf.AlphaFormat = AC_SRC_ALPHA;
+ }
+ m_width = bm.bmWidth;
+ m_height = bm.bmHeight;
+ m_inner_height = m_height - m_bTop - m_bBottom;
+ m_inner_width = m_width - m_bLeft - m_bRight;
+ if (m_bTop && m_bBottom && m_bLeft && m_bRight) {
+ m_dwFlags |= IMAGE_FLAG_DIVIDED;
+ if (m_inner_height <= 0 || m_inner_width <= 0) {
+ DeleteObject(hbm);
+ m_hbm = 0;
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * Reads the definitions for an image item from the given .tsk file
+ * It does _not_ create the image itself, a call to CImageItem::Create() must be done
+ * to read the image in memory and prepare
+ *
+ * @param szFilename char*: full path and filename to the .TSK file
+ *
+ * @return char*: full path and filename to the .png image which represents this image item.
+ * caller MUST delete it.
+ */
+TCHAR* CImageItem::Read(const TCHAR *szFilename)
+{
+ TCHAR buffer[501];
+ TCHAR szDrive[MAX_PATH], szPath[MAX_PATH];
+ TCHAR *szFinalName = 0;
+
+ GetPrivateProfileString(m_szName, _T("Glyph"), _T("None"), buffer, 500, szFilename);
+ if (_tcscmp(buffer, _T("None"))) {
+ _stscanf(buffer, _T("%d,%d,%d,%d"), &m_glyphMetrics[0], &m_glyphMetrics[1],
+ &m_glyphMetrics[2], &m_glyphMetrics[3]);
+ if (m_glyphMetrics[2] > m_glyphMetrics[0] && m_glyphMetrics[3] > m_glyphMetrics[1]) {
+ m_dwFlags |= IMAGE_GLYPH;
+ m_glyphMetrics[2] = (m_glyphMetrics[2] - m_glyphMetrics[0]) + 1;
+ m_glyphMetrics[3] = (m_glyphMetrics[3] - m_glyphMetrics[1]) + 1;
+ }
+ }
+ GetPrivateProfileString(m_szName, _T("Image"), _T("None"), buffer, 500, szFilename);
+ if (_tcscmp(buffer, _T("None")) || m_dwFlags & IMAGE_GLYPH) {
+ szFinalName = new TCHAR[MAX_PATH];
+ //strncpy(m_szName, &m_szName[1], sizeof(m_szName));
+ //m_szName[sizeof(m_szName) - 1] = 0;
+ _tsplitpath(szFilename, szDrive, szPath, NULL, NULL);
+ mir_sntprintf(szFinalName, MAX_PATH, _T("%s\\%s%s"), szDrive, szPath, buffer);
+ if(!PathFileExists(szFinalName)) {
+ delete[] szFinalName;
+ szFinalName = 0;
+ }
+ m_alpha = GetPrivateProfileInt(m_szName, _T("Alpha"), 100, szFilename);
+ m_alpha = min(m_alpha, 100);
+ m_alpha = (BYTE)((FLOAT)(((FLOAT) m_alpha) / 100) * 255);
+ m_bf.SourceConstantAlpha = m_alpha;
+ m_bLeft = GetPrivateProfileInt(m_szName, _T("Left"), 0, szFilename);
+ m_bRight = GetPrivateProfileInt(m_szName, _T("Right"), 0, szFilename);
+ m_bTop = GetPrivateProfileInt(m_szName, _T("Top"), 0, szFilename);
+ m_bBottom = GetPrivateProfileInt(m_szName, _T("Bottom"), 0, szFilename);
+ if (m_dwFlags & IMAGE_GLYPH) {
+ m_width = m_glyphMetrics[2];
+ m_height = m_glyphMetrics[3];
+ m_inner_height = m_glyphMetrics[3] - m_bTop - m_bBottom;
+ m_inner_width = m_glyphMetrics[2] - m_bRight - m_bLeft;
+
+ if (m_bTop && m_bBottom && m_bLeft && m_bRight)
+ m_dwFlags |= IMAGE_FLAG_DIVIDED;
+ m_bf.BlendFlags = 0;
+ m_bf.BlendOp = AC_SRC_OVER;
+ m_bf.AlphaFormat = 0;
+ m_dwFlags |= IMAGE_PERPIXEL_ALPHA;
+ m_bf.AlphaFormat = AC_SRC_ALPHA;
+ if (m_inner_height <= 0 || m_inner_width <= 0) {
+ if(szFinalName) {
+ delete[] szFinalName;
+ szFinalName = 0;
+ }
+ return(szFinalName);
+ }
+ }
+ GetPrivateProfileString(m_szName, _T("Fillcolor"), _T("None"), buffer, 500, szFilename);
+ if (_tcscmp(buffer, _T("None"))) {
+ COLORREF fillColor = CSkin::HexStringToLong(buffer);
+ m_fillBrush = CreateSolidBrush(fillColor);
+ m_dwFlags |= IMAGE_FILLSOLID;
+ } else
+ m_fillBrush = 0;
+ GetPrivateProfileString(m_szName, _T("Colorkey"), _T("None"), buffer, 500, szFilename);
+ if (_tcscmp(buffer, _T("None"))) {
+ CSkin::m_ContainerColorKey = CSkin::HexStringToLong(buffer);
+ if (CSkin::m_ContainerColorKeyBrush)
+ DeleteObject(CSkin::m_ContainerColorKeyBrush);
+ CSkin::m_ContainerColorKeyBrush = CreateSolidBrush(CSkin::m_ContainerColorKey);
+ }
+ GetPrivateProfileString(m_szName, _T("Stretch"), _T("None"), buffer, 500, szFilename);
+ if (buffer[0] == 'B' || buffer[0] == 'b')
+ m_bStretch = IMAGE_STRETCH_B;
+ else if (buffer[0] == 'h' || buffer[0] == 'H')
+ m_bStretch = IMAGE_STRETCH_V;
+ else if (buffer[0] == 'w' || buffer[0] == 'W')
+ m_bStretch = IMAGE_STRETCH_H;
+ m_hbm = 0;
+ if (GetPrivateProfileInt(m_szName, _T("Perpixel"), 0, szFilename))
+ m_dwFlags |= IMAGE_PERPIXEL_ALPHA;
+
+ return(szFinalName);
+ }
+ return 0;
+}
+
+/**
+ * Free all resources allocated by an image item
+ */
+void CImageItem::Free()
+{
+ if(m_hdc ) {
+ ::SelectObject(m_hdc, m_hbmOld);
+ ::DeleteDC(m_hdc);
+ }
+ if(m_hbm)
+ ::DeleteObject(m_hbm);
+
+ if(m_fillBrush)
+ ::DeleteObject(m_fillBrush);
+
+ ZeroMemory(this, sizeof(CImageItem));
+}
+
+/**
+ * Set the alpha value for a 32bit RGBA bitmap to the given value
+ *
+ * @param hBitmap bitmap handle
+ * @param bAlpha new alpha value (0 -> fully transparent, 255 -> opaque)
+ * default value is 255
+ */
+void CImageItem::SetBitmap32Alpha(HBITMAP hBitmap, BYTE bAlpha)
+{
+ BITMAP bmp;
+ DWORD dwLen;
+ BYTE *p;
+ int x, y;
+ BOOL fixIt = TRUE;
+
+ GetObject(hBitmap, sizeof(bmp), &bmp);
+
+ if (bmp.bmBitsPixel != 32)
+ return;
+
+ dwLen = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8);
+ p = (BYTE *)malloc(dwLen);
+ if (p == NULL)
+ return;
+ memset(p, 0, dwLen);
+
+ GetBitmapBits(hBitmap, dwLen, p);
+
+ for (y = 0; y < bmp.bmHeight; ++y) {
+ BYTE *px = p + bmp.bmWidth * 4 * y;
+
+ for (x = 0; x < bmp.bmWidth; ++x) {
+ px[3] = bAlpha;
+ px += 4;
+ }
+ }
+ SetBitmapBits(hBitmap, bmp.bmWidth * bmp.bmHeight * 4, p);
+ free(p);
+}
+
+void CImageItem::PreMultiply(HBITMAP hBitmap, int mode)
+{
+ BYTE *p = NULL;
+ DWORD dwLen;
+ int width, height, x, y;
+ BITMAP bmp;
+ BYTE alpha;
+
+ ::GetObject(hBitmap, sizeof(bmp), &bmp);
+ width = bmp.bmWidth;
+ height = bmp.bmHeight;
+ dwLen = width * height * 4;
+ p = (BYTE *)malloc(dwLen);
+ if (p) {
+ ::GetBitmapBits(hBitmap, dwLen, p);
+ for (y = 0; y < height; ++y) {
+ BYTE *px = p + width * 4 * y;
+
+ for (x = 0; x < width; ++x) {
+ if (mode) {
+ alpha = px[3];
+ px[0] = px[0] * alpha / 255;
+ px[1] = px[1] * alpha / 255;
+ px[2] = px[2] * alpha / 255;
+ } else
+ px[3] = 255;
+ px += 4;
+ }
+ }
+ dwLen = ::SetBitmapBits(hBitmap, dwLen, p);
+ free(p);
+ }
+}
+
+void CImageItem::Colorize(HBITMAP hBitmap, BYTE dr, BYTE dg, BYTE db, BYTE alpha)
+{
+ BYTE *p = NULL;
+ DWORD dwLen;
+ int width, height, x, y;
+ BITMAP bmp;
+
+ float r = (float)dr / 2.55;
+ float g = (float)dg / 2.55;
+ float b = (float)db / 2.55;
+
+ ::GetObject(hBitmap, sizeof(bmp), &bmp);
+ width = bmp.bmWidth;
+ height = bmp.bmHeight;
+ dwLen = width * height * 4;
+ p = (BYTE *)malloc(dwLen);
+ if (p) {
+ ::GetBitmapBits(hBitmap, dwLen, p);
+ for (y = 0; y < height; ++y) {
+ BYTE *px = p + width * 4 * y;
+
+ for (x = 0; x < width; ++x) {
+ px[0] = (int)(px[0] + b) > 255 ? 255 : px[0] + b;
+ px[1] = (int)(px[1] + g) > 255 ? 255 : px[1] + g;
+ px[2] = (int)(px[2] + r) > 255 ? 255 : px[2] + r;
+ px[3] += alpha;
+ px += 4;
+ }
+ }
+ dwLen = ::SetBitmapBits(hBitmap, dwLen, p);
+ free(p);
+ }
+}
+
+/**
+ * load PNG image using core service (advaimg)
+ */
+
+HBITMAP TSAPI CImageItem::LoadPNG(const TCHAR *szFilename)
+{
+ HBITMAP hBitmap = 0;
+ hBitmap = (HBITMAP)CallService(MS_IMG_LOAD, (WPARAM)szFilename, IMGL_TCHAR);
+ return hBitmap;
+}
+
+
+/**
+ * set filename and load parameters from the database
+ * called on:
+ * ) init
+ * ) manual loading on user's request
+ */
+void CSkin::setFileName()
+{
+ DBVARIANT dbv;
+ if(0 == M->GetTString(0, SRMSGMOD_T, "ContainerSkin", &dbv)) {
+ M->pathToAbsolute(dbv.ptszVal, m_tszFileName, M->getSkinPath());
+ m_tszFileName[MAX_PATH - 1] = 0;
+ DBFreeVariant(&dbv);
+ }
+ else
+ m_tszFileName[0] = 0;
+
+ m_fLoadOnStartup = M->GetByte("useskin", 0) ? true : false;
+}
+/**
+ * initialize the skin object
+ */
+
+void CSkin::Init(bool fStartup)
+{
+ m_ImageItems = 0;
+ ZeroMemory(this, sizeof(CSkin));
+ m_SkinItems = ::SkinItems;
+ m_fLoadOnStartup = false;
+ m_skinEnabled = m_frameSkins = false;
+ m_bAvatarBorderType = AVBORDER_NORMAL;
+ m_avatarBorderClr = ::GetSysColor(COLOR_3DDKSHADOW);
+ m_sideBarContainerBG = ::GetSysColor(COLOR_3DFACE);
+
+ m_SkinItems[ID_EXTBKINFOPANELBG] = _defInfoPanel;
+ /*
+ * read current skin name from db
+ */
+
+ m_DisableScrollbars = M->GetByte("disableVScroll", 0) ? true : false;
+
+ setFileName();
+ m_aeroEffect = M->GetDword("aerostyle", AERO_EFFECT_MILK);
+ if(m_fLoadOnStartup && fStartup)
+ Load();
+}
+
+/**
+ * throws a warning to close all message windows before a skin can
+ * be loaded. user can cancel it
+ * @return: bool: true if windows were closed (or none was open) -> skin can be loaded
+ *
+ */
+bool CSkin::warnToClose() const
+{
+ if (::pFirstContainer) {
+ if (MessageBox(0, CTranslator::get(CTranslator::GEN_SKIN_WARNCLOSE),
+ CTranslator::get(CTranslator::GEN_SKIN_WARNCLOSE_TITLE), MB_YESNO | MB_ICONQUESTION) == IDYES) {
+ TContainerData *pContainer = ::pFirstContainer;
+ while (pFirstContainer)
+ SendMessage(pFirstContainer->hwnd, WM_CLOSE, 0, 1);
+ return true;
+ } else
+ return false;
+ }
+ return true;
+}
+
+/**
+ * free the aero tab bitmaps
+ * only called on exit, NOT when a skin is unloaded as these elements
+ * are always needed (even without a skin)
+ */
+void CSkin::UnloadAeroTabs()
+{
+ if(m_tabTop) {
+ delete m_tabTop;
+ m_tabTop = NULL;
+ }
+
+ if(m_tabBottom) {
+ delete m_tabBottom;
+ m_tabBottom = NULL;
+ }
+
+ if(m_tabGlowTop) {
+ delete m_tabGlowTop;
+ m_tabGlowTop = NULL;
+ }
+
+ if(m_tabGlowBottom) {
+ delete m_tabGlowBottom;
+ m_tabGlowTop = NULL;
+ }
+
+ if(m_switchBarItem) {
+ delete m_switchBarItem;
+ m_switchBarItem = NULL;
+ }
+}
+
+/**
+ * Unload the skin. Free everything allocated.
+ * Called when:
+ * * user unloads the skin from the dialog box
+ * * a new skin is loaded by user's request.
+ */
+
+void CSkin::Unload()
+{
+ int i;
+ CImageItem *tmp = m_ImageItems, *nextItem = 0;
+
+ /*
+ * delete all image items
+ */
+
+ if(warnToClose() == false)
+ return; // do nothing when user decides to not close any window
+
+ m_skinEnabled = m_frameSkins = false;
+
+ while(tmp) {
+ nextItem = tmp->getNextItem();
+ delete tmp;
+ tmp = nextItem;
+ }
+
+ m_ImageItems = 0;
+ m_glyphItem.Free();
+
+ if(m_ContainerColorKeyBrush)
+ ::DeleteObject(m_ContainerColorKeyBrush);
+ if(m_MenuBGBrush)
+ ::DeleteObject(m_MenuBGBrush);
+
+ m_ContainerColorKeyBrush = m_MenuBGBrush = 0;
+
+ if(m_SkinLightShadowPen)
+ ::DeleteObject(m_SkinLightShadowPen);
+ m_SkinLightShadowPen = 0;
+
+ if(m_SkinDarkShadowPen)
+ ::DeleteObject(m_SkinDarkShadowPen);
+ m_SkinDarkShadowPen = 0;
+
+ for(i = 0; i < ID_EXTBK_LAST; i++) {
+ m_SkinItems[i].IGNORED = 1;
+ m_SkinItems[i].imageItem = 0;
+ }
+ m_SkinItems[ID_EXTBKINFOPANELBG] = _defInfoPanel;
+
+ ZeroMemory(this, sizeof(CSkin));
+
+ m_SkinItems = ::SkinItems;
+ setFileName();
+
+ m_bClipBorder = m_DisableScrollbars = false;
+ m_SkinnedFrame_left = m_SkinnedFrame_right = m_SkinnedFrame_bottom = m_SkinnedFrame_caption = 0;
+ m_realSkinnedFrame_left = m_realSkinnedFrame_right = m_realSkinnedFrame_bottom = m_realSkinnedFrame_caption = 0;
+
+ m_titleBarLeftOff = m_titleButtonTopOff = m_captionOffset = m_captionPadding =
+ m_titleBarRightOff = m_sidebarTopOffset = m_sidebarBottomOffset = m_bRoundedCorner = 0;
+
+ m_titleBarButtonSize.cx = m_titleBarButtonSize.cy = 0;
+ m_ContainerColorKey = 0;
+ m_ContainerColorKeyBrush = m_MenuBGBrush = 0;
+ m_skinEnabled = m_frameSkins = false;
+
+ if(m_closeIcon)
+ ::DestroyIcon(m_closeIcon);
+ if(m_maxIcon)
+ ::DestroyIcon(m_maxIcon);
+ if(m_minIcon)
+ ::DestroyIcon(m_minIcon);
+
+ m_closeIcon = m_maxIcon = m_minIcon = 0;
+
+ for(i = 0; i < m_nrSkinIcons; i++) {
+ if(m_skinIcons[i].phIcon )
+ ::DestroyIcon(*(m_skinIcons[i].phIcon));
+ }
+ M->getAeroState(); // refresh after unload
+ ::FreeTabConfig();
+ ::ReloadTabConfig();
+
+ m_bAvatarBorderType = AVBORDER_NORMAL;
+ m_avatarBorderClr = ::GetSysColor(COLOR_3DDKSHADOW);
+ m_sideBarContainerBG = ::GetSysColor(COLOR_3DFACE);
+
+ m_DisableScrollbars = M->GetByte("disableVScroll", 0) ? true : false;
+}
+
+void CSkin::LoadIcon(const TCHAR *szSection, const TCHAR *name, HICON *hIcon)
+{
+ TCHAR buffer[512];
+ if (*hIcon != 0)
+ DestroyIcon(*hIcon);
+ GetPrivateProfileString(szSection, name, _T("none"), buffer, 250, m_tszFileName);
+ buffer[500] = 0;
+
+ if (_tcsicmp(buffer, _T("none"))) {
+ TCHAR szDrive[MAX_PATH], szDir[MAX_PATH], szImagePath[MAX_PATH];
+
+ _tsplitpath(m_tszFileName, szDrive, szDir, NULL, NULL);
+ mir_sntprintf(szImagePath, MAX_PATH, _T("%s\\%s\\%s"), szDrive, szDir, buffer);
+ if (hIcon)
+ *hIcon = (HICON)LoadImage(0, szImagePath, IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
+ }
+}
+
+
+/**
+ * Read a skin item (not a image item - these are handled elsewhere)
+ * Reads all values from the .ini style .tsk file and fills the
+ * structure.
+ *
+ * @param id int: zero-based index into the table of predefined skin items
+ * @param szItem char *: the section name in the ini file which holds the definition for this
+ * item.
+ */
+void CSkin::ReadItem(const int id, const TCHAR *szItem)
+{
+ TCHAR buffer[512];
+ TCHAR def_color[20];
+ COLORREF clr;
+ CSkinItem *defaults = &StatusItem_Default;
+
+ CSkinItem *this_item = &m_SkinItems[id];
+
+ this_item->ALPHA = (int)GetPrivateProfileInt(szItem, _T("Alpha"), defaults->ALPHA, m_tszFileName);
+ this_item->ALPHA = min(this_item->ALPHA, 100);
+
+ clr = RGB(GetBValue(defaults->COLOR), GetGValue(defaults->COLOR), GetRValue(defaults->COLOR));
+ _sntprintf(def_color, 15, _T("%6.6x"), clr);
+ GetPrivateProfileString(szItem, _T("Color1"), def_color, buffer, 400, m_tszFileName);
+ this_item->COLOR = HexStringToLong(buffer);
+
+ clr = RGB(GetBValue(defaults->COLOR2), GetGValue(defaults->COLOR2), GetRValue(defaults->COLOR2));
+ _sntprintf(def_color, 15, _T("%6.6x"), clr);
+ GetPrivateProfileString(szItem, _T("Color2"), def_color, buffer, 400, m_tszFileName);
+ this_item->COLOR2 = HexStringToLong(buffer);
+
+ this_item->COLOR2_TRANSPARENT = (BYTE)GetPrivateProfileInt(szItem, _T("COLOR2_TRANSPARENT"), defaults->COLOR2_TRANSPARENT, m_tszFileName);
+
+ this_item->CORNER = defaults->CORNER & CORNER_ACTIVE ? defaults->CORNER : 0;
+ GetPrivateProfileString(szItem, _T("Corner"), _T("None"), buffer, 400, m_tszFileName);
+ if (_tcsstr(buffer, _T("tl")))
+ this_item->CORNER |= CORNER_TL;
+ if (_tcsstr(buffer, _T("tr")))
+ this_item->CORNER |= CORNER_TR;
+ if (_tcsstr(buffer, _T("bl")))
+ this_item->CORNER |= CORNER_BL;
+ if (_tcsstr(buffer, _T("br")))
+ this_item->CORNER |= CORNER_BR;
+ if (this_item->CORNER)
+ this_item->CORNER |= CORNER_ACTIVE;
+
+ this_item->GRADIENT = defaults->GRADIENT & GRADIENT_ACTIVE ? defaults->GRADIENT : 0;
+ GetPrivateProfileString(szItem, _T("Gradient"), _T("None"), buffer, 400, m_tszFileName);
+ if (_tcsstr(buffer, _T("left")))
+ this_item->GRADIENT = GRADIENT_RL;
+ else if (_tcsstr(buffer, _T("right")))
+ this_item->GRADIENT = GRADIENT_LR;
+ else if (_tcsstr(buffer, _T("up")))
+ this_item->GRADIENT = GRADIENT_BT;
+ else if (_tcsstr(buffer, _T("down")))
+ this_item->GRADIENT = GRADIENT_TB;
+ if (this_item->GRADIENT)
+ this_item->GRADIENT |= GRADIENT_ACTIVE;
+
+ this_item->MARGIN_LEFT = GetPrivateProfileInt(szItem, _T("Left"), defaults->MARGIN_LEFT, m_tszFileName);
+ this_item->MARGIN_RIGHT = GetPrivateProfileInt(szItem, _T("Right"), defaults->MARGIN_RIGHT, m_tszFileName);
+ this_item->MARGIN_TOP = GetPrivateProfileInt(szItem, _T("Top"), defaults->MARGIN_TOP, m_tszFileName);
+ this_item->MARGIN_BOTTOM = GetPrivateProfileInt(szItem, _T("Bottom"), defaults->MARGIN_BOTTOM, m_tszFileName);
+ this_item->BORDERSTYLE = GetPrivateProfileInt(szItem, _T("Radius"), defaults->BORDERSTYLE, m_tszFileName);
+
+ GetPrivateProfileString(szItem, _T("Textcolor"), _T("ffffffff"), buffer, 400, m_tszFileName);
+ this_item->TEXTCOLOR = HexStringToLong(buffer);
+ this_item->IGNORED = 0;
+}
+
+/**
+ * stub to read a single item. Called from CSkin::LoadItems()
+ * The real work is done by the CImageItem::Read().
+ *
+ * @param itemname char *: image item name, also section name in the .tsk file
+ */
+void CSkin::ReadImageItem(const TCHAR *itemname)
+{
+ TCHAR buffer[512], szItemNr[30];
+
+ CImageItem tmpItem(itemname);
+
+ TCHAR *szImageFileName = tmpItem.Read(m_tszFileName);
+
+ if (!_tcsicmp(itemname, _T("$glyphs")) && szImageFileName != 0) { // the glyph item MUST have a valid image
+ tmpItem.Create(szImageFileName);
+ if (tmpItem.getHbm()) {
+ m_glyphItem = tmpItem;
+ m_fHaveGlyph = true;
+ }
+ tmpItem.Clear();
+ delete[] szImageFileName;
+ return;
+ }
+
+ /*
+ * handle the assignments of image items to skin items
+ */
+
+ for (int n = 0;;n++) {
+ mir_sntprintf(szItemNr, 30, _T("Item%d"), n);
+ GetPrivateProfileString(itemname, szItemNr, _T("None"), buffer, 500, m_tszFileName);
+ if (!_tcscmp(buffer, _T("None")))
+ break;
+ for (int i = 0; i <= ID_EXTBK_LAST; i++) {
+ if (!_tcsicmp(SkinItems[i].szName[0] == '{' ? &SkinItems[i].szName[3] : SkinItems[i].szName, buffer)) {
+ if (!(tmpItem.getFlags() & IMAGE_GLYPH)) {
+ if(szImageFileName)
+ tmpItem.Create(szImageFileName);
+ else {
+ tmpItem.Clear();
+ return; // no reference to the glpyh image and no valid image file name -> invalid item
+ }
+ }
+ if (tmpItem.getHbm() || (tmpItem.getFlags() & IMAGE_GLYPH)) {
+ CImageItem *newItem = new CImageItem(tmpItem);
+ SkinItems[i].imageItem = newItem;
+ if (m_ImageItems == NULL)
+ m_ImageItems = newItem;
+ else {
+ CImageItem *pItem = m_ImageItems;
+
+ while (pItem->getNextItem() != 0)
+ pItem = pItem->getNextItem();
+ pItem->setNextItem(newItem);
+ }
+ }
+ }
+ }
+ }
+ tmpItem.Clear();
+ if(szImageFileName)
+ delete szImageFileName;
+}
+
+/* DISABLED code
+
+void CSkin::ReadButtonItem(const TCHAR *itemName) const
+{
+ ButtonItem tmpItem, *newItem;
+ TCHAR szBuffer[1024];
+ char szBufferA[1024];
+ CImageItem *imgItem = m_ImageItems;
+ HICON *phIcon;
+
+ ZeroMemory(&tmpItem, sizeof(tmpItem));
+ mir_snprintf(tmpItem.szName, safe_sizeof(tmpItem.szName), "%s", &szItemNameA[1]);
+ tmpItem.width = GetPrivateProfileInt(itemName, _T("Width"), 16, m_tszFileName);
+ tmpItem.height = GetPrivateProfileInt(itemName,_T( "Height"), 16, m_tszFileName);
+ tmpItem.xOff = GetPrivateProfileInt(itemName, _T("xoff"), 0, m_tszFileName);
+ tmpItem.yOff = GetPrivateProfileInt(itemName, _T("yoff"), 0, m_tszFileName);
+
+ tmpItem.dwFlags |= GetPrivateProfileInt(itemName, _T("toggle"), 0, m_tszFileName) ? BUTTON_ISTOGGLE : 0;
+
+ GetPrivateProfileString(itemName, _T("Pressed"), _T("None"), szBuffer, 1000, m_tszFileName);
+ if (!_tcsicmp(szBuffer, _T("default")))
+ tmpItem.imgPressed = SkinItems[ID_EXTBKBUTTONSPRESSED].imageItem;
+ else {
+ while (imgItem) {
+ if (!_tcsicmp(imgItem->getName(), szBuffer)) {
+ tmpItem.imgPressed = imgItem;
+ break;
+ }
+ imgItem = imgItem->getNextItem();
+ }
+ }
+
+ imgItem = m_ImageItems;
+ GetPrivateProfileString(itemName, _T("Normal"), _T("None"), szBuffer, 1000, m_tszFileName);
+ if (!_tcsicmp(szBuffer, _T("default")))
+ tmpItem.imgNormal = SkinItems[ID_EXTBKBUTTONSNPRESSED].imageItem;
+ else {
+ while (imgItem) {
+ if (!_tcsicmp(imgItem->getName(), szBuffer)) {
+ tmpItem.imgNormal = imgItem;
+ break;
+ }
+ imgItem = imgItem->getNextItem();
+ }
+ }
+
+ imgItem = m_ImageItems;
+ GetPrivateProfileString(itemName, _T("Hover"), _T("None"), szBuffer, 1000, m_tszFileName);
+ if (!_tcsicmp(szBuffer, _T("default")))
+ tmpItem.imgHover = SkinItems[ID_EXTBKBUTTONSMOUSEOVER].imageItem;
+ else {
+ while (imgItem) {
+ if (!_tcsicmp(imgItem->getName(), szBuffer)) {
+ tmpItem.imgHover = imgItem;
+ break;
+ }
+ imgItem = imgItem->getNextItem();
+ }
+ }
+
+ tmpItem.uId = IDC_TBFIRSTUID - 1;
+ tmpItem.pfnAction = tmpItem.pfnCallback = NULL;
+
+ GetPrivateProfileString(itemName, _T("Action"), _T("Custom"), szBuffer, 1000, m_tszFileName);
+ if (!_tcsicmp(szBuffer, _T("service"))) {
+ tmpItem.szService[0] = 0;
+ GetPrivateProfileStringA(szItemNameA, "Service", "None", szBufferA, 1000, szFileNameA);
+ if (_stricmp(szBufferA, "None")) {
+ mir_snprintf(tmpItem.szService, 256, "%s", szBufferA);
+ tmpItem.dwFlags |= BUTTON_ISSERVICE;
+ tmpItem.uId = nextButtonID++;
+ }
+ } else if (!_tcsicmp(szBuffer, _T("protoservice"))) {
+ tmpItem.szService[0] = 0;
+ GetPrivateProfileStringA(szItemNameA, "Service", "None", szBufferA, 1000, szFileNameA);
+ if (_stricmp(szBufferA, "None")) {
+ mir_snprintf(tmpItem.szService, 256, "%s", szBufferA);
+ tmpItem.dwFlags |= BUTTON_ISPROTOSERVICE;
+ tmpItem.uId = nextButtonID++;
+ }
+ } else if (!_tcsicmp(szBuffer, _T("database"))) {
+ int n;
+
+ GetPrivateProfileStringA(szItemNameA, "Module", "None", szBufferA, 1000, szFileNameA);
+ if (_stricmp(szBufferA, "None"))
+ mir_snprintf(tmpItem.szModule, 256, "%s", szBufferA);
+ GetPrivateProfileStringA(szItemNameA, "Setting", "None", szBufferA, 1000, szFileNameA);
+ if (_stricmp(szBufferA, "None"))
+ mir_snprintf(tmpItem.szSetting, 256, "%s", szBufferA);
+ if (GetPrivateProfileIntA(szItemNameA, "contact", 0, szFileNameA) != 0)
+ tmpItem.dwFlags |= BUTTON_DBACTIONONCONTACT;
+
+ for (n = 0; n <= 1; n++) {
+ char szKey[20];
+ BYTE *pValue;
+
+ strcpy(szKey, n == 0 ? "dbonpush" : "dbonrelease");
+ pValue = (n == 0 ? tmpItem.bValuePush : tmpItem.bValueRelease);
+
+ GetPrivateProfileStringA(szItemNameA, szKey, "None", szBufferA, 1000, szFileNameA);
+ switch (szBufferA[0]) {
+ case 'b': {
+ BYTE value = (BYTE)atol(&szBufferA[1]);
+ pValue[0] = value;
+ tmpItem.type = DBVT_BYTE;
+ break;
+ }
+ case 'w': {
+ WORD value = (WORD)atol(&szBufferA[1]);
+ *((WORD *)&pValue[0]) = value;
+ tmpItem.type = DBVT_WORD;
+ break;
+ }
+ case 'd': {
+ DWORD value = (DWORD)atol(&szBufferA[1]);
+ *((DWORD *)&pValue[0]) = value;
+ tmpItem.type = DBVT_DWORD;
+ break;
+ }
+ case 's': {
+ mir_snprintf((char *)pValue, 256, &szBufferA[1]);
+ tmpItem.type = DBVT_ASCIIZ;
+ break;
+ }
+ }
+ }
+ if (tmpItem.szModule[0] && tmpItem.szSetting[0]) {
+ tmpItem.dwFlags |= BUTTON_ISDBACTION;
+ if (tmpItem.szModule[0] == '$' && (tmpItem.szModule[1] == 'c' || tmpItem.szModule[1] == 'C'))
+ tmpItem.dwFlags |= BUTTON_ISCONTACTDBACTION;
+ tmpItem.uId = nextButtonID++;
+ }
+ } else if (_tcsicmp(szBuffer, _T("Custom"))) {
+ if (BTN_GetStockItem(&tmpItem, szBuffer))
+ goto create_it;
+ }
+ GetPrivateProfileString(itemName, _T("PassContact"), _T("None"), szBuffer, 1000, m_tszFileName);
+ if (_tcsicmp(szBuffer, _T("None"))) {
+ if (szBuffer[0] == 'w' || szBuffer[0] == 'W')
+ tmpItem.dwFlags |= BUTTON_PASSHCONTACTW;
+ else if (szBuffer[0] == 'l' || szBuffer[0] == 'L')
+ tmpItem.dwFlags |= BUTTON_PASSHCONTACTL;
+ }
+
+ GetPrivateProfileString(itemName, _T("Tip"), _T("None"), szBuffer, 1000, m_tszFileName);
+ if (_tcsicmp(szBuffer, _T("None"))) {
+ mir_sntprintf(tmpItem.szTip, 256, _T("%s"), szBuffer);
+ } else
+ tmpItem.szTip[0] = 0;
+
+create_it:
+
+ GetPrivateProfileString(itemName, _T("Label"), _T("None"), szBuffer, 40, m_tszFileName);
+ if (_tcsicmp(szBuffer, _T("None"))) {
+ mir_sntprintf(tmpItem.tszLabel, 40, _T("%s"), szBuffer);
+ tmpItem.dwFlags |= BUTTON_HASLABEL;
+ } else
+ tmpItem.tszLabel[0] = 0;
+
+ GetPrivateProfileString(itemName, _T("NormalGlyph"), _T("0, 0, 0, 0"), szBuffer, 1000, m_tszFileName);
+ if (_tcsicmp(szBuffer, _T("default"))) {
+ tmpItem.dwFlags &= ~BUTTON_NORMALGLYPHISICON;
+ if ((phIcon = BTN_GetIcon(szBuffer)) != 0) {
+ tmpItem.dwFlags |= BUTTON_NORMALGLYPHISICON;
+ tmpItem.normalGlyphMetrics[0] = (LONG_PTR)phIcon;
+ } else {
+ _tscanf(szBuffer, _T("%d,%d,%d,%d"), &tmpItem.normalGlyphMetrics[0], &tmpItem.normalGlyphMetrics[1],
+ &tmpItem.normalGlyphMetrics[2], &tmpItem.normalGlyphMetrics[3]);
+ tmpItem.normalGlyphMetrics[2] = (tmpItem.normalGlyphMetrics[2] - tmpItem.normalGlyphMetrics[0]) + 1;
+ tmpItem.normalGlyphMetrics[3] = (tmpItem.normalGlyphMetrics[3] - tmpItem.normalGlyphMetrics[1]) + 1;
+ }
+ }
+
+ GetPrivateProfileString(itemName, _T("PressedGlyph"), _T("0, 0, 0, 0"), szBuffer, 1000, m_tszFileName);
+ if (_tcsicmp(szBuffer, _T("default"))) {
+ tmpItem.dwFlags &= ~BUTTON_PRESSEDGLYPHISICON;
+ if ((phIcon = BTN_GetIcon(szBuffer)) != 0) {
+ tmpItem.pressedGlyphMetrics[0] = (LONG_PTR)phIcon;
+ tmpItem.dwFlags |= BUTTON_PRESSEDGLYPHISICON;
+ } else {
+ _tscanf(szBuffer, _T("%d,%d,%d,%d"), &tmpItem.pressedGlyphMetrics[0], &tmpItem.pressedGlyphMetrics[1],
+ &tmpItem.pressedGlyphMetrics[2], &tmpItem.pressedGlyphMetrics[3]);
+ tmpItem.pressedGlyphMetrics[2] = (tmpItem.pressedGlyphMetrics[2] - tmpItem.pressedGlyphMetrics[0]) + 1;
+ tmpItem.pressedGlyphMetrics[3] = (tmpItem.pressedGlyphMetrics[3] - tmpItem.pressedGlyphMetrics[1]) + 1;
+ }
+ }
+
+ GetPrivateProfileString(itemName, _T("HoverGlyph"), _T("0, 0, 0, 0"), szBuffer, 1000, m_tszFileName);
+ if (_tcsicmp(szBuffer, _T("default"))) {
+ tmpItem.dwFlags &= ~BUTTON_HOVERGLYPHISICON;
+ if ((phIcon = BTN_GetIcon(szBuffer)) != 0) {
+ tmpItem.hoverGlyphMetrics[0] = (LONG_PTR)phIcon;
+ tmpItem.dwFlags |= BUTTON_HOVERGLYPHISICON;
+ } else {
+ _tscanf(szBuffer, _T("%d,%d,%d,%d"), &tmpItem.hoverGlyphMetrics[0], &tmpItem.hoverGlyphMetrics[1],
+ &tmpItem.hoverGlyphMetrics[2], &tmpItem.hoverGlyphMetrics[3]);
+ tmpItem.hoverGlyphMetrics[2] = (tmpItem.hoverGlyphMetrics[2] - tmpItem.hoverGlyphMetrics[0]) + 1;
+ tmpItem.hoverGlyphMetrics[3] = (tmpItem.hoverGlyphMetrics[3] - tmpItem.hoverGlyphMetrics[1]) + 1;
+ }
+ }
+
+ newItem = (ButtonItem *)malloc(sizeof(ButtonItem));
+ ZeroMemory(newItem, sizeof(ButtonItem));
+ if (g_ButtonSet.items == NULL) {
+ g_ButtonSet.items = newItem;
+ *newItem = tmpItem;
+ newItem->nextItem = 0;
+ } else {
+ ButtonItem *curItem = g_ButtonSet.items;
+ while (curItem->nextItem)
+ curItem = curItem->nextItem;
+ *newItem = tmpItem;
+ newItem->nextItem = 0;
+ curItem->nextItem = newItem;
+ }
+#ifdef _UNICODE
+ mir_free((void *)szItemNameA);
+#endif
+ return;
+}
+
+*/
+
+/**
+ * Load the skin from the .tsk file
+ * It reads and initializes all static values for the skin. Afterwards
+ * it calls ReadItems() to read additional skin information like image items,
+ * buttons and icons.
+ */
+void CSkin::Load()
+{
+ if(warnToClose() == false)
+ return;
+
+ if(m_skinEnabled) {
+ Unload();
+ m_skinEnabled = false;
+ }
+
+ m_fHaveGlyph = false;
+
+ if(m_tszFileName[0]) {
+ if(::PathFileExists(m_tszFileName)) {
+ TCHAR *p;
+ TCHAR *szSections = (TCHAR *)malloc(6004);
+ int i = 1, j = 0;
+ UINT data;
+ TCHAR buffer[500];
+
+ if (!(GetPrivateProfileInt(_T("Global"), _T("Version"), 0, m_tszFileName) >= 1 &&
+ GetPrivateProfileInt(_T("Global"), _T("Signature"), 0, m_tszFileName) == 101))
+ return;
+
+ i = 0;
+ while (_tagSettings[i].szIniKey != NULL) {
+ data = 0;
+ data = GetPrivateProfileInt(_tagSettings[i].szIniKey, _tagSettings[i].szIniName,
+ _tagSettings[i].defaultval, m_tszFileName);
+ switch (_tagSettings[i].size) {
+ case 1:
+ M->WriteByte(SRMSGMOD_T, _tagSettings[i].szSetting, (BYTE)data);
+ break;
+ case 4:
+ M->WriteDword(SRMSGMOD_T, _tagSettings[i].szSetting, data);
+ break;
+ case 2:
+ DBWriteContactSettingWord(NULL, SRMSGMOD_T, _tagSettings[i].szSetting, (WORD)data);
+ break;
+ case 5:
+ GetPrivateProfileString(_tagSettings[i].szIniKey, _tagSettings[i].szIniName, _T("000000"),
+ buffer, 10, m_tszFileName);
+ M->WriteDword(SRMSGMOD_T, _tagSettings[i].szSetting, HexStringToLong(buffer));
+ break;
+ }
+ i++;
+ }
+
+ m_DisableScrollbars = M->GetByte("disableVScroll", 0) ? true : false;
+
+ ZeroMemory(szSections, 6000);
+ p = szSections;
+ GetPrivateProfileSectionNames(szSections, 3000, m_tszFileName);
+ szSections[3001] = szSections[3000] = 0;
+ p = szSections;
+ while (lstrlen(p) > 1) {
+ if (p[0] != '%') {
+ p += (lstrlen(p) + 1);
+ continue;
+ }
+ for (i = 0; i <= ID_EXTBK_LAST; i++) {
+ if (!_tcsicmp(&p[1], SkinItems[i].szName[0] == '{' ? &SkinItems[i].szName[3] : SkinItems[i].szName)) {
+ ReadItem(i, p);
+ break;
+ }
+ }
+ p += (lstrlen(p) + 1);
+ j++;
+ }
+
+ if (j > 0) {
+ m_skinEnabled = true;
+ M->getAeroState(); // refresh aero state (set to false when a skin is successfully loaded and active)
+ }
+
+ GetPrivateProfileString(_T("Avatars"), _T("BorderColor"), _T("000000"), buffer, 20, m_tszFileName);
+ m_avatarBorderClr = (COLORREF)HexStringToLong(buffer);
+
+ GetPrivateProfileString(_T("Global"), _T("SideBarBG"), _T("None"), buffer, 20, m_tszFileName);
+ if(_tcscmp(buffer, _T("None")))
+ m_sideBarContainerBG = (COLORREF)HexStringToLong(buffer);
+ else
+ m_sideBarContainerBG = SkinItems[ID_EXTBKSIDEBARBG].COLOR;
+
+ m_bAvatarBorderType = GetPrivateProfileInt(_T("Avatars"), _T("BorderType"), 1, m_tszFileName);
+
+ LoadIcon(_T("Global"), _T("CloseGlyph"), &CSkin::m_closeIcon);
+ LoadIcon(_T("Global"), _T("MaximizeGlyph"), &CSkin::m_maxIcon);
+ LoadIcon(_T("Global"), _T("MinimizeGlyph"), &CSkin::m_minIcon);
+
+ m_frameSkins = GetPrivateProfileInt(_T("Global"), _T("framelessmode"), 0, m_tszFileName) ? true : false;
+ m_DisableScrollbars = GetPrivateProfileInt(_T("Global"), _T("NoScrollbars"), 0, m_tszFileName) ? true : false;
+
+ m_SkinnedFrame_left = GetPrivateProfileInt(_T("WindowFrame"), _T("left"), 4, m_tszFileName);
+ m_SkinnedFrame_right = GetPrivateProfileInt(_T("WindowFrame"), _T("right"), 4, m_tszFileName);
+ m_SkinnedFrame_caption = GetPrivateProfileInt(_T("WindowFrame"), _T("Caption"), 24, m_tszFileName);
+ m_SkinnedFrame_bottom = GetPrivateProfileInt(_T("WindowFrame"), _T("bottom"), 4, m_tszFileName);
+
+ m_titleBarButtonSize.cx = GetPrivateProfileInt(_T("WindowFrame"), _T("TitleButtonWidth"), 24, m_tszFileName);
+ m_titleBarButtonSize.cy = GetPrivateProfileInt(_T("WindowFrame"), _T("TitleButtonHeight"), 12, m_tszFileName);
+ m_titleButtonTopOff = GetPrivateProfileInt(_T("WindowFrame"), _T("TitleButtonTopOffset"), 0, m_tszFileName);
+
+ m_titleBarRightOff = GetPrivateProfileInt(_T("WindowFrame"), _T("TitleBarRightOffset"), 0, m_tszFileName);
+ m_titleBarLeftOff = GetPrivateProfileInt(_T("WindowFrame"), _T("TitleBarLeftOffset"), 0, m_tszFileName);
+
+ m_captionOffset = GetPrivateProfileInt(_T("WindowFrame"), _T("CaptionOffset"), 3, m_tszFileName);
+ m_captionPadding = GetPrivateProfileInt(_T("WindowFrame"), _T("CaptionPadding"), 0, m_tszFileName);
+ m_sidebarTopOffset = GetPrivateProfileInt(_T("ClientArea"), _T("SidebarTop"), -1, m_tszFileName);
+ m_sidebarBottomOffset = GetPrivateProfileInt(_T("ClientArea"), _T("SidebarBottom"), -1, m_tszFileName);
+
+ m_bClipBorder = GetPrivateProfileInt(_T("WindowFrame"), _T("ClipFrame"), 0, m_tszFileName) ? true : false;;
+
+ BYTE radius_tl, radius_tr, radius_bl, radius_br;
+ TCHAR szFinalName[MAX_PATH];
+ TCHAR szDrive[MAX_PATH], szPath[MAX_PATH];
+
+ radius_tl = GetPrivateProfileInt(_T("WindowFrame"), _T("RadiusTL"), 0, m_tszFileName);
+ radius_tr = GetPrivateProfileInt(_T("WindowFrame"), _T("RadiusTR"), 0, m_tszFileName);
+ radius_bl = GetPrivateProfileInt(_T("WindowFrame"), _T("RadiusBL"), 0, m_tszFileName);
+ radius_br = GetPrivateProfileInt(_T("WindowFrame"), _T("RadiusBR"), 0, m_tszFileName);
+
+ CSkin::m_bRoundedCorner = radius_tl;
+
+ GetPrivateProfileString(_T("Theme"), _T("File"), _T("None"), buffer, MAX_PATH, m_tszFileName);
+
+ _tsplitpath(m_tszFileName, szDrive, szPath, NULL, NULL);
+ mir_sntprintf(szFinalName, MAX_PATH, _T("%s\\%s\\%s"), szDrive, szPath, buffer);
+ if (PathFileExists(szFinalName)) {
+ ReadThemeFromINI(szFinalName, 0, FALSE, m_fLoadOnStartup ? 0 : M->GetByte("skin_loadmode", 0));
+ CacheLogFonts();
+ CacheMsgLogIcons();
+ }
+
+ GetPrivateProfileString(_T("Global"), _T("MenuBarBG"), _T("None"), buffer, 20, m_tszFileName);
+ data = HexStringToLong(buffer);
+ if (m_MenuBGBrush) {
+ DeleteObject(m_MenuBGBrush);
+ m_MenuBGBrush = 0;
+ }
+ if (_tcscmp(buffer, _T("None")))
+ m_MenuBGBrush = CreateSolidBrush(data);
+
+ GetPrivateProfileString(_T("Global"), _T("LightShadow"), _T("000000"), buffer, 20, m_tszFileName);
+ data = HexStringToLong(buffer);
+ CSkin::m_SkinLightShadowPen = CreatePen(PS_SOLID, 1, RGB(GetRValue(data), GetGValue(data), GetBValue(data)));
+ GetPrivateProfileString(_T("Global"), _T("DarkShadow"), _T("000000"), buffer, 20, m_tszFileName);
+ data = HexStringToLong(buffer);
+ CSkin::m_SkinDarkShadowPen = CreatePen(PS_SOLID, 1, RGB(GetRValue(data), GetGValue(data), GetBValue(data)));
+
+ SkinCalcFrameWidth();
+
+ GetPrivateProfileString(_T("Global"), _T("FontColor"), _T("None"), buffer, 20, m_tszFileName);
+ if (_tcscmp(buffer, _T("None")))
+ CSkin::m_DefaultFontColor = HexStringToLong(buffer);
+ else
+ CSkin::m_DefaultFontColor = GetSysColor(COLOR_BTNTEXT);
+ buffer[499] = 0;
+ free(szSections);
+
+ LoadItems();
+ ::FreeTabConfig();
+ ::ReloadTabConfig();
+ }
+ }
+}
+
+#define SECT_BUFFER_SIZE 2500
+
+/**
+ * Load additional skin items (like image items, buttons, icons etc.)
+ * This is called AFTER ReadItems() has read the basic skin items
+ */
+void CSkin::LoadItems()
+{
+ TCHAR *szSections = NULL;
+ TCHAR *p, *p1;
+ TIconDesc tmpIconDesc = {0};
+
+ CImageItem *pItem = m_ImageItems;
+
+ if (m_skinIcons == NULL)
+ m_skinIcons = (TIconDescW *)malloc(sizeof(TIconDescW) * NR_MAXSKINICONS);
+
+ ZeroMemory(m_skinIcons, sizeof(TIconDesc) * NR_MAXSKINICONS);
+ m_nrSkinIcons = 0;
+
+ szSections = (TCHAR *)malloc((SECT_BUFFER_SIZE + 2) * sizeof(TCHAR));
+ ZeroMemory(szSections, (SECT_BUFFER_SIZE + 2) * sizeof(TCHAR));
+
+ GetPrivateProfileSection(_T("Icons"), szSections, SECT_BUFFER_SIZE, m_tszFileName);
+ szSections[SECT_BUFFER_SIZE] = 0;
+
+ p = szSections;
+ while (lstrlen(p) > 1) {
+ p1 = _tcschr(p, (int)'=');
+ if (p1)
+ *p1 = 0;
+ if (m_nrSkinIcons < NR_MAXSKINICONS && p1) {
+ LoadIcon(_T("Icons"), p, (HICON *)&tmpIconDesc.uId);
+ if (tmpIconDesc.uId) {
+ ZeroMemory(&m_skinIcons[m_nrSkinIcons], sizeof(TIconDesc));
+ m_skinIcons[m_nrSkinIcons].uId = tmpIconDesc.uId;
+ m_skinIcons[m_nrSkinIcons].phIcon = (HICON *)(&m_skinIcons[m_nrSkinIcons].uId);
+ m_skinIcons[m_nrSkinIcons].szName = (TCHAR *)malloc(sizeof(TCHAR) * (lstrlen(p) + 1));
+ lstrcpy(m_skinIcons[m_nrSkinIcons].szName, p);
+ m_nrSkinIcons++;
+ }
+ }
+ if (p1)
+ *p1 = '=';
+ p += (lstrlen(p) + 1);
+ }
+
+ ZeroMemory(szSections, (SECT_BUFFER_SIZE + 2) * sizeof(TCHAR));
+ GetPrivateProfileSectionNames(szSections, SECT_BUFFER_SIZE, m_tszFileName);
+ szSections[SECT_BUFFER_SIZE] = 0;
+
+ p = szSections;
+ while (lstrlen(p) > 1) {
+ if (p[0] == '$')
+ ReadImageItem(p);
+ p += (lstrlen(p) + 1);
+ }
+ nextButtonID = IDC_TBFIRSTUID;
+
+ p = szSections;
+ /*
+ while (lstrlen(p) > 1) {
+ if (p[0] == '!')
+ ReadButtonItem(p);
+ p += (lstrlen(p) + 1);
+ }
+ */
+ free(szSections);
+ g_ButtonSet.top = GetPrivateProfileInt(_T("ButtonArea"), _T("top"), 0, m_tszFileName);
+ g_ButtonSet.bottom = GetPrivateProfileInt(_T("ButtonArea"), _T("bottom"), 0, m_tszFileName);
+ g_ButtonSet.left = GetPrivateProfileInt(_T("ButtonArea"), _T("left"), 0, m_tszFileName);
+ g_ButtonSet.right = GetPrivateProfileInt(_T("ButtonArea"), _T("right"), 0, m_tszFileName);
+}
+
+/**
+ * setup and cache the bitmap for the close button on tabs and switch bar
+ * buttons.
+ * re-created when:
+ * ) theme changes
+ * ) icons change (via ico lib service)
+ *
+ * @param fDeleteOnly: only delete GDI resources (this is ONLY used at plugin shutdown)
+ */
+void CSkin::setupTabCloseBitmap(bool fDeleteOnly)
+{
+ if(m_tabCloseHDC || fDeleteOnly) {
+ if(m_tabCloseHDC) {
+ ::SelectObject(m_tabCloseHDC, m_tabCloseOldBitmap);
+ ::DeleteObject(m_tabCloseBitmap);
+ ::DeleteDC(m_tabCloseHDC);
+ }
+ if(fDeleteOnly)
+ return;
+ }
+
+ bool fFree = false;
+ RECT rc = {0, 0, 20, 20};
+ HDC dc = ::GetDC(PluginConfig.g_hwndHotkeyHandler);
+ m_tabCloseHDC = ::CreateCompatibleDC(dc);
+
+ if(M->isAero())
+ m_tabCloseBitmap = CreateAeroCompatibleBitmap(rc, m_tabCloseHDC);
+ else
+ m_tabCloseBitmap = ::CreateCompatibleBitmap(dc, 20, 20);
+
+ m_tabCloseOldBitmap = reinterpret_cast<HBITMAP>(::SelectObject(m_tabCloseHDC, m_tabCloseBitmap));
+
+ if(M->isVSThemed() || M->isAero()) {
+ ::FillRect(m_tabCloseHDC, &rc, M->isAero() ? reinterpret_cast<HBRUSH>(::GetStockObject(BLACK_BRUSH)) : ::GetSysColorBrush(COLOR_3DFACE));
+
+ HANDLE hTheme = CMimAPI::m_pfnOpenThemeData(PluginConfig.g_hwndHotkeyHandler, L"BUTTON");
+ rc.left--; rc.right++;
+ rc.top--; rc.bottom++;
+ CMimAPI::m_pfnDrawThemeParentBackground(PluginConfig.g_hwndHotkeyHandler, m_tabCloseHDC, &rc);
+ CMimAPI::m_pfnDrawThemeBackground(hTheme, m_tabCloseHDC, 1, 1, &rc, &rc);
+ CMimAPI::m_pfnCloseThemeData(hTheme);
+ }
+ else if(CSkin::m_skinEnabled)
+ CSkin::DrawItem(m_tabCloseHDC, &rc, &SkinItems[ID_EXTBKBUTTONSNPRESSED]);
+ else {
+ ::FillRect(m_tabCloseHDC, &rc, ::GetSysColorBrush(COLOR_3DFACE));
+ ::DrawFrameControl(m_tabCloseHDC, &rc, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_MONO);
+ }
+ ::DrawIconEx(m_tabCloseHDC, 2, 2, PluginConfig.g_buttonBarIcons[ICON_BUTTON_CANCEL], 16, 16, 0, 0, DI_NORMAL);
+ ::SelectObject(m_tabCloseHDC, m_tabCloseOldBitmap);
+
+ HBITMAP hbmTemp = ResizeBitmap(m_tabCloseBitmap, 16, 16, fFree);
+ ::DeleteObject(m_tabCloseBitmap);
+ m_tabCloseBitmap = hbmTemp;
+ CImageItem::PreMultiply(m_tabCloseBitmap, 1);
+ m_tabCloseOldBitmap = reinterpret_cast<HBITMAP>(::SelectObject(m_tabCloseHDC, m_tabCloseBitmap));
+
+ ::ReleaseDC(PluginConfig.g_hwndHotkeyHandler, dc);
+}
+/**
+ * load and setup some images which are used to draw tabs in aero mode
+ * there is one image for tabs (it is flipped vertically for bottom tabs)
+ * and one image for the glowing effect on tabs (also flipped for bottom
+ * tabs).
+ *
+ * support for custom images added 3.0.0.34
+ * user can place images with a custom_ prefix into the images folder and
+ * they will be loaded instead the default ones.
+ *
+ * the 3rd image acts as background for switch bar buttons
+ *
+ * this is executed when:
+ * ) dwm mode changes
+ * ) aero effect is changed by the user
+ * ) glow colorization is changed by user's request
+ */
+void CSkin::setupAeroSkins()
+{
+ TCHAR tszFilename[MAX_PATH], tszBasePath[MAX_PATH];
+
+ M->getAeroState();
+ UnloadAeroTabs();
+
+ BOOL isOpaque;
+ HBITMAP hbm;
+ BITMAP bm;
+
+ if(!m_fAeroSkinsValid)
+ return;
+
+ mir_sntprintf(tszBasePath, MAX_PATH, _T("%s"), M->getDataPath());
+ if(tszBasePath[lstrlen(tszBasePath) - 1] != '\\')
+ _tcscat(tszBasePath, _T("\\"));
+
+ /*
+ * load unknown avatar..
+ */
+ if(0 == PluginConfig.g_hbmUnknown) {
+ mir_sntprintf(tszFilename, MAX_PATH, _T("%scustom_unknown.png"), tszBasePath);
+ if(!PathFileExists(tszFilename))
+ mir_sntprintf(tszFilename, MAX_PATH, _T("%sunknown.png"), tszBasePath);
+ PluginConfig.g_hbmUnknown = (HBITMAP)CallService(MS_IMG_LOAD, (WPARAM)tszFilename, IMGL_TCHAR);
+ if (PluginConfig.g_hbmUnknown == 0) {
+ HDC dc = GetDC(0);
+ PluginConfig.g_hbmUnknown = CreateCompatibleBitmap(dc, 20, 20);
+ ReleaseDC(0, dc);
+ }
+ }
+
+ mir_sntprintf(tszFilename, MAX_PATH, _T("%scustom_tabskin_aero.png"), tszBasePath);
+ if(!PathFileExists(tszFilename))
+ mir_sntprintf(tszFilename, MAX_PATH, _T("%stabskin_aero.png"), tszBasePath);
+
+ if(CMimAPI::m_pfnDwmGetColorizationColor && M->isAero())
+ CMimAPI::m_pfnDwmGetColorizationColor(&m_dwmColor, &isOpaque);
+ else
+ m_dwmColor = PluginConfig.m_fillColor;
+
+ float fr = (float)((m_dwmColor & 0x00ff0000) >> 16);
+ float fg = (float)((m_dwmColor & 0x0000ff00) >> 8);
+ float fb = (float)((m_dwmColor & 0x000000ff));
+ BYTE alphafactor = 255 - ((m_dwmColor & 0xff000000) >> 24);
+
+ /*
+ * a bit tricky, because for low alpha settings (high DWM transparency), the dwm
+ * color is almost dark gray, so we need to intensify the strongest color a bit more than
+ * the others. This will give us a good match for the dwm color that can be used
+ * to render non transparent stuff (i.e. the tool bar).
+ *
+ * TODO: this isn't perfect yet, for some colors, the result is a bit off...
+ */
+
+ if(!isOpaque && alphafactor > 150 && !(fr == fg && fg == fb)) {
+ float fmax = max(max(fr,fg), fb);
+
+ if(fmax == fr) {
+ fr *= (alphafactor / 100 * 2.2);
+ fr = min(fr, 255);
+ fb = min(fb * alphafactor / 100, 255);
+ fg = min(fg * alphafactor / 100, 255);
+ } else if(fmax == fg) {
+ fg *= (alphafactor / 100 * 2.2);
+ fg = min(fg, 255);
+ fr = min(fr * alphafactor / 100, 255);
+ fb = min(fb * alphafactor / 100, 255);
+ } else {
+ fb *= (alphafactor / 100 * 2.2);
+ fb = min(fb, 255);
+ fr = min(fr * alphafactor / 100, 255);
+ fg = min(fg * alphafactor / 100, 255);
+ }
+ }
+
+ m_dwmColorRGB = RGB((BYTE)fr, (BYTE)fg, (BYTE)fb);
+
+ FIBITMAP *fib = (FIBITMAP *)CallService(MS_IMG_LOAD, (WPARAM)tszFilename, IMGL_TCHAR | IMGL_RETURNDIB);
+
+ hbm = FIF->FI_CreateHBITMAPFromDIB(fib);
+
+ CImageItem::Colorize(hbm, GetRValue(m_dwmColorRGB),
+ GetGValue(m_dwmColorRGB),
+ GetBValue(m_dwmColorRGB));
+
+ CImageItem::PreMultiply(hbm, 1);
+
+ GetObject(hbm, sizeof(bm), &bm);
+ m_tabTop = new CImageItem(4, 4, 4, 4, 0, hbm, IMAGE_FLAG_DIVIDED | IMAGE_PERPIXEL_ALPHA,
+ 0, 255, 30, 80, 50, 100);
+
+ m_tabTop->setAlphaFormat(AC_SRC_ALPHA, 255);
+ m_tabTop->setMetrics(bm.bmWidth, bm.bmHeight);
+
+
+ /*
+ * created inverted bitmap for bottom tabs
+ */
+
+ FIF->FI_FlipVertical(fib);
+
+ hbm = FIF->FI_CreateHBITMAPFromDIB(fib);
+
+ CImageItem::Colorize(hbm, GetRValue(m_dwmColorRGB),
+ GetGValue(m_dwmColorRGB),
+ GetBValue(m_dwmColorRGB));
+
+ CImageItem::PreMultiply(hbm, 1);
+ FIF->FI_Unload(fib);
+
+ GetObject(hbm, sizeof(bm), &bm);
+ m_tabBottom = new CImageItem(4, 4, 4, 4, 0, hbm, IMAGE_FLAG_DIVIDED | IMAGE_PERPIXEL_ALPHA,
+ 0, 255, 30, 80, 50, 100);
+
+ m_tabBottom->setAlphaFormat(AC_SRC_ALPHA, 255);
+ m_tabBottom->setMetrics(bm.bmWidth, bm.bmHeight);
+
+
+ mir_sntprintf(tszFilename, MAX_PATH, _T("%scustom_tabskin_aero_glow.png"), tszBasePath);
+ if(!PathFileExists(tszFilename))
+ mir_sntprintf(tszFilename, MAX_PATH, _T("%stabskin_aero_glow.png"), tszBasePath);
+
+ fib = (FIBITMAP *)CallService(MS_IMG_LOAD, (WPARAM)tszFilename, IMGL_TCHAR | IMGL_RETURNDIB);
+
+ COLORREF glowColor = M->GetDword(FONTMODULE, "aeroGlow", RGB(40, 40, 255));
+ hbm = FIF->FI_CreateHBITMAPFromDIB(fib);
+ CImageItem::Colorize(hbm, GetRValue(glowColor), GetGValue(glowColor), GetBValue(glowColor));
+ CImageItem::PreMultiply(hbm, 1);
+
+ GetObject(hbm, sizeof(bm), &bm);
+ m_tabGlowTop = new CImageItem(4, 4, 4, 4, 0, hbm, IMAGE_FLAG_DIVIDED | IMAGE_PERPIXEL_ALPHA,
+ 0, 255, 30, 80, 50, 100);
+
+ m_tabGlowTop->setAlphaFormat(AC_SRC_ALPHA, 255);
+ m_tabGlowTop->setMetrics(bm.bmWidth, bm.bmHeight);
+
+ FIF->FI_FlipVertical(fib);
+
+ hbm = FIF->FI_CreateHBITMAPFromDIB(fib);
+ CImageItem::Colorize(hbm, GetRValue(glowColor), GetGValue(glowColor), GetBValue(glowColor));
+ CImageItem::PreMultiply(hbm, 1);
+ FIF->FI_Unload(fib);
+
+ GetObject(hbm, sizeof(bm), &bm);
+ m_tabGlowBottom = new CImageItem(4, 4, 4, 4, 0, hbm, IMAGE_FLAG_DIVIDED | IMAGE_PERPIXEL_ALPHA,
+ 0, 255, 30, 80, 50, 100);
+
+ m_tabGlowBottom->setAlphaFormat(AC_SRC_ALPHA, 255);
+ m_tabGlowBottom->setMetrics(bm.bmWidth, bm.bmHeight);
+
+ /*
+ * background item for the button switch bar
+ */
+ mir_sntprintf(tszFilename, MAX_PATH, _T("%scustom_tabskin_aero_button.png"), tszBasePath);
+ if(!PathFileExists(tszFilename))
+ mir_sntprintf(tszFilename, MAX_PATH, _T("%stabskin_aero_button.png"), tszBasePath);
+
+ hbm = (HBITMAP)CallService(MS_IMG_LOAD, (WPARAM)tszFilename, IMGL_TCHAR);
+
+ CImageItem::Colorize(hbm, GetRValue(m_dwmColorRGB),
+ GetGValue(m_dwmColorRGB),
+ GetBValue(m_dwmColorRGB));
+
+ CImageItem::PreMultiply(hbm, 1);
+
+ GetObject(hbm, sizeof(bm), &bm);
+
+ m_switchBarItem = new CImageItem(4, 4, 4, 4, 0, hbm, IMAGE_FLAG_DIVIDED | IMAGE_PERPIXEL_ALPHA,
+ 0, 255, 2, 12, 10, 20);
+
+ m_switchBarItem->setAlphaFormat(AC_SRC_ALPHA, 255);
+ m_switchBarItem->setMetrics(bm.bmWidth, bm.bmHeight);
+}
+
+/**
+ * Calculate window frame borders for a skin with the ability to paint the window frame.
+ * Uses system metrics to determine predefined window borders and caption bar size.
+ */
+void CSkin::SkinCalcFrameWidth()
+{
+ int xBorder, yBorder, yCaption;
+
+ xBorder = GetSystemMetrics(SM_CXSIZEFRAME);
+ yBorder = GetSystemMetrics(SM_CYSIZEFRAME);
+ yCaption = GetSystemMetrics(SM_CYCAPTION);
+
+ m_realSkinnedFrame_left = m_SkinnedFrame_left - xBorder;
+ m_realSkinnedFrame_right = m_SkinnedFrame_right - xBorder;
+ m_realSkinnedFrame_bottom = m_SkinnedFrame_bottom - yBorder;
+ m_realSkinnedFrame_caption = m_SkinnedFrame_caption - yCaption;
+}
+
+
+/**
+ * Draws part of the background to the foreground control
+ *
+ * @param hwndClient HWND: target window
+ * @param hwnd HWND: source window (usually the parent, needed for transforming client coordinates
+ * @param pContainer ContainerWindowData *: needed to access the cached DC of the container window
+ * @param rcClient RECT *: client rectangle (target area)
+ * @param hdcTarget HDC: device context of the target window
+ */
+void CSkin::SkinDrawBG(HWND hwndClient, HWND hwnd, struct TContainerData *pContainer, RECT *rcClient, HDC hdcTarget)
+{
+ RECT rcWindow;
+ POINT pt;
+ LONG width = rcClient->right - rcClient->left;
+ LONG height = rcClient->bottom - rcClient->top;
+ HDC dc;
+
+ ::GetWindowRect(hwndClient, &rcWindow);
+ pt.x = rcWindow.left + rcClient->left;
+ pt.y = rcWindow.top + rcClient->top;
+ ::ScreenToClient(hwnd, &pt);
+ if (pContainer)
+ dc = pContainer->cachedDC;
+ else
+ dc = ::GetDC(hwnd);
+ pt.y = max(pt.y, 0);
+ ::BitBlt(hdcTarget, rcClient->left, rcClient->top, width, height, dc, pt.x, pt.y, SRCCOPY);
+ if (!pContainer)
+ ::ReleaseDC(hwnd, dc);
+}
+
+/**
+ * Draws part of the background to the foreground control
+ * same as above, but can use any source DC, not just the
+ * container
+ *
+ * @param hwndClient HWND: target window
+ * @param hwnd HWND: source window (usually the parent, needed for transforming client coordinates
+ * @param pContainer ContainerWindowData *: needed to access the cached DC of the container window
+ * @param rcClient RECT *: client rectangle (target area)
+ * @param hdcTarget HDC: device context of the target window
+ */
+
+void CSkin::SkinDrawBGFromDC(HWND hwndClient, HWND hwnd, RECT *rcClient, HDC hdcTarget)
+{
+ RECT rcWindow;
+ POINT pt;
+ LONG width = rcClient->right - rcClient->left;
+ LONG height = rcClient->bottom - rcClient->top;
+ HDC hdcSrc = ::GetDC(hwnd);
+
+ ::GetWindowRect(hwndClient, &rcWindow);
+ pt.x = rcWindow.left + rcClient->left;
+ pt.y = rcWindow.top + rcClient->top;
+ ::ScreenToClient(hwnd, &pt);
+ ::StretchBlt(hdcTarget, rcClient->left, rcClient->top, width, height, hdcSrc, pt.x, pt.y, width, height, SRCCOPY | CAPTUREBLT);
+ ::ReleaseDC(hwnd, hdcSrc);
+}
+
+/**
+ * draw transparent avatar image. Get around crappy image rescaling quality of the
+ * AlphaBlend() API.
+ *
+ * hdcMem contains the bitmap to draw (must be premultiplied for proper per-pixel alpha
+ * rendering in AlphaBlend().
+ */
+
+void CSkin::MY_AlphaBlend(HDC hdcDraw, DWORD left, DWORD top, int width, int height, int bmWidth, int bmHeight, HDC hdcMem)
+{
+ HDC hdcTemp = CreateCompatibleDC(hdcDraw);
+ HBITMAP hbmTemp = CreateCompatibleBitmap(hdcMem, bmWidth, bmHeight);
+ HBITMAP hbmOld = (HBITMAP)SelectObject(hdcTemp, hbmTemp);
+
+ SetStretchBltMode(hdcTemp, HALFTONE);
+ StretchBlt(hdcTemp, 0, 0, bmWidth, bmHeight, hdcDraw, left, top, width, height, SRCCOPY);
+ if (CMimAPI::m_MyAlphaBlend)
+ CMimAPI::m_MyAlphaBlend(hdcTemp, 0, 0, bmWidth, bmHeight, hdcMem, 0, 0, bmWidth, bmHeight, CSkin::m_default_bf);
+ else {
+ SetStretchBltMode(hdcTemp, HALFTONE);
+ StretchBlt(hdcTemp, 0, 0, bmWidth, bmHeight, hdcMem, 0, 0, bmWidth, bmHeight, SRCCOPY);
+ }
+ StretchBlt(hdcDraw, left, top, width, height, hdcTemp, 0, 0, bmWidth, bmHeight, SRCCOPY);
+ SelectObject(hdcTemp, hbmOld);
+ DeleteObject(hbmTemp);
+ DeleteDC(hdcTemp);
+}
+
+/**
+ * draw an icon "dimmed" (small amount of transparency applied)
+*/
+
+void CSkin::DrawDimmedIcon(HDC hdc, LONG left, LONG top, LONG dx, LONG dy, HICON hIcon, BYTE alpha)
+{
+ HDC dcMem = ::CreateCompatibleDC(hdc);
+ HBITMAP hbm = ::CreateCompatibleBitmap(hdc, dx, dy), hbmOld = 0;
+
+ hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(dcMem, hbm));
+ ::DrawIconEx(dcMem, 0, 0, hIcon, dx, dy, 0, 0, DI_NORMAL);
+ m_default_bf.SourceConstantAlpha = alpha;
+ if (CMimAPI::m_MyAlphaBlend) {
+ HBITMAP hbm = (HBITMAP)SelectObject(dcMem, hbmOld);
+ CImageItem::PreMultiply(hbm, 1); // for AlphaBlend()...
+ hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(dcMem, hbm));
+ CMimAPI::m_MyAlphaBlend(hdc, left, top, dx, dy, dcMem, 0, 0, dx, dy, m_default_bf);
+ }
+ else {
+ SetStretchBltMode(hdc, HALFTONE);
+ StretchBlt(hdc, left, top, dx, dy, dcMem, 0, 0, dx, dy, SRCCOPY);
+ }
+ m_default_bf.SourceConstantAlpha = 255;
+ SelectObject(dcMem, hbmOld);
+ DeleteObject(hbm);
+ DeleteDC(dcMem);
+}
+
+UINT CSkin::NcCalcRichEditFrame(HWND hwnd, const TWindowData *mwdat, UINT skinID, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC OldWndProc)
+{
+ LRESULT orig = 0;
+ NCCALCSIZE_PARAMS *nccp = (NCCALCSIZE_PARAMS *)lParam;
+ BOOL bReturn = FALSE;
+
+ if (CSkin::m_DisableScrollbars) {
+ SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_VSCROLL);
+ EnableScrollBar(hwnd, SB_VERT, ESB_DISABLE_BOTH);
+ ShowScrollBar(hwnd, SB_VERT, FALSE);
+ }
+ if(OldWndProc)
+ orig = CallWindowProc(OldWndProc, hwnd, msg, wParam, lParam);
+
+ if(0 == mwdat)
+ return(orig);
+
+ if (CSkin::m_skinEnabled) {
+ CSkinItem *item = &SkinItems[skinID];
+ if (!item->IGNORED)
+ return WVR_REDRAW;
+ }
+ if (mwdat->hTheme && wParam && CMimAPI::m_pfnGetThemeBackgroundContentRect) {
+ RECT rcClient;
+ HDC hdc = GetDC(GetParent(hwnd));
+
+ if (CMimAPI::m_pfnGetThemeBackgroundContentRect(mwdat->hTheme, hdc, 1, 1, &nccp->rgrc[0], &rcClient) == S_OK) {
+ if (EqualRect(&rcClient, &nccp->rgrc[0]))
+ InflateRect(&rcClient, -1, -1);
+ CopyRect(&nccp->rgrc[0], &rcClient);
+ bReturn = TRUE;
+ }
+ ReleaseDC(GetParent(hwnd), hdc);
+ if (bReturn)
+ return WVR_REDRAW;
+ else
+ return orig;
+ }
+ if ((mwdat->sendMode & SMODE_MULTIPLE || mwdat->sendMode & SMODE_CONTAINER ||
+ mwdat->fEditNotesActive || mwdat->sendMode & SMODE_SENDLATER) && skinID == ID_EXTBKINPUTAREA) {
+ InflateRect(&nccp->rgrc[0], -1, -1);
+ return WVR_REDRAW;
+ }
+ return orig;
+}
+
+/*
+ * process WM_NCPAINT for the rich edit control. Draw a visual style border and avoid classic static edge / client edge
+ * may also draw a colorized border around the control
+ */
+
+UINT CSkin::DrawRichEditFrame(HWND hwnd, const TWindowData *mwdat, UINT skinID, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC OldWndProc)
+{
+ CSkinItem *item = &SkinItems[skinID];
+ LRESULT result = 0;
+
+ if(OldWndProc)
+ result = CallWindowProc(OldWndProc, hwnd, msg, wParam, lParam); // do default processing (otherwise, NO scrollbar as it is painted in NC_PAINT)
+
+ if (0 == mwdat)
+ return result;
+
+ BOOL isEditNotesReason = ((mwdat->fEditNotesActive) && (skinID == ID_EXTBKINPUTAREA));
+ BOOL isSendLaterReason = ((mwdat->sendMode & SMODE_SENDLATER) && (skinID == ID_EXTBKINPUTAREA));
+ BOOL isMultipleReason = ((skinID == ID_EXTBKINPUTAREA) && (mwdat->sendMode & SMODE_MULTIPLE || mwdat->sendMode & SMODE_CONTAINER));
+
+ HDC hdc = GetWindowDC(hwnd);
+ RECT rcWindow;
+ POINT pt;
+ LONG left_off, top_off, right_off, bottom_off;
+ LONG dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ LONG dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
+
+ GetWindowRect(hwnd, &rcWindow);
+ pt.x = pt.y = 0;
+ ClientToScreen(hwnd, &pt);
+ left_off = pt.x - rcWindow.left;
+ if (dwStyle & WS_VSCROLL && dwExStyle & WS_EX_RTLREADING)
+ left_off -= PluginConfig.m_ncm.iScrollWidth;
+ top_off = pt.y - rcWindow.top;
+
+ if (CSkin::m_skinEnabled && !item->IGNORED) {
+ right_off = item->MARGIN_RIGHT;
+ bottom_off = item->MARGIN_BOTTOM;
+ } else {
+ right_off = left_off;
+ bottom_off = top_off;
+ }
+
+ rcWindow.right -= rcWindow.left;
+ rcWindow.bottom -= rcWindow.top;
+ rcWindow.left = rcWindow.top = 0;
+
+ ExcludeClipRect(hdc, left_off, top_off, rcWindow.right - right_off, rcWindow.bottom - bottom_off);
+ if (CSkin::m_skinEnabled && !item->IGNORED) {
+ ReleaseDC(hwnd, hdc);
+ return result;
+ } else if (CMimAPI::m_pfnDrawThemeBackground) {
+ if (isMultipleReason || isEditNotesReason || isSendLaterReason) {
+ HBRUSH br = CreateSolidBrush(isMultipleReason ? RGB(255, 130, 130) : (isEditNotesReason ? RGB(80, 255, 80) : RGB(80, 80, 255)));
+ FillRect(hdc, &rcWindow, br);
+ DeleteObject(br);
+ } else {
+ if(PluginConfig.m_cRichBorders) {
+ HBRUSH br = CreateSolidBrush(PluginConfig.m_cRichBorders);
+ FillRect(hdc, &rcWindow, br);
+ DeleteObject(br);
+ }
+ else
+ CMimAPI::m_pfnDrawThemeBackground(mwdat->hTheme, hdc, 1, 1, &rcWindow, &rcWindow);
+ }
+ }
+ else {
+ HBRUSH br = CreateSolidBrush(PluginConfig.m_cRichBorders ? PluginConfig.m_cRichBorders : ::GetSysColor(COLOR_3DSHADOW));
+ FillRect(hdc, &rcWindow, br);
+ DeleteObject(br);
+ }
+ ReleaseDC(hwnd, hdc);
+ return result;
+}
+
+/**
+ * convert a html-style color string (without the #) to a 32bit COLORREF value
+ *
+ * @param szSource TCHAR*: the color value as string. format:
+ * html-style without the leading #. e.g.
+ * "f3e355"
+ *
+ * @return COLORREF representation of the string value.
+ */
+DWORD __fastcall CSkin::HexStringToLong(const TCHAR *szSource)
+{
+ TCHAR *stopped;
+ COLORREF clr = _tcstol(szSource, &stopped, 16);
+ if (clr == -1)
+ return clr;
+ return(RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)));
+}
+
+/**
+ * Render text to the given HDC. This function is aero aware and will use uxtheme DrawThemeTextEx() when needed.
+ * Paramaters are pretty much comparable to GDI DrawText() API
+ *
+ * @return
+ */
+
+int CSkin::RenderText(HDC hdc, HANDLE hTheme, const TCHAR *szText, RECT *rc, DWORD dtFlags, const int iGlowSize, COLORREF clr, bool fForceAero)
+{
+ if((PluginConfig.m_bIsVista && !CSkin::m_skinEnabled && hTheme) || fForceAero) {
+ DTTOPTS dto = {0};
+ dto.dwSize = sizeof(dto);
+ if(iGlowSize && (M->isAero() || fForceAero)) {
+ dto.iGlowSize = iGlowSize;
+ dto.dwFlags = DTT_COMPOSITED|DTT_GLOWSIZE;
+ }
+ else {
+ dto.dwFlags = DTT_TEXTCOLOR|DTT_COMPOSITED;//|DTT_SHADOWTYPE|DTT_SHADOWOFFSET|DTT_SHADOWCOLOR|DTT_BORDERSIZE|DTT_BORDERCOLOR;
+ dto.crText = clr;
+ }
+ dto.iBorderSize = 10;
+ return(CMimAPI::m_pfnDrawThemeTextEx(hTheme, hdc, BP_PUSHBUTTON, PBS_NORMAL, szText, -1, dtFlags, rc, &dto));
+ }
+ else {
+ ::SetTextColor(hdc, clr);
+ return(::DrawText(hdc, szText, -1, rc, dtFlags));
+ }
+}
+
+/**
+ * Resize a bitmap using image service. The function does not care about the image aspect ratio.
+ * The caller is responsible to submit proper values for the desired height and width.
+ *
+ * @param hBmpSrc HBITMAP: the source bitmap
+ * @param width LONG: width of the destination bitmap
+ * @param height LONG: height of the new bitmap
+ * @param mustFree bool: indicates that the new bitmap had been
+ * resized and either the source or destination
+ * bitmap should be freed.
+ *
+ * @return HBTIAMP: handle to a bitmap with the desired size.
+ */
+HBITMAP CSkin::ResizeBitmap(HBITMAP hBmpSrc, LONG width, LONG height, bool &mustFree)
+{
+ BITMAP bm;
+
+ GetObject(hBmpSrc, sizeof(bm), &bm);
+ if(bm.bmHeight != height || bm.bmWidth != width) {
+ ::ResizeBitmap rb;
+ rb.size = sizeof(rb);
+ rb.fit = RESIZEBITMAP_STRETCH;
+ rb.max_height = height;
+ rb.max_width = width;
+ rb.hBmp = hBmpSrc;
+
+ HBITMAP hbmNew = (HBITMAP)CallService("IMG/ResizeBitmap", (WPARAM)&rb, 0);
+ if(hbmNew != hBmpSrc)
+ mustFree = true;
+ return(hbmNew);
+ }
+ else {
+ mustFree = false;
+ return(hBmpSrc);
+ }
+}
+
+/**
+ * Draw the given skin item to the target rectangle and dc
+ *
+ * @param hdc HDC: device context
+ * @param rc RECT: target rectangle
+ * @param item CSkinItem*: fully initialiized skin item
+ *
+ * @return bool: true if the item has been painted, false if not
+ * (only reason: the ignore flag in the item is set).
+ */
+bool __fastcall CSkin::DrawItem(const HDC hdc, const RECT *rc, const CSkinItem *item)
+{
+ if(!item->IGNORED) {
+ ::DrawAlpha(hdc, const_cast<RECT *>(rc), item->COLOR, item->ALPHA, item->COLOR2, item->COLOR2_TRANSPARENT,
+ item->GRADIENT, item->CORNER, item->BORDERSTYLE, item->imageItem);
+ return(true);
+ }
+ return(false);
+}
+
+/**
+ * Create a 32bit RGBA bitmap, compatible for rendering with alpha channel.
+ * Required by anything which would render on a transparent aero surface.
+ * the image is a "bottom up" bitmap, as it has a negative
+ * height. This is a requirement for some UxTheme APIs (e.g.
+ * DrawThemeTextEx).
+ *
+ * @param rc RECT &: the rectangle describing the target area.
+ * @param dc The device context for which the bitmap should be created.
+ *
+ * @return HBITMAP: handle to the bitmap created.
+ */
+HBITMAP CSkin::CreateAeroCompatibleBitmap(const RECT &rc, HDC dc)
+{
+ BITMAPINFO dib = {0};
+
+ dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ dib.bmiHeader.biWidth = rc.right - rc.left;
+ dib.bmiHeader.biHeight = -(rc.bottom - rc.top);
+ dib.bmiHeader.biPlanes = 1;
+ dib.bmiHeader.biBitCount = 32;
+ dib.bmiHeader.biCompression = BI_RGB;
+
+ return(CreateDIBSection(dc, &dib, DIB_RGB_COLORS, NULL, NULL, 0 ));
+}
+
+/**
+ * Map a given rectangle within the window, specified by hwndClient
+ * to the client area of another window.
+ *
+ * @param hwndClient HWND: Client window
+ * @param hwndParent HWND: The window to which the coordinates should be mapped
+ * @param rc RECT &: Rectangular area within the client area of hwndClient.
+ *
+ * It will receive the transformed coordinates, relative to the client area of hwndParent
+ */
+void CSkin::MapClientToParent(HWND hwndClient, HWND hwndParent, RECT &rc)
+{
+ POINT pt;
+
+ LONG cx = rc.right - rc.left;
+ LONG cy = rc.bottom - rc.top;
+ pt.x = rc.left; pt.y = rc.top;
+
+ ::ClientToScreen(hwndClient, &pt);
+ ::ScreenToClient(hwndParent, &pt);
+
+ rc.top = pt.y;
+ rc.left = pt.x;
+ rc.right = rc.left + cx;
+ rc.bottom = rc.top + cy;
+}
+
+/**
+ * Draw the background for the message window tool bar
+ *
+ * @param dat _MessageWindowData *: structure describing the message session
+ *
+ * @param hdc HDC: handle to the device context in which painting should occur.
+ * @param rcWindow RECT &: The window rectangle of the message dialog window
+ */
+void CSkin::RenderToolbarBG(const TWindowData *dat, HDC hdc, const RECT &rcWindow)
+{
+ if(dat) {
+ if(dat->pContainer->dwFlags & CNT_HIDETOOLBAR)
+ return;
+
+ bool fAero = M->isAero();
+ bool fTbColorsValid = PluginConfig.m_tbBackgroundHigh && PluginConfig.m_tbBackgroundLow;
+ BYTE bAlphaOffset = 0;
+ BOOL fMustDrawNonThemed = ((fAero || fTbColorsValid) && !M->GetByte(SRMSGMOD_T, "forceThemedToolbar", 0));
+ RECT rc, rcToolbar;;
+ POINT pt;
+
+ if(!(dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR)) {
+ ::GetWindowRect(::GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_CHAT ? IDC_CHAT_LOG : IDC_LOG), &rc);
+ pt.y = rc.bottom + 0;
+ ::ScreenToClient(dat->hwnd, &pt);
+ rcToolbar.top = pt.y;
+ rcToolbar.left = 0;
+ rcToolbar.right = rcWindow.right;
+
+ if(dat->bType == SESSIONTYPE_IM) {
+ if(dat->dwFlags & MWF_ERRORSTATE)
+ rcToolbar.top += ERRORPANEL_HEIGHT;
+ if(dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED || dat->bNotOnList) {
+ rcToolbar.top += 20;
+ RECT rcAdd;
+ rcAdd.left = 0; rcAdd.right = rcToolbar.right - rcToolbar.left;
+ rcAdd.bottom = rcToolbar.top - 1;
+ rcAdd.top = rcAdd.bottom - 20;
+ ::DrawEdge(hdc, &rcAdd, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_RECT | BF_SOFT | BF_FLAT);
+ }
+ }
+
+ ::GetWindowRect(::GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_CHAT ? IDC_CHAT_MESSAGE : IDC_MESSAGE), &rc);
+ pt.y = rc.top - (dat->fIsAutosizingInput ? 1 : 2);
+ ::ScreenToClient(dat->hwnd, &pt);
+ rcToolbar.bottom = pt.y;
+ }
+ else {
+ GetWindowRect(::GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_CHAT ? IDC_CHAT_MESSAGE : IDC_MESSAGE), &rc);
+ pt.y = rc.bottom - (dat->bType == SESSIONTYPE_IM ? 2 : 2);
+ ScreenToClient(dat->hwnd, &pt);
+ rcToolbar.top = pt.y + 1;
+ rcToolbar.left = 0;
+ rcToolbar.right = rcWindow.right;
+ rcToolbar.bottom = rcWindow.bottom;
+ }
+ LONG cx = rcToolbar.right - rcToolbar.left;
+ LONG cy = rcToolbar.bottom - rcToolbar.top;
+
+ RECT rcCachedToolbar = {0};
+ rcCachedToolbar.right = cx;
+ rcCachedToolbar.bottom = cy;
+
+ if(dat->pContainer->cachedToolbarDC == 0)
+ dat->pContainer->cachedToolbarDC = ::CreateCompatibleDC(hdc);
+
+ if(dat->pContainer->szOldToolbarSize.cx != cx || dat->pContainer->szOldToolbarSize.cy != cy) {
+ if(dat->pContainer->oldhbmToolbarBG) {
+ ::SelectObject(dat->pContainer->cachedToolbarDC, dat->pContainer->oldhbmToolbarBG);
+ ::DeleteObject(dat->pContainer->hbmToolbarBG);
+ }
+ dat->pContainer->hbmToolbarBG = CSkin::CreateAeroCompatibleBitmap(rcCachedToolbar, hdc);// ::CreateCompatibleBitmap(hdc, cx, cy);
+ dat->pContainer->oldhbmToolbarBG = reinterpret_cast<HBITMAP>(::SelectObject(dat->pContainer->cachedToolbarDC, dat->pContainer->hbmToolbarBG));
+ }
+ dat->pContainer->szOldToolbarSize.cx = cx;
+ dat->pContainer->szOldToolbarSize.cy = cy;
+
+ if(!fMustDrawNonThemed && M->isVSThemed()) {
+ CMimAPI::m_pfnDrawThemeBackground(dat->hThemeToolbar, dat->pContainer->cachedToolbarDC, 6, 1,
+ &rcCachedToolbar, &rcCachedToolbar);
+ dat->pContainer->bTBRenderingMode = 1; // tell TSButton how to render the tool bar buttons
+ }
+ else {
+ dat->pContainer->bTBRenderingMode = (M->isVSThemed() ? 1 : 0);
+ m_tmp_tb_high = PluginConfig.m_tbBackgroundHigh ? PluginConfig.m_tbBackgroundHigh :
+ ((fAero && m_pCurrentAeroEffect) ? m_pCurrentAeroEffect->m_clrToolbar : ::GetSysColor(COLOR_3DFACE));
+ m_tmp_tb_low = PluginConfig.m_tbBackgroundLow ? PluginConfig.m_tbBackgroundLow :
+ ((fAero && m_pCurrentAeroEffect) ? m_pCurrentAeroEffect->m_clrToolbar2 : ::GetSysColor(COLOR_3DFACE));
+
+ bAlphaOffset = PluginConfig.m_tbBackgroundHigh ? 40 : 0;
+ ::DrawAlpha(dat->pContainer->cachedToolbarDC, &rcCachedToolbar, m_tmp_tb_high, 55 + bAlphaOffset, m_tmp_tb_low, 0, 9, 0, 0, 0);
+ }
+
+ ::BitBlt(hdc, rcToolbar.left, rcToolbar.top, cx, cy,
+ dat->pContainer->cachedToolbarDC, 0, 0, SRCCOPY);
+ }
+}
+
+/**
+ * Initiate a buffered paint operation
+ *
+ * @param hdcSrc The source device context (usually obtained by BeginPaint())
+ * @param rc RECT&: the target rectangle that receives the painting
+ * @param hdcOut HDC& (out) receives the buffered device context handle
+ *
+ * @return
+ */
+HANDLE CSkin::InitiateBufferedPaint(const HDC hdcSrc, RECT& rc, HDC& hdcOut)
+{
+ HANDLE hbp = CMimAPI::m_pfnBeginBufferedPaint(hdcSrc, &rc, BPBF_TOPDOWNDIB, NULL, &hdcOut);
+ return(hbp);
+}
+
+/**
+ * finalize buffered paint cycle and apply (if applicable) the global alpha value
+ *
+ * @param hbp HANDLE: handle of the buffered paint context
+ * @param rc RECT*: target rectangly where alpha value should be applied
+ */
+void CSkin::FinalizeBufferedPaint(HANDLE hbp, RECT *rc)
+{
+ if(m_pCurrentAeroEffect && m_pCurrentAeroEffect->m_finalAlpha > 0)
+ CMimAPI::m_pfnBufferedPaintSetAlpha(hbp, rc, m_pCurrentAeroEffect->m_finalAlpha);
+ CMimAPI::m_pfnEndBufferedPaint(hbp, TRUE);
+}
+/**
+ * Apply an effect to a aero glass area
+ *
+ * @param hdc HDC: device context
+ * @param rc RECT*: target rectangle
+ * @param iEffectArea
+ * int: area identifier (specifies which area we are drawing, so that allows to
+ * have different effects on different areas).
+ * Area can be the status bar, info panel, menu
+ * bar etc.
+ * @param hbp HANDLE: handle to a buffered paint identifier.
+ * default is none, needed forsome special
+ * effects. default paramenter is 0
+ */
+
+void CSkin::ApplyAeroEffect(const HDC hdc, const RECT *rc, int iEffectArea, HANDLE hbp)
+{
+ if(m_pCurrentAeroEffect == 0 || m_aeroEffect == AERO_EFFECT_NONE)
+ return;
+
+ if(m_pCurrentAeroEffect->pfnEffectRenderer)
+ m_pCurrentAeroEffect->pfnEffectRenderer(hdc, rc, iEffectArea);
+}
+
+/** aero effect callbacks
+ *
+ */
+
+void CSkin::AeroEffectCallback_Milk(const HDC hdc, const RECT *rc, int iEffectArea)
+{
+ if(iEffectArea < 0x1000) {
+ int alpha = (iEffectArea == AERO_EFFECT_AREA_INFOPANEL) ? m_pCurrentAeroEffect->m_baseAlpha : 40;
+ if(iEffectArea == AERO_EFFECT_AREA_MENUBAR)
+ alpha = 90;
+ BYTE color2_trans = (iEffectArea == AERO_EFFECT_AREA_MENUBAR) ? 0 : 1;
+ DWORD corner = (iEffectArea == AERO_EFFECT_AREA_INFOPANEL) ? m_pCurrentAeroEffect->m_cornerRadius : 6;
+
+ DrawAlpha(hdc, const_cast<RECT *>(rc), m_pCurrentAeroEffect->m_baseColor, alpha, m_pCurrentAeroEffect->m_gradientColor,
+ color2_trans, m_pCurrentAeroEffect->m_gradientType, m_pCurrentAeroEffect->m_cornerType, corner, 0);
+ }
+}
+
+void CSkin::AeroEffectCallback_Carbon(const HDC hdc, const RECT *rc, int iEffectArea)
+{
+ if(iEffectArea < 0x1000)
+ DrawAlpha(hdc, const_cast<RECT *>(rc), m_pCurrentAeroEffect->m_baseColor, m_pCurrentAeroEffect->m_baseAlpha,
+ m_pCurrentAeroEffect->m_gradientColor, 0, m_pCurrentAeroEffect->m_gradientType,
+ m_pCurrentAeroEffect->m_cornerType, m_pCurrentAeroEffect->m_cornerRadius, 0);
+}
+
+void CSkin::AeroEffectCallback_Solid(const HDC hdc, const RECT *rc, int iEffectArea)
+{
+ if(iEffectArea < 0x1000) {
+ if(iEffectArea == AERO_EFFECT_AREA_SIDEBAR_LEFT)
+ ::DrawAlpha(hdc, const_cast<RECT *>(rc), m_pCurrentAeroEffect->m_baseColor, m_pCurrentAeroEffect->m_baseAlpha,
+ m_pCurrentAeroEffect->m_gradientColor, 0, GRADIENT_TB + 1,
+ 0, 2, 0);
+ else
+ ::DrawAlpha(hdc, const_cast<RECT *>(rc), m_pCurrentAeroEffect->m_baseColor, m_pCurrentAeroEffect->m_baseAlpha,
+ m_pCurrentAeroEffect->m_gradientColor, 0, m_pCurrentAeroEffect->m_gradientType,
+ m_pCurrentAeroEffect->m_cornerType, m_pCurrentAeroEffect->m_cornerRadius, 0);
+ }
+ else {
+ BYTE bGradient = (iEffectArea & AERO_EFFECT_AREA_TAB_BOTTOM ? GRADIENT_BT : GRADIENT_TB) + 1;
+ ::DrawAlpha(hdc, const_cast<RECT *>(rc), m_pCurrentAeroEffect->m_baseColor, 70,
+ m_pCurrentAeroEffect->m_gradientColor, 1, bGradient,
+ m_pCurrentAeroEffect->m_cornerType, m_pCurrentAeroEffect->m_cornerRadius, 0);
+ }
+}
+
+void CSkin::initAeroEffect()
+{
+ if(m_BrushBack) {
+ ::DeleteObject(m_BrushBack);
+ m_BrushBack = 0;
+ }
+ if(PluginConfig.m_bIsVista && m_aeroEffect > AERO_EFFECT_NONE && m_aeroEffect < AERO_EFFECT_LAST) {
+ m_currentAeroEffect = m_aeroEffects[m_aeroEffect];
+ m_pCurrentAeroEffect = &m_currentAeroEffect;
+ m_glowSize = m_pCurrentAeroEffect->m_glowSize;
+
+ if(m_pCurrentAeroEffect->m_clrToolbar == -1)
+ m_pCurrentAeroEffect->m_clrToolbar = PluginConfig.m_ipBackgroundGradientHigh;
+
+ if(m_pCurrentAeroEffect->m_clrToolbar2 == -1)
+ m_pCurrentAeroEffect->m_clrToolbar2 = PluginConfig.m_ipBackgroundGradient;
+ else if(m_pCurrentAeroEffect->m_clrToolbar2 == 0)
+ m_pCurrentAeroEffect->m_clrToolbar2 = m_dwmColorRGB;
+
+ if(m_aeroEffect == AERO_EFFECT_CUSTOM || m_aeroEffect == AERO_EFFECT_SOLID) {
+ m_pCurrentAeroEffect->m_baseColor = PluginConfig.m_ipBackgroundGradientHigh;
+ m_pCurrentAeroEffect->m_gradientColor = PluginConfig.m_ipBackgroundGradient;
+ if(m_aeroEffect == AERO_EFFECT_CUSTOM)
+ m_pCurrentAeroEffect->m_clrBack = PluginConfig.m_ipBackgroundGradientHigh;
+ }
+
+ m_BrushBack = ::CreateSolidBrush(m_pCurrentAeroEffect->m_clrBack);
+ } else {
+ m_pCurrentAeroEffect = 0;
+ m_glowSize = 10;
+ m_BrushBack = ::CreateSolidBrush(0);
+ }
+
+ TContainerData *pContainer = pFirstContainer;
+
+ while (pContainer) {
+ InvalidateRect(GetDlgItem(pContainer->hwnd, IDC_MSGTABS), NULL, TRUE);
+ InvalidateRect(pContainer->hwnd, NULL, TRUE);
+ if(IsWindow(GetDlgItem(pContainer->hwnd, 5000)))
+ InvalidateRect(GetDlgItem(pContainer->hwnd, 5000), NULL, TRUE);
+ pContainer = pContainer->pNextContainer;
+ }
+}
+
+void CSkin::setAeroEffect(LRESULT effect)
+{
+ if(effect == -1)
+ effect = static_cast<LRESULT>(M->GetDword(SRMSGMOD_T, "aerostyle", AERO_EFFECT_NONE));
+
+ if(effect >= 0 && effect < AERO_EFFECT_LAST)
+ m_aeroEffect = (UINT)effect;
+ else
+ m_aeroEffect = AERO_EFFECT_NONE;
+
+ initAeroEffect();
+ M->WriteDword(SRMSGMOD_T, "aerostyle", m_aeroEffect);
+}
+
+/**
+ * extract the aero skin images from the DLL and store them in
+ * the private data folder.
+ * runs at every startup
+ */
+void CSkin::extractSkinsAndLogo(bool fForceOverwrite) const
+{
+ TCHAR tszBasePath[MAX_PATH];
+
+ mir_sntprintf(tszBasePath, MAX_PATH, _T("%s"), M->getDataPath());
+ if(tszBasePath[lstrlen(tszBasePath) - 1] != '\\')
+ _tcscat(tszBasePath, _T("\\"));
+
+ CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)tszBasePath);
+
+ m_fAeroSkinsValid = true;
+
+ try {
+ for(int i = 0; i < safe_sizeof(my_default_skin); i++)
+ Utils::extractResource(g_hInst, my_default_skin[i].ulID, _T("SKIN_GLYPH"), tszBasePath, my_default_skin[i].tszName, fForceOverwrite);
+ }
+ catch(CRTException& ex) {
+ ex.display();
+ m_fAeroSkinsValid = false;
+ }
+}
+
+/**
+ * redraw the splitter area between the message input and message log
+ * area only
+ */
+void CSkin::UpdateToolbarBG(TWindowData* dat, DWORD dwRdwOptFlags)
+{
+ RECT rcUpdate, rcTmp;
+ POINT pt;
+
+ if(dat) {
+ ::GetWindowRect(::GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG), &rcTmp);
+
+ pt.x = rcTmp.left;
+ pt.y = rcTmp.top;
+ ::ScreenToClient(dat->hwnd, &pt);
+
+ rcUpdate.left = 0;
+ rcUpdate.top = pt.y;
+
+ ::GetClientRect(dat->hwnd, &rcTmp);
+ rcUpdate.right = rcTmp.right;
+ rcUpdate.bottom = rcTmp.bottom;
+
+ if(M->isAero() || M->isDwmActive())
+ dat->fLimitedUpdate = true; // skip unrelevant window updates when we have buffered paint avail
+ ::RedrawWindow(dat->hwnd, &rcUpdate, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW);
+ ::BB_RedrawButtons(dat);
+ dat->fLimitedUpdate = false;
+ }
+}
+
+/**
+ * fill a background area with the default color. This can be either the configured
+ * fill color or default system color.
+ *
+ * @param hdc: device context
+ * @param rc: area to fill.
+ */
+void CSkin::FillBack(const HDC hdc, RECT* rc)
+{
+ if(0 == CSkin::m_BrushFill) {
+ if(PluginConfig.m_fillColor)
+ CSkin::m_BrushFill = ::CreateSolidBrush(PluginConfig.m_fillColor);
+ }
+
+ if(PluginConfig.m_fillColor)
+ ::FillRect(hdc, rc, CSkin::m_BrushFill);
+ else
+ ::FillRect(hdc, rc, GetSysColorBrush(COLOR_3DFACE));
+}
diff --git a/plugins/TabSRMM/src/translator.cpp b/plugins/TabSRMM/src/translator.cpp
new file mode 100644
index 0000000000..1e801152ea
--- /dev/null
+++ b/plugins/TabSRMM/src/translator.cpp
@@ -0,0 +1,665 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: translator.cpp 12999 2010-10-22 07:32:53Z silvercircle $
+ *
+ * handle pretranslated strings
+ *
+ */
+
+#include "commonheaders.h"
+
+wchar_t* CTranslator::weekDays[7] = {LPGENT("Sunday"), LPGENT("Monday"),
+ LPGENT("Tuesday"), LPGENT("Wednesday"),
+ LPGENT("Thursday"), LPGENT("Friday"), LPGENT("Saturday")};
+
+wchar_t* CTranslator::months[12] = {LPGENT("January"), LPGENT("February"),
+ LPGENT("March"), LPGENT("April"), LPGENT("May"),
+ LPGENT("June"), LPGENT("July"), LPGENT("August"),
+ LPGENT("September"), LPGENT("October"), LPGENT("November"), LPGENT("December")};
+
+wchar_t* CTranslator::weekDays_translated[7];
+wchar_t* CTranslator::months_translated[12];
+
+wchar_t* CTranslator::m_strings[STR_LAST] = {
+ LPGENT("Stay on Top"), /* CNT_MENU_STAYONTOP */
+ LPGENT("Hide titlebar"), /* CNT_MENU_HIDETITLEBAR */
+ LPGENT("Container options..."), /* CNT_MENU_CONTAINEROPTIONS */
+ LPGENT("Message Session..."), /* CNT_TITLE_DEFAULT */
+ LPGENT("Attach to"), /* CNT_ATTACH_TO */
+ LPGENT("Meta Contact"), /* GEN_META_CONTACT */
+ LPGENT("(Forced)"), /* GEN_META_FORCED */
+ LPGENT("Autoselect"), /* GEN_META_AUTOSELECT */
+ LPGENT("Use Protocol"), /* GEN_META_USEPROTO */
+ LPGENT("Set Default Protocol"), /* GEN_META_SETDEFAULT */
+ LPGENT("Nick name"), /* GEN_MUC_NICKNAME */
+ LPGENT("Unique Id"), /* GEN_MUC_UID */
+ LPGENT("Status"), /* GEN_MUC_STATUS */
+ LPGENT("%s: Chat Room (%u user%s)"), /* GEN_MUC_ROOM_TITLE_USER */
+ LPGENT("%s: Chat Room (%u users%s)"), /* GEN_MUC_ROOM_TITLE_USERS */
+ LPGENT(", event filter active"), /* GEN_MUC_ROOM_TITLE_FILTER */
+ LPGENT("%s: Message Session"), /* GEN_MUC_PRIVSESSION */
+ LPGENT("%s: Message Session (%u users)"), /* GEN_MUC_PRIVSESSION_MULTI */
+ LPGENT("The filter canoot be enabled, because there are no event types selected either global or for this chat room"), /* GEN_MUC_FILTER_ERROR */
+ LPGENT("Event filter error"), /* GEN_MUC_FILTER_ERROR_TITLE */
+ LPGENT("Text color"), /* GEN_MUC_TEXTCOLOR */
+ LPGENT("Background color"), /* GEN_MUC_BGCOLOR */
+ LPGENT("Container options"), /* CNT_OPT_TITLE */
+ LPGENT("Tabs at the top"), /* CNT_OPT_TABSTOP */
+ LPGENT("Tabs at the bottom"), /* CNT_OPT_TABSBOTTOM */
+ LPGENT("Switch bar on the left side"), /* CNT_OPT_TABSLEFT */
+ LPGENT("Switch bar on the right side"), /* CNT_OPT_TABSRIGHT */
+ LPGENT("Configure container options for\n%s"), /* CNT_OPT_HEADERBAR */
+ LPGENT("&File"), /* GEN_MENUBAR_FILE */
+ LPGENT("&View"), /* GEN_MENUBAR_VIEW */
+ LPGENT("&User"), /* GEN_MENUBAR_USER */
+ LPGENT("&Room"), /* GEN_MENUBAR_FILE */
+ LPGENT("Message &Log"), /* GEN_MENUBAR_LOG */
+ LPGENT("&Container"), /* GEN_MENUBAR_CONTAINER */
+ LPGENT("Help"), /* GEN_MENUBAR_HELP */
+ LPGENT("Sounds are %s. Click to toggle status, hold SHIFT and click to set for all open containers"), /* GEN_CNT_SBAR_SOUNDS */
+ LPGENT("enabled"), /* GEN_ENABLED */
+ LPGENT("disabled"), /* GEN_DISABLED */
+ LPGENT("Sending typing notifications is %s."), /* GEN_CNT_SBAR_MTN */
+ LPGENT("Extended status for %s: %s"), /* GEN_IP_TIP_XSTATUS */
+ LPGENT("%s is using"), /* GEN_IP_TIP_CLIENT */
+ LPGENT("Status message for %s (%s)"), /* GEN_IP_TIP_STATUSMSG */
+ LPGENT("tabSRMM Information"), /* GEN_IP_TIP_TITLE */
+ LPGENT("All message containers need to close before the skin can be changed\nProceed?"), /* GEN_SKIN_WARNCLOSE */
+ LPGENT("Change skin"), /* GEN_SKIN_WARNCLOSE_TITLE */
+ LPGENT("Warning: Popup plugin not found."), /* GEN_MTN_POPUP_WARNING */
+ LPGENT("Warning: Current Popup plugin version is not supported."), /* GEN_MTN_POPUP_UNSUPPORTED */
+ LPGENT("Contact"), /* GEN_CONTACT */
+ LPGENT("...is typing a message."), /* GEN_MTN_START */
+ LPGENT("...has stopped typing."), /* GEN_MTN_STOP */
+ LPGENT("Favorites"), /* GEN_FAVORITES */
+ LPGENT("Recent Sessions"), /* GEN_RECENT_SESSIONS */
+ LPGENT("Last received: %s at %s"), /* GEN_SBAR_LASTRECEIVED */
+ LPGENT("There are %d pending send jobs. Message length: %d bytes, message length limit: %d bytes\n\n%d messages are queued for later delivery"), /* GEN_SBAR_TIP_MSGLENGTH */
+ LPGENT("General options"), /* CNT_OPT_TITLE_GEN */
+ LPGENT("Window layout"), /* CNT_OPT_TITLE_LAYOUT */
+ LPGENT("Tabs and switch bar"), /* CNT_OPT_TITLE_TABS */
+ LPGENT("Notifications"), /* CNT_OPT_TITLE_NOTIFY */
+ LPGENT("Flashing"), /* CNT_OPT_TITLE_FLASHING */
+ LPGENT("Title bar"), /* CNT_OPT_TITLE_TITLEBAR */
+ LPGENT("Window size and theme"), /* CNT_OPT_TITLE_THEME */
+ LPGENT("Transparency"), /* CNT_OPT_TITLE_TRANS */
+ LPGENT("Choose your options for the tabbed user interface. Not all options can be applied to open windows. You may need to close and re-open them."), /* CNT_OPT_DESC_TABS */
+ LPGENT("Select, when you want to see event notifications (popups) for this window. The settings apply to all tabs within this window."), /*CNT_OPT_DESC_NOTIFY */
+ LPGENT("You can select a private theme (.tabsrmm file) for this container which will then override the default message log theme. You will have to close and re-open all message windows after changing this option."), /* CNT_OPT_DESC_THEME */
+ LPGENT("This feature requires Windows 2000 or later and may be unavailable when using a container skin."), /* CNT_OPT_DESC_TRANS */
+ LPGENT("Message"), /* GEN_POPUPS_MESSAGE */
+ LPGENT("Unknown event"), /* GEN_POPUPS_UNKNOWN */
+ LPGENT("New messages: "), /* GEN_POPUPS_NEW */
+ LPGENT("No status message"), /* GEN_NO_STATUS */
+ LPGENT("%s is typing a message."), /* GEN_MTN_STARTWITHNICK */
+ LPGENT("Typing Notification"), /* GEN_MTN_TTITLE */
+ LPGENT("Message from %s"), /* GEN_MSG_TTITLE */
+ LPGENT("/"), /* GEN_ICONPACK_WARNING */ /* NOT IN USE!! */
+ LPGENT("Select container for %s"), /* CNT_SELECT_FOR */
+ LPGENT("This name is already in use"), /* CNT_SELECT_INUSE */
+ LPGENT("You cannot rename the default container"), /* CNT_SELECT_RENAMEERROR */
+ LPGENT("You cannot delete the default container"), /* CNT_SELECT_DELETEERROR */
+ LPGENT(" "), /* GEN_WARN_CLOSE */ /* UNUSED */
+ LPGENT("Error creating destination directory"), /* GEN_MSG_SAVE_NODIR */
+ LPGENT("Save contact picture"), /* GEN_MSG_SAVE */
+ LPGENT("The file exists. Do you want to overwrite it?"), /* GEN_MSG_SAVE_FILE_EXISTS */
+ LPGENT("Topic is: %s"), /* GEN_MUC_TOPIC_IS */
+ LPGENT("no topic set."), /* GEN_MUC_NO_TOPIC */
+ LPGENT("%s has entered text."), /* GEN_MTN_STOPPED */
+ LPGENT("Contact Picture Settings..."), /* GEN_AVATAR_SETTINGS */
+ LPGENT("Set Your Avatar..."), /* GEN_AVATAR_SETOWN */
+ LPGENT("Do you want to also read message templates from the theme?\nCaution: This will overwrite the stored template set which may affect the look of your message window significantly.\nSelect cancel to not load anything at all."), /* GEN_WARNING_LOADTEMPLATES */
+ LPGENT("Load theme"), /* GEN_TITLE_LOADTHEME */
+ LPGENT("The 'paste and send' feature is disabled. You can enable it on the 'General' options page in the 'Sending Messages' section"), /* GEN_WARNING_PASTEANDSEND_DISABELD */
+ LPGENT("Either the nudge plugin is not installed or the contact's protocol does not support sending a nudge event."), /*GEN_WARNING_NUDGE_DISABLED */
+ LPGENT("'(Unknown Contact)'"), /* GEN_UNKNOWN_CONTACT */
+ LPGENT("Today"), /* GEN_LOG_TODAY */
+ LPGENT("Yesterday"), /* GEN_LOG_YESTERDAY */
+ LPGENT("Use default codepage"), /* GEN_LOG_USEDEFAAULTCP */
+ LPGENT("UID: %s (SHIFT click -> copy to clipboard)\nClick for User's Details\nRight click for MetaContact control\nClick dropdown to add or remove user from your favorites."), /* GEN_MSG_UINCOPY */
+ LPGENT("No UID"), /* GEN_MSG_NOUIN */
+ LPGENT("UID: %s (SHIFT click -> copy to clipboard)\nClick for User's Details\nClick dropdown to change this contact's favorite status."), /* GEN_MSG_UINCOPY_NO_MC */
+ LPGENT("signed off."), /* GEN_MSG_SIGNEDOFF */
+ LPGENT("signed on and is now %s."), /* GEN_MSG_SIGNEDON */
+ LPGENT("changed status from %s to %s."), /* GEN_MSG_CHANGEDSTATUS */
+ LPGENT("There are unsent messages waiting for confirmation.\nWhen you close the window now, Miranda will try to send them but may be unable to inform you about possible delivery errors.\nDo you really want to close the Window(s)?"), /* GEN_SQ_WARNING */
+ LPGENT("Message window warning"), /* GEN_SQ_WARNING_TITLE */
+ LPGENT("You haven't selected any contacts from the list. Click the checkbox box next to a name to send the message to that person."), /* GEN_SQ_MULTISEND_NOCONTACTS */
+ LPGENT("A message delivery has failed.\nClick to open the message window."), /* GEN_SQ_DELIVERYFAILED */
+ LPGENT("A message delivery has failed after the contacts chat window was closed. You may want to resend the last message"), /* GEN_SQ_DELIVERYFAILEDLATE */
+ LPGENT("Multisend: successfully sent to: %s"), /* GEN_SQ_MULTISEND_SUCCESS */
+ LPGENT("Message successfully queued for later delivery.\nIt will be sent as soon as possible and a popup will inform you about the result."), /* GEN_SQ_QUEUED_MESSAGE */
+ LPGENT("The send later feature is not available on this protocol."), /* GEN_SQ_QUEUING_NOT_AVAIL */
+ LPGENT("\n(Sent delayed. Original timestamp %s)"), /* GEN_SQ_SENDLATER_HEADER */
+ LPGENT("Session list.\nClick left for a list of open sessions.\nClick right to access favorites and quickly configure message window behavior"), /* CNT_SBAR_SLIST */
+ LPGENT("Character Encoding"), /* GEN_MSG_ENCODING */
+ LPGENT("A message failed to send successfully."), /* GEN_MSG_FAILEDSEND */
+ LPGENT("WARNING: The message you are trying to paste exceeds the message size limit for the active protocol. It will be sent in chunks of max %d characters"), /* GEN_MSG_TOO_LONG_SPLIT */
+ LPGENT("The message you are trying to paste exceeds the message size limit for the active protocol. Only the first %d characters will be sent."), /* GEN_MSG_TOO_LONG_NOSPLIT */
+ LPGENT("Close Session"), /* GEN_MSG_CLOSE */
+ LPGENT("Save and close session"), /* GEN_MSG_SAVEANDCLOSE */
+ LPGENT("Autoscrolling is disabled (press F12 to enable it)"), /* GEN_MSG_LOGFROZENSTATIC */
+ LPGENT("Click for contact menu\nClick dropdown for window settings"), /*GEN_MSG_TIP_CONTACTMENU */
+ LPGENT("Retry"), /* GEN_MSG_BUTTON_RETRY */
+ LPGENT("Cancel"), /* GEN_MSG_BUTTON_CANCEL */
+ LPGENT("Send later"), /* GEN_MSG_BUTTON_SENDLATER */
+ LPGENT("Selection copied to clipboard"), /* GEN_MSG_SEL_COPIED */
+ LPGENT("Autoscrolling is disabled, %d message(s) queued (press F12 to enable it)"), /* GEN_MSG_LOGFROZENQUEUED */
+ LPGENT("Unknown client"), /* GEN_MSG_UNKNOWNCLIENT */
+ LPGENT("No extended status message available"), /* GEN_MSG_NOXSTATUSMSG */
+ LPGENT("Delivery failure: %s"), /* GEN_MSG_DELIVERYFAILURE */
+ LPGENT("The message send timed out"), /* GEN_MSG_SENDTIMEOUT */
+ LPGENT("Show Contact Picture"), /* GEN_MSG_SHOWPICTURE */
+ LPGENT("You cannot edit user notes when there are unsent messages"), /* GEN_MSG_NO_EDIT_NOTES */
+ LPGENT("You are editing the user notes. Click the button again or use the hotkey (default: Alt-N) to save the notes and return to normal messaging mode"), /* GEN_MSG_EDIT_NOTES_TIP */
+ LPGENT("Warning: you have selected a subprotocol for sending the following messages which is currently offline"), /* GEN_MSG_MC_OFFLINEPROTOCOL */
+ LPGENT("Contact is offline and this protocol does not support sending files to offline users."), /* GEN_MSG_OFFLINE_NO_FILE */
+ LPGENT("File"), /* GEN_STRING_FILE */
+ LPGENT("Message from %s"), /* GEN_STRING_MESSAGEFROM */
+ LPGENT("Multisend: failed sending to: %s"), /* GEN_SQ_MULTISENDERROR */
+ LPGENT("Look up \'%s\':"), /* GEN_MUC_LOOKUP */
+ LPGENT("No word to look up"), /* GEN_MUC_LOOKUP_NOWORD */
+ LPGENT("&Message"), /* GEN_MUC_MESSAGEAMP */
+ LPGENT("UTF-8"), /* GEN_STRING_UTF8 */
+
+ /* MUC LOG Formatting strings*/
+
+ LPGENT("%s has joined"), /* MUC_LOG_JOINED */
+ LPGENT("You have joined %s"), /* MUC_LOG_ME_JOINED */
+ LPGENT("%s has left"), /* MUC_LOG_LEFT */
+ LPGENT("%s has disconnected"), /* MUC_LOG_DISC */
+ LPGENT("%s is now known as %s"), /* MUC_LOG_NICKCHANGE */
+ LPGENT("You are now known as %s"), /* MUC_LOG_ME_NICKCHANGE */
+ LPGENT("%s kicked %s"), /* MUC_LOG_KICK */
+ LPGENT("Notice from %s: "), /* MUC_LOG_NOTICE */
+ LPGENT("The topic is \'%s%s\'"), /* MUC_LOG_TOPICIS */
+ LPGENT(" (set by %s on %s)"), /* MUC_LOG_TOPICSETBYON */
+ LPGENT(" (set by %s)"), /* MUC_LOG_TOPICSETBY */
+ LPGENT("%s enables \'%s\' status for %s"), /* MUC_LOG_STATUSENABLE */
+ LPGENT("%s disables \'%s\' status for %s"), /* MUC_LOG_STATUSDISABLE */
+ LPGENT("Highlight User..."), /* GEN_MUC_MENU_ADDTOHIGHLIGHT */
+ LPGENT("Add user to highlight list"), /* GEN_MUC_HIGHLIGHT_ADD */
+ LPGENT("Edit user highlight list"), /* GEN_MUC_HIGHLIGHT_EDIT */
+ LPGENT("Edit Highlight List..."), /* GEN_MUC_MENU_EDITHIGHLIGHTLIST */
+ LPGENT("Contact not on list. You may add it..."), /* GEN_MSG_CONTACT_NOT_ON_LIST */
+ LPGENT("A send later job completed successfully.\nThe original message: %s"), /* GEN_SQ_SENDLATER_SUCCESS_POPUP */
+
+ LPGENT("Copy To Clipboard"), /* GEN_IP_MENU_COPY */
+ LPGENT("Open User Details..."), /* GEN_IP_MENU_USER_DETAILS */
+ LPGENT("Messaging Settings..."), /* GEN_IP_MENU_MSGPREFS */
+ LPGENT("Room Settings..."), /* GEN_IP_MENU_ROOMPREFS */
+ LPGENT("Open History..."), /* GEN_IP_MENU_HISTORY */
+
+ LPGENT("hour"), /* GEN_STRING_HOUR */
+ LPGENT("hours"), /* GEN_STRING_HOURS */
+ LPGENT("minute"), /* GEN_STRING_MINUTE */
+ LPGENT("minutes"), /* GEN_STRING_MINUTES */
+ LPGENT(", %d %s, %d %s idle"), /* MUC_SBAR_IDLEFORMAT */
+ LPGENT("%s on %s%s"), /* MUC_SBAR_ON_SERVER */
+ LPGENT(", %d %s idle"), /* MUC_SBAR_IDLEFORMAT_SHORT */
+ LPGENT("Contact avatars"), /* CNT_OPT_TITLE_AVATARS */
+
+ /*
+ * MUC tray icon notifications
+ */
+
+ LPGENT("%s wants your attention in %s"), /* GEN_MUC_TRAY_HILIGHT */
+ LPGENT("%s speaks in %s"), /* GEN_MUC_TRAY_MSG */
+ LPGENT("%s has joined %s"), /* GEN_MUC_TRAY_JOINED */
+ LPGENT("%s has left %s"), /* GEN_MUC_TRAY_LEFT */
+ LPGENT("%s has disconnected"), /* GEN_MUC_TRAY_QUIT */
+ LPGENT("%s is now known as %s"), /* GEN_MUC_TRAY_NICK */
+ LPGENT("%s kicked %s from %s"), /* GEN_MUC_TRAY_KICK */
+ LPGENT("Notice from %s"), /* GEN_MUC_TRAY_NOTICE */
+ LPGENT("Topic change in %s"), /* GEN_MUC_TRAY_TOPIC */
+ LPGENT("Information in %s"), /* GEN_MUC_TRAY_INFO */
+ LPGENT("%s enables \'%s\' status for %s in %s"), /* GEN_MUC_TRAY_STATUS_ON */
+ LPGENT("%s disables \'%s\' status for %s in %s"), /* GEN_MUC_TRAY_STATUS_OFF */
+
+ /*
+ * muc popups and disk logging
+ */
+
+ LPGENT("%s%s says:%s %s"), /* GEN_MUC_POPUP_MSG */
+ LPGENT("%s has joined"), /* GEN_MUC_POPUP_JOINED */
+ LPGENT("%s has left"), /* GEN_MUC_POPUP_LEFT */
+ LPGENT("%s has left (%s)"), /* GEN_MUC_POPUP_LEFT1 */
+ LPGENT("%s has disconnected"), /* GEN_MUC_POPUP_QUIT */
+ LPGENT("%s has disconnected (%s)"), /* GEN_MUC_POPUP_QUIT1 */
+ LPGENT("%s is now known as %s"), /* GEN_MUC_POPUP_NICK */
+ LPGENT("%s kicked %s"), /* GEN_MUC_POPUP_KICK */
+ LPGENT("%s kicked %s (%s)"), /* GEN_MUC_POPUP_KICK1 */
+ LPGENT("Notice from %s: %s"), /* GEN_MUC_POPUP_NOTICE */
+ LPGENT("The topic is \'%s\'"), /* GEN_MUC_POPUP_TOPIC */
+ LPGENT("The topic is \'%s\' (set by %s)"), /* GEN_MUC_POPUP_TOPIC1 */
+ LPGENT("%s enables \'%s\' status for %s"), /* GEN_MUC_POPUP_STATUS_ON */
+ LPGENT("%s disables \'%s\' status for %s"), /* GEN_MUC_POPUP_STATUS_OFF */
+
+ LPGENT("Sound notifications"), /* CNT_OPT_TITLE_SOUNDS */
+ LPGENT("%s Idle: %dh,%02dm"), /* GEN_IP_IDLENOTICE */
+
+ /**
+ * template strings for the richedit - based infopanel tooltip.
+ * Please DO NOT mess with the RTF formatting codes or you may destroy the layout of the
+ * tooltips, just translate the strings inside
+ */
+ LPGENT("\\tab \\ul\\b Status message:\\ul0\\b0 \\par %s"), /* GEN_INFOTIP_STATUSMSG */
+ LPGENT("\\par\\par\\tab \\ul\\b Extended status information:\\ul0\\b0 \\par "), /* GEN_INFOTIP_XSTATUS */
+ LPGENT("\\par\\par\\tab \\ul\\b Listening to:\\ul0\\b0 \\par %s"), /* GEN_INFOTIP_LISTENING */
+ LPGENT("\\par\\par\\ul\\b Client:\\ul0\\b0 %s"), /* GEN_INFOTIP_CLIENT */
+
+ LPGENT("Insert [img] tag / surround selected text with [img][/img]"), /* GEN_BB_IMGTOOLTIP */
+ LPGENT("Original timestamp"), /* QMGR_COL_ODATE */
+ LPGENT("Message text"), /* QMGR_COL_MESSAGETEXT */
+ LPGENT("Status"), /* QMGR_COL_STATUS */
+ LPGENT("Last send info"), /* QMGR_COL_LASTSENDINFO */
+ LPGENT("<All contacts>"), /* QMGR_FILTER_ALLCONTACTS */
+ LPGENT("Failed"), /* QMGR_STATUS_FAILED */
+ LPGENT("Sent OK"), /* QMGR_STATUS_SENTOK */
+ LPGENT("Pending"), /* QMGR_STATUS_PENDING */
+ LPGENT("Wait ACK"), /* QMGR_STATUS_WAITACK */
+ LPGENT("Configuration issue|The unattended send feature is disabled. The \\b1 send later\\b0 and \\b1 send to multiple contacts\\b0 features depend on it.\n\nYou must enable it under \\b1Options->Message Sessions->Advanced tweaks\\b0. Changing this option requires a restart."), /* QMGR_ERROR_NOMULTISEND */
+ LPGENT("Removed"), /* QMGR_STATUS_REMOVED */
+ LPGENT("You are about to modify the state of one or more items in the\nunattended send queue. The requested action(s) will be executed at the next scheduled queue processing.\n\nThis action cannot be made undone."), /* QMGR_WARNING_REMOVAL */
+ LPGENT("Queue manager"), /* QMGR_TITLE */
+ LPGENT("Suspended"), /* QMGR_STATUS_HOLD */
+ LPGENT("Deferred"), /* QMGR_STATUS_DEFERRED */
+ LPGENT("A send later job failed to complete.\nThe original message: %s"), /* GEN_SQ_SENDLATER_FAILED_POPUP */
+ LPGENT("The message cannot be sent delayed or to multiple contacts, because it exceeds the maximum allowed message length of %d bytes"), /* GEN_SQ_SENDLATER_ERROR_MSG_TOO_LONG */
+
+ LPGENT("Default container"), /* GEN_DEFAULT_CONTAINER_NAME */
+ /*
+ * event notification popups
+ */
+ LPGENT("No description given"), /* GEN_STRING_EVENT_FILE_NODESC */
+ LPGENT("Incoming file (invalid format"), /* GEN_STRING_EVENT_FILE_INVALID */
+ LPGENT("Incoming file"), /* GEN_STRING_EVENT_FILE */
+ /*
+ * tooltips for static message window buttons
+ */
+ LPGENT("Add this contact permanently to your contact list"), /* GEN_TOOLTIP_ADDCONTACT */
+ LPGENT("Do not add this contact permanently"), /* GEN_TOOLTIP_DONTADD */
+ LPGENT("Expand or collapse the side bar"), /* GEN_TOOLTIP_EXPANDSIDEBAR */
+
+ /*
+ * task bar support (thumbnails)
+ */
+ LPGENT("Chat room %s"), /* GEN_TASKBAR_STRING_CHAT_ROOM */
+ LPGENT("Server window"), /* GEN_TASKBAR_STRING_SERVER_WINDOW */
+ LPGENT("%d Unread"), /* GEN_TASKBAR_STRING_UNREAD */
+ LPGENT("%d User(s)"), /* GEN_TASKBAR_STRING_USERS */
+
+ LPGENT("Previews not availble when using History++ plugin for message log display."), /* GEN_AEROPEEK_NOHPP */
+ LPGENT("TabSRMM warning message"), /* GEN_STRING_WARNING_TITLE */
+};
+
+/*
+ * these strings are used by option pages ONLY
+ */
+
+wchar_t* CTranslator::m_OptStrings[OPT_LAST] = {
+ LPGENT("Use Global Setting"), /* OPT_UPREFS_IPGLOBAL */
+ LPGENT("Always On"), /* OPT_UPREFS_ON */
+ LPGENT("Always Off"), /* OPT_UPREFS_OFF */
+ LPGENT("Show always (if present)"), /* OPT_UPREFS_AVON */
+ LPGENT("Never show it at all"), /* OPT_UPREFS_AVOFF */
+ LPGENT("Force History++"), /* OPT_UPREFS_FORCEHPP */
+ LPGENT("Force IEView"), /* OPT_UPREFS_FORCEIEV */
+ LPGENT("Force Default Message Log"), /* OPT_UPREFS_FORCEDEFAULT */
+ LPGENT("Simple Tags (*/_)"), /* OPT_UPREFS_SIMPLETAGS */
+ LPGENT("BBCode"), /* OPT_UPREFS_BBCODE */
+ LPGENT("Force Off"), /* OPT_UPREFS_FORMATTING_OFF */
+ LPGENT("Use default codepage"), /* OPT_UPREFS_DEFAULTCP */
+ LPGENT("Time zone service is missing"), /* OPT_UPREFS_NOTZSVC */
+ LPGENT("Set messaging options for %s"), /* OPT_UPREFS_TITLE */
+ LPGENT("Message Log"), /* OPT_UPREFS_MSGLOG */
+ LPGENT("General"), /* OPT_UPREFS_GENERIC */
+ LPGENT(""), /* OPT_AERO_EFFECT_NONE */
+ LPGENT(""), /* OPT_AERO_EFFECT_MILK */
+ LPGENT(""), /* OPT_AERO_EFFECT_CARBON */
+ LPGENT(""), /* OPT_AERO_EFFECT_SOLID */
+ LPGENT("No border"), /* OPT_GEN_NONE */
+ LPGENT(""), /* OPT_GEN_AUTO */
+ LPGENT(""), /* OPT_GEN_SUNKEN */
+ LPGENT("1 pixel, solid"), /* OPT_GEN_1PIXEL */
+ LPGENT("Rounded (only for internal avatar drawing)"), /* OPT_GEN_ROUNDED */
+ LPGENT("Globally on"), /* OPT_GEN_GLOBALLY ON */
+ LPGENT("On, if present"), /* OPT_GEN_ON_IF_PRESENT */
+ LPGENT("Globally OFF"), /* OPT_GEN_GLOBALLY_OFF */
+ LPGENT("On, if present, always in bottom display"), /* OPT_GEN_ON_ALWAYS_BOTTOM */
+ LPGENT("Don't show them"), /* OPT_GEN_DONT_SHOW */
+ LPGENT("Window layout tweaks"), /* OPT_TAB_LAYOUTTWEAKS */
+ LPGENT("Load and apply"), /* OPT_TAB_SKINLOAD */
+ LPGENT("Set panel visibility for this %s"), /* OPT_IPANEL_VISIBILTY_TITLE */
+ LPGENT("contact"), /* OPT_IPANEL_VISIBILTY_IM */
+ LPGENT("chat room"), /* OPT_IPANEL_VISIBILTY_CHAT */
+ LPGENT("Do not synchronize the panel height with IM windows"), /* OPT_IPANEL_SYNC_TITLE_IM */
+ LPGENT("Do not synchronize the panel height with group chat windows"), /* OPT_IPANEL_SYNC_TITLE_MUC */
+ LPGENT("Inherit from container setting"), /* OPT_IPANEL_VIS_INHERIT */
+ LPGENT("Always off"), /* OPT_IPANEL_VIS_OFF */
+ LPGENT("Always on"), /* OPT_IPANEL_VIS_ON*/
+ LPGENT("Use default size"), /* OPT_IPANEL_SIZE_GLOBAL */
+ LPGENT("Use private size"), /* OPT_IPANEL_SIZE_PRIVATE */
+ LPGENT("Off"), /* OPT_GEN_OFF */
+ LPGENT("BBCode"), /* OPT_GEN_BBCODE */
+ LPGENT("Default"), /* OPT_LOG_DEFAULT */
+ LPGENT("IEView plugin"), /* OPT_LOG_IEVIEW */
+ LPGENT("History++ plugin"), /* OPT_LOG_HPP */
+ LPGENT("** New contacts **"), /* OPT_MTN_NEW */
+ LPGENT("** Unknown contacts **"), /* OPT_MTN_UNKNOWN */
+ LPGENT("Always"), /* OPT_GEN_ALWAYS */
+ LPGENT("Always, but no popup when window is focused"), /* OPT_MTN_NOTFOUCSED */
+ LPGENT("Only when no message window is open"), /* OPT_MTN_ONLYCLOSED */
+ LPGENT("Normal - close tab, if last tab is closed also close the window"), /* OPT_CNT_ESCNORMAL */
+ LPGENT("Minimize the window to the task bar"), /* OPT_CNT_ESCMINIMIZE */
+ LPGENT("Close or hide window, depends on the close button setting above"), /* OPT_CNT_ESCCLOSE */
+ LPGENT("Show balloon popup (unsupported system)"), /* OPT_MTN_UNSUPPORTED */
+ LPGENT("Choose status modes"), /* OPT_SMODE_CHOOSE */
+ LPGENT("nick of current contact (if defined)"), /* OPT_MUC_LOGTIP1 */
+ LPGENT("protocol name of current contact (if defined). Account name is used when protocol supports multiaccounts"), /* OPT_MUC_LOGTIP2 */
+ LPGENT("UserID of current contact (if defined). It is like UIN Number for ICQ, JID for Jabber, etc."), /* OPT_MUC_LOGTIP3 */
+ LPGENT("path to root miranda folder"), /* OPT_MUC_LOGTIP4 */
+ LPGENT("path to current miranda profile"), /* OPT_MUC_LOGTIP5 */
+ LPGENT("name of current miranda profile (filename, without extension)"), /* OPT_MUC_LOGTIP6 */
+ LPGENT("will return parsed string %miranda_profile%\\Profiles\\%miranda_profilename%"), /* OPT_MUC_LOGTIP7 */
+ LPGENT("same as environment variable %APPDATA% for currently logged-on Windows user"), /* OPT_MUC_LOGTIP8 */
+ LPGENT("username for currently logged-on Windows user"), /* OPT_MUC_LOGTIP9 */
+ LPGENT("\"My Documents\" folder for currently logged-on Windows user"), /* OPT_MUC_LOGTIP10 */
+ LPGENT("\"Desktop\" folder for currently logged-on Windows user"), /* OPT_MUC_LOGTIP11 */
+ LPGENT("any environment variable defined in current Windows session (like %systemroot%, %allusersprofile%, etc.)"), /* OPT_MUC_LOGTIP12 */
+ LPGENT("day of month, 1-31"), /* OPT_MUC_LOGTIP13 */
+ LPGENT("day of month, 01-31"), /* OPT_MUC_LOGTIP14 */
+ LPGENT("month number, 1-12"), /* OPT_MUC_LOGTIP15 */
+ LPGENT("month number, 01-12"), /* OPT_MUC_LOGTIP16 */
+ LPGENT("abbreviated month name"), /* OPT_MUC_LOGTIP17 */
+ LPGENT("full month name"), /* OPT_MUC_LOGTIP18 */
+ LPGENT("year without century, 01-99"), /* OPT_MUC_LOGTIP19 */
+ LPGENT("year with century, 1901-9999"), /* OPT_MUC_LOGTIP20 */
+ LPGENT("abbreviated weekday name"), /* OPT_MUC_LOGTIP21 */
+ LPGENT("full weekday name"), /* OPT_MUC_LOGTIP22 */
+ LPGENT("Appearance and functionality of chat room windows"), /* OPT_MUC_OPTHEADER1 */
+ LPGENT("Appearance of the message log"), /* OPT_MUC_OPTEHADER2 */
+ LPGENT("Variables"), /* OPT_MUC_VARIABLES */
+ LPGENT("Select Folder"), /* OPT_MUC_SELECTFOLDER */
+ LPGENT("No markers"), /* OPT_MUC_NOMARKERS */
+ LPGENT("Show as icons"), /* OPT_MUC_ASICONS */
+ LPGENT("Show as text symbols"), /* OPT_MUC_ASSYMBOLS */
+ LPGENT("Template Set Editor"), /* OPT_TEMP_TITLE */
+ LPGENT("This will reset the template set to the default built-in templates. Are you sure you want to do this?"), /* OPT_TEMP_RESET */
+ LPGENT("Template set was successfully reset, please close and reopen all message windows. This template editor window will now close."), /* OPT_TEMP_WASRESET */
+ LPGENT("Template editor help"), /* OPT_TEMP_HELPTITLE */
+ LPGENT("General"), /* OPT_TABS_GENERAL */
+ LPGENT("Tabs and layout"), /* OPT_TABS_TABS */
+ LPGENT("Containers"), /* OPT_TABS_CONTAINERS */
+ LPGENT("Message log"), /* OPT_TABS_LOG */
+ LPGENT("Tool bar"), /* OPT_TABS_TOOLBAR */
+ LPGENT("Advanced tweaks"), /* OPT_TABS_ADVANCED */
+ LPGENT("Settings"), /* OPT_TABS_MUC_SETTINGS */
+ LPGENT("Log formatting"), /* OPT_TABS_MUC_LOG */
+ LPGENT("Events and filters"), /* OPT_TABS_MUC_EVENTS */
+ LPGENT("Highlighting"), /* OPT_TABS_MUC_HIGHLIGHT */
+ LPGENT("You have chosen to use an external plugin for displaying the message history in the chat window. Most of the settings on this page are for the standard message log viewer only and will have no effect. To change the appearance of the message log, you must configure either IEView or History++."), /* OPT_MSGLOG_EXPLAINSETTINGS */
+ LPGENT("<no skin>"), /* OPT_SKIN_NOSKINSELECT */
+};
+
+/** IMPORTANT note to translators for translation of the warning dialogs:
+ *
+ * Make sure to NOT remove the pipe character ( | ) from the strings. This separates the
+ * warning title from the actual warning text.
+ *
+ * Also, do NOT insert multiple | characters in the translated string. Not well-formatted
+ * warnings cannot be translated and the plugin will show the untranslated versions.
+ *
+ * strings marked with a NOT TRANSLATABLE comment cannot be translated at all. This
+ * will be used for important and critical error messages only.
+ *
+ * some strings are empty, this is intentional and used for error messages that share
+ * the message with other possible error notifications (popups, tool tips etc.)
+ *
+ * Entries that do not use the LPGENT() macro are NOT TRANSLATABLE, so don't bother translating them.
+ */
+wchar_t* CTranslator::m_Warnings[WARN_LAST] = {
+ LPGENT("Important release notes|A test warning message"), /* WARN_TEST */ /* reserved for important notes after upgrade - NOT translatable */
+ LPGENT("Icon pack version check|The installed icon pack is outdated and might be incompatible with TabSRMM version 3.\n\n\\b1Missing or misplaced icons are possible issues with the currently installed icon pack.\\b0"), /* WARN_ICONPACKVERSION */ /* NOT TRANSLATABLE */
+ LPGENT("Edit user notes|You are editing the user notes. Click the button again or use the hotkey (default: Alt-N) to save the notes and return to normal messaging mode"), /* WARN_EDITUSERNOTES */
+ LPGENT("Missing component|The icon pack is missing. Please install it to the default icons folder.\n\nNo icons will be available"), /* WARN_ICONPACKMISSING */ /* NOT TRANSLATABLE */
+ LPGENT("Aero peek warning|You have enabled Aero Peek features and loaded a custom container window skin\n\nThis can result in minor visual anomalies in the live preview feature."), /* WARN_AEROPEEKSKIN */
+ LPGENT("TabSRMM group chat module|TabSRMM could not enable its group chat module. The most likely cause is that you have installed and enabled \\b1chat.dll\\b0 or another plugin that provides groupchat services.\n\nShould I try to fix this now \\b1(a restart of Miranda is required to apply these changes)?\\b0"), /* WARN_CHAT_ENABLED */ /* NOT TRANSLATABLE */
+ L"Filetransfer problem|Sending the image by file transfer failed.\n\nPossible reasons: File transfers not supported, either you or the target contact is offline, or you are invisible and the target contact is not on your visibilty list.", /* WARN_IMGSVC_MISSING */ /* NOT TRANSLATABLE */
+ LPGENT("Settings problem|The option \\b1 History->Imitate IEView API\\b0 is enabled and the History++ plugin is active. This can cause problems when using IEView as message log viewer.\n\nShould I correct the option (a restart is required)?"), /* WARN_HPP_APICHECK */
+ L" ", /* WARN_NO_SENDLATER */ /*uses QMGR_ERROR_NOMULTISEND */
+ LPGENT("Closing Window|You are about to close a window with multiple tabs open.\n\nProceed?"), /* WARN_CLOSEWINDOW */
+ LPGENT("Closing options dialog|To reflect the changes done by importing a theme in the options dialog, the dialog must be closed after loading a theme \\b1 and unsaved changes might be lost\\b0 .\n\nDo you want to continue?"), /* WARN_OPTION_CLOSE */
+ LPGENT("Loading a theme|Loading a color and font theme can overwrite the settings defined by your skin.\n\nDo you want to continue?"), /* WARN_THEME_OVERWRITE */
+};
+
+wchar_t* CTranslator::m_translated[STR_LAST];
+wchar_t* CTranslator::m_OptTranslated[OPT_LAST];
+wchar_t* CTranslator::m_WarningsTranslated[WARN_LAST];
+
+TOptionListGroup CTranslator::m_lvGroupsModPlus[] = {
+ 0, LPGENT("Message window tweaks"),
+ 0, LPGENT("Error feedback"),
+ 0, NULL
+};
+
+TOptionListItem CTranslator::m_lvItemsModPlus[] = {
+ 0, LPGENT("Show client icon in status bar (fingerprint plugin required)"), 0, LOI_TYPE_SETTING, (UINT_PTR)"adv_ClientIconInStatusBar", 0,
+ 0, LPGENT("Show skinnable tooltip in chat (tipper plugin required)"), 1, LOI_TYPE_SETTING, (UINT_PTR)"adv_TipperTooltip", 0,
+ 0, LPGENT("Enable typing sounds"), 0, LOI_TYPE_SETTING, (UINT_PTR)"adv_soundontyping", 0,
+ 0, LPGENT("Disable animated GIF avatars (will not affect already open message windows)"), 0, LOI_TYPE_SETTING, (UINT_PTR)"adv_DisableAniAvatars", 0,
+ 0, LPGENT("Close current tab on send"), 0, LOI_TYPE_SETTING, (UINT_PTR)"adv_AutoClose_2", 0,
+ 0, LPGENT("Disable error popups on sending failures"), 0, LOI_TYPE_SETTING, (UINT_PTR)"adv_noErrorPopups", 1,
+ 0, LPGENT("Automatic keyboard layout: Do not load the system default for new contacts"), 1, LOI_TYPE_SETTING, (UINT_PTR)"adv_leaveKeyboardAlone", 0,
+ 0, LPGENT("Enable unattended send (experimental feature, required for multisend and send later) (*)"), 0, LOI_TYPE_SETTING, (UINT_PTR)"sendLaterAvail", 0,
+ 0, NULL, 0, 0, 0, 0
+};
+
+TOptionListItem CTranslator::m_lvItemsNEN [] = {
+ 0, LPGENT("Show a preview of the event"), IDC_CHKPREVIEW, LOI_TYPE_SETTING, (UINT_PTR)&nen_options.bPreview, 1,
+ 0, LPGENT("Don't announce event when message dialog is open"), IDC_CHKWINDOWCHECK, LOI_TYPE_SETTING, (UINT_PTR)&nen_options.bWindowCheck, 1,
+ 0, LPGENT("Don't announce events from RSS protocols"), IDC_NORSS, LOI_TYPE_SETTING, (UINT_PTR)&nen_options.bNoRSS, 1,
+ 0, LPGENT("Enable the system tray icon"), IDC_ENABLETRAYSUPPORT, LOI_TYPE_SETTING, (UINT_PTR)&nen_options.bTraySupport, 2,
+ 0, LPGENT("Merge new events for the same contact into existing popup"), 1, LOI_TYPE_SETTING, (UINT_PTR)&nen_options.bMergePopup, 6,
+ 0, LPGENT("Show headers"), IDC_CHKSHOWHEADERS, LOI_TYPE_SETTING, (UINT_PTR)&nen_options.bShowHeaders, 6,
+ 0, LPGENT("Dismiss popup"), MASK_DISMISS, LOI_TYPE_FLAG, (UINT_PTR)&nen_options.maskActL, 3,
+ 0, LPGENT("Open event"), MASK_OPEN, LOI_TYPE_FLAG, (UINT_PTR)&nen_options.maskActL, 3,
+ 0, LPGENT("Dismiss event"), MASK_REMOVE, LOI_TYPE_FLAG, (UINT_PTR)&nen_options.maskActL, 3,
+
+ 0, LPGENT("Dismiss popup"), MASK_DISMISS, LOI_TYPE_FLAG, (UINT_PTR)&nen_options.maskActR, 4,
+ 0, LPGENT("Open event"), MASK_OPEN, LOI_TYPE_FLAG, (UINT_PTR)&nen_options.maskActR, 4,
+ 0, LPGENT("Dismiss event"), MASK_REMOVE, LOI_TYPE_FLAG, (UINT_PTR)&nen_options.maskActR, 4,
+
+ 0, LPGENT("Dismiss popup"), MASK_DISMISS, LOI_TYPE_FLAG, (UINT_PTR)&nen_options.maskActTE, 5,
+ 0, LPGENT("Open event"), MASK_OPEN, LOI_TYPE_FLAG, (UINT_PTR)&nen_options.maskActTE, 5,
+
+ 0, LPGENT("Disable event notifications for instant messages"), IDC_CHKWINDOWCHECK, LOI_TYPE_SETTING, (UINT_PTR)&nen_options.iDisable, 0,
+ 0, LPGENT("Disable event notifications for group chats"), IDC_CHKWINDOWCHECK, LOI_TYPE_SETTING, (UINT_PTR)&nen_options.iMUCDisable, 0,
+ 0, LPGENT("Disable notifications for non-message events"), IDC_CHKWINDOWCHECK, LOI_TYPE_SETTING, (UINT_PTR)&nen_options.bDisableNonMessage, 0,
+
+ 0, LPGENT("Remove popups for a contact when the message window is focused"), PU_REMOVE_ON_FOCUS, LOI_TYPE_FLAG, (UINT_PTR)&nen_options.dwRemoveMask, 7,
+ 0, LPGENT("Remove popups for a contact when I start typing a reply"), PU_REMOVE_ON_TYPE, LOI_TYPE_FLAG, (UINT_PTR)&nen_options.dwRemoveMask, 7,
+ 0, LPGENT("Remove popups for a contact when I send a reply"), PU_REMOVE_ON_SEND, LOI_TYPE_FLAG, (UINT_PTR)&nen_options.dwRemoveMask, 7,
+
+ 0, NULL, 0, 0, 0, 0
+};
+
+TOptionListGroup CTranslator::m_lvGroupsNEN[] = {
+ 0, LPGENT("Disable notifications"),
+ 0, LPGENT("General options"),
+ 0, LPGENT("System tray icon"),
+ 0, LPGENT("Left click actions (popups only)"),
+ 0, LPGENT("Right click actions (popups only)"),
+ 0, LPGENT("Timeout actions (popups only)"),
+ 0, LPGENT("Combine notifications for the same contact"),
+ 0, LPGENT("Remove popups under following conditions"),
+ 0, NULL
+};
+
+TOptionListGroup CTranslator::m_lvGroupsMsg[] = {
+ 0, LPGENT("Message window behaviour"),
+ 0, LPGENT("Sending messages"),
+ 0, LPGENT("Other options"),
+ 0, NULL
+};
+
+TOptionListItem CTranslator::m_lvItemsMsg[] = {
+ 0, LPGENT("Send on SHIFT - Enter"), 0, LOI_TYPE_SETTING, (UINT_PTR)"sendonshiftenter", 1,
+ 0, LPGENT("Send message on 'Enter'"), SRMSGDEFSET_SENDONENTER, LOI_TYPE_SETTING, (UINT_PTR)SRMSGSET_SENDONENTER, 1,
+ 0, LPGENT("Send message on double 'Enter'"), 0, LOI_TYPE_SETTING, (UINT_PTR)"SendOnDblEnter", 1,
+ 0, LPGENT("Minimize the message window on send"), SRMSGDEFSET_AUTOMIN, LOI_TYPE_SETTING, (UINT_PTR)SRMSGSET_AUTOMIN, 1,
+ //Mad
+ 0, LPGENT("Close the message window on send"), 0, LOI_TYPE_SETTING, (UINT_PTR)"AutoClose", 1,
+ //mad_
+ 0, LPGENT("Always flash contact list and tray icon for new messages"), 0, LOI_TYPE_SETTING, (UINT_PTR)"flashcl", 0,
+ 0, LPGENT("Delete temporary contacts on close"), 0, LOI_TYPE_SETTING, (UINT_PTR)"deletetemp", 0,
+ 0, LPGENT("Enable \"Paste and send\" feature"), 0, LOI_TYPE_SETTING, (UINT_PTR)"pasteandsend", 1,
+ 0, LPGENT("Allow BBCode formatting in outgoing messages"), 0, LOI_TYPE_SETTING, (UINT_PTR)"sendformat", 1,
+ 0, LPGENT("Automatically split long messages (experimental, use with care)"), 0, LOI_TYPE_SETTING, (UINT_PTR)"autosplit", 2,
+ 0, NULL, 0, 0, 0, 0
+};
+
+TOptionListGroup CTranslator::m_lvGroupsLog[] = {
+ 0, LPGENT("Message log appearance"),
+ 0, LPGENT("Support for external plugins"),
+ 0, LPGENT("Other options"),
+ 0, LPGENT("Additional events to show"),
+ 0, LPGENT("Timestamp settings (note: timstamps also depend on your templates)"),
+ 0, LPGENT("Message log icons"),
+ 0, NULL
+};
+
+TOptionListItem CTranslator::m_lvItemsLog[] = {
+ 0, LPGENT("Show file events"), 1, LOI_TYPE_SETTING, (UINT_PTR)SRMSGSET_SHOWFILES, 3,
+ 0, LPGENT("Show timestamps"), 1, LOI_TYPE_FLAG, (UINT_PTR)MWF_LOG_SHOWTIME, 4,
+ 0, LPGENT("Show dates in timestamps"), 1, LOI_TYPE_FLAG, (UINT_PTR)MWF_LOG_SHOWDATES, 4,
+ 0, LPGENT("Show seconds in timestamps"), 1, LOI_TYPE_FLAG, (UINT_PTR)MWF_LOG_SHOWSECONDS, 4,
+ 0, LPGENT("Use contacts local time (if timezone info available)"), 0, LOI_TYPE_FLAG, (UINT_PTR)MWF_LOG_LOCALTIME, 4,
+ 0, LPGENT("Draw grid lines"), 1, LOI_TYPE_FLAG, MWF_LOG_GRID, 0,
+ 0, LPGENT("Event type icons in the message log"), 1, LOI_TYPE_FLAG, MWF_LOG_SHOWICONS, 5,
+ 0, LPGENT("Text symbols as event markers"), 0, LOI_TYPE_FLAG, MWF_LOG_SYMBOLS, 5,
+ 0, LPGENT("Use Incoming/Outgoing Icons"), 1, LOI_TYPE_FLAG, MWF_LOG_INOUTICONS, 5,
+ 0, LPGENT("Use Message Grouping"), 1, LOI_TYPE_FLAG, MWF_LOG_GROUPMODE, 0,
+ 0, LPGENT("Indent message body"), 1, LOI_TYPE_FLAG, MWF_LOG_INDENT, 0,
+ 0, LPGENT("Simple text formatting (*bold* etc.)"), 0, LOI_TYPE_FLAG, MWF_LOG_TEXTFORMAT, 0,
+ 0, LPGENT("Support BBCode formatting"), 1, LOI_TYPE_FLAG, MWF_LOG_BBCODE, 0,
+ 0, LPGENT("Place a separator in the log after a window lost its foreground status"), 0, LOI_TYPE_SETTING, (UINT_PTR)"usedividers", 0,
+ 0, LPGENT("Only place a separator when an incoming event is announced with a popup"), 0, LOI_TYPE_SETTING, (UINT_PTR)"div_popupconfig", 0,
+ 0, LPGENT("RTL is default text direction"), 0, LOI_TYPE_FLAG, MWF_LOG_RTL, 0,
+ //0, LPGENT("Support Math Module plugin"), 1, LOI_TYPE_SETTING, (UINT_PTR)"wantmathmod", 1,
+//MAD:
+ 0, LPGENT("Show events at the new line (IEView Compatibility Mode)"), 1, LOI_TYPE_FLAG, MWF_LOG_NEWLINE, 1,
+ 0, LPGENT("Underline timestamp/nickname (IEView Compatibility Mode)"), 0, LOI_TYPE_FLAG, MWF_LOG_UNDERLINE, 1,
+ 0, LPGENT("Show timestamp after nickname (IEView Compatibility Mode)"), 0, LOI_TYPE_FLAG, MWF_LOG_SWAPNICK, 1,
+//
+ 0, LPGENT("Log status changes"), 1, LOI_TYPE_FLAG, MWF_LOG_STATUSCHANGES, 2,
+ 0, LPGENT("Automatically copy selected text"), 0, LOI_TYPE_SETTING, (UINT_PTR)"autocopy", 2,
+ 0, LPGENT("Use normal templates (uncheck to use simple templates if your template set supports them)"), 1, LOI_TYPE_FLAG, MWF_LOG_NORMALTEMPLATES, 0,
+ 0, NULL, 0, 0, 0, 0
+};
+
+TOptionListGroup CTranslator::m_lvGroupsTab[] = {
+ 0, LPGENT("Tab options"),
+ 0, LPGENT("How to create tabs and windows for incoming messages"),
+ 0, LPGENT("Miscellaneous options"),
+ 0, NULL
+};
+
+TOptionListItem CTranslator::m_lvItemsTab[] = {
+ 0, LPGENT("Show status text on tabs"), 1, LOI_TYPE_SETTING, (UINT_PTR)"tabstatus", 0,
+ 0, LPGENT("Prefer xStatus icons when available"), 1, LOI_TYPE_SETTING, (UINT_PTR)"use_xicons", 0,
+ 0, LPGENT("Detailed tooltip on tabs (requires mToolTip or Tipper plugin)"), 0, LOI_TYPE_SETTING, (UINT_PTR)"d_tooltips", 0,
+ 0, LPGENT("ALWAYS activate new message sessions (has PRIORITY over the options below)"), SRMSGDEFSET_AUTOPOPUP, LOI_TYPE_SETTING, (UINT_PTR)SRMSGSET_AUTOPOPUP, 1,
+ 0, LPGENT("Automatically create new message sessions without activating them"), 1, LOI_TYPE_SETTING, (UINT_PTR)"autotabs", 1,
+ 0, LPGENT("New windows are minimized (the option above MUST be active)"), 1, LOI_TYPE_SETTING, (UINT_PTR)"autocontainer", 1,
+ 0, LPGENT("Activate a minimized window when a new tab is created inside it"), 0, LOI_TYPE_SETTING, (UINT_PTR)"cpopup", 1,
+ 0, LPGENT("Automatically switch existing tabs in minimized windows on incoming messages (ignored when using Aero Peek task bar features)"), 1, LOI_TYPE_SETTING, (UINT_PTR)"autoswitchtabs", 1,
+ 0, LPGENT("Remember and set keyboard layout per contact"), 1, LOI_TYPE_SETTING, (UINT_PTR)"al", 2,
+ 0, LPGENT("Close button only hides message windows"), 0, LOI_TYPE_SETTING, (UINT_PTR)"hideonclose", 2,
+ 0, LPGENT("Allow TAB key in typing area (this will disable focus selection by TAB key)"), 0, LOI_TYPE_SETTING, (UINT_PTR)"tabmode", 2,
+ 0, LPGENT("Add offline contacts to multisend list"),0,LOI_TYPE_SETTING,(UINT_PTR) "AllowOfflineMultisend", 2,
+ 0, NULL, 0, 0, 0, 0
+};
+
+
+TOptionListItem* CTranslator::getTree(UINT id)
+{
+ switch(id) {
+ case TREE_MODPLUS:
+ return(m_lvItemsModPlus);
+ case TREE_NEN:
+ return(m_lvItemsNEN);
+ case TREE_MSG:
+ return(m_lvItemsMsg);
+ case TREE_LOG:
+ return(m_lvItemsLog);
+ case TREE_TAB:
+ return(m_lvItemsTab);
+ default:
+ return(0);
+ }
+}
+
+TOptionListGroup* CTranslator::getGroupTree(UINT id)
+{
+ switch(id) {
+ case TREE_MODPLUS:
+ return(m_lvGroupsModPlus);
+ case TREE_NEN:
+ return(m_lvGroupsNEN);
+ case TREE_MSG:
+ return(m_lvGroupsMsg);
+ case TREE_LOG:
+ return(m_lvGroupsLog);
+ case TREE_TAB:
+ return(m_lvGroupsTab);
+ default:
+ return(0);
+ }
+}
+
+void CTranslator::translateGroupTree(TOptionListGroup *lvGroup)
+{
+ UINT i = 0;
+
+ while(lvGroup[i].szName) {
+ lvGroup[i].szName = TranslateTS(lvGroup[i].szName);
+ i++;
+ }
+}
+
+void CTranslator::translateOptionTree(TOptionListItem *lvItems)
+{
+ UINT i = 0;
+
+ while(lvItems[i].szName) {
+ lvItems[i].szName = TranslateTS(lvItems[i].szName);
+ i++;
+ }
+}
diff --git a/plugins/TabSRMM/src/trayicon.cpp b/plugins/TabSRMM/src/trayicon.cpp
new file mode 100644
index 0000000000..28de552468
--- /dev/null
+++ b/plugins/TabSRMM/src/trayicon.cpp
@@ -0,0 +1,374 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * This code is based on and still contains large parts of the the
+ * original chat module for Miranda IM, written and copyrighted
+ * by Joergen Persson in 2005.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: trayicon.cpp 13447 2011-03-14 19:55:07Z george.hazan $
+ *
+ * The code that creates and animates the tray icon.
+ *
+ */
+
+#include "commonheaders.h"
+#pragma hdrstop
+//#include "m_toptoolbar.h"
+
+static BOOL isAnimThreadRunning = TRUE;
+static HANDLE hTrayAnimThread = 0;
+static HICON hIconTrayCurrent = 0;
+HANDLE g_hEvent = 0;
+
+static TCHAR g_eventName[100];
+
+static unsigned __stdcall TrayAnimThread(LPVOID vParam)
+{
+ int iAnimMode = (PluginConfig.m_AnimTrayIcons[0] && PluginConfig.m_AnimTrayIcons[1] && PluginConfig.m_AnimTrayIcons[2] &&
+ PluginConfig.m_AnimTrayIcons[3]);
+ DWORD dwElapsed = 0, dwAnimStep = 0;
+ HICON hIconDefault = iAnimMode ? PluginConfig.m_AnimTrayIcons[0] : PluginConfig.g_iconContainer;
+ DWORD idleTimer = 0;
+ HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, g_eventName);
+
+ do {
+ if (isAnimThreadRunning && PluginConfig.m_UnreadInTray == 0) {
+ if (hIconTrayCurrent != hIconDefault)
+ FlashTrayIcon(hIconDefault); // restore default icon
+ PluginConfig.m_TrayFlashState = 0;
+
+ dwElapsed = 0;
+ dwAnimStep = 0;
+ WaitForSingleObject(hEvent, 30000);
+ ResetEvent(hEvent);
+ idleTimer += 2000;
+ }
+ if (!isAnimThreadRunning) {
+ if (hIconTrayCurrent != hIconDefault)
+ FlashTrayIcon(hIconDefault); // restore default icon
+ PluginConfig.m_TrayFlashState = 0;
+ break;
+ }
+ if (PluginConfig.m_UnreadInTray) {
+ if (iAnimMode) {
+ dwAnimStep++;
+ if (dwAnimStep > 3)
+ dwAnimStep = 0;
+ FlashTrayIcon(PluginConfig.m_AnimTrayIcons[dwAnimStep]); // restore default icon
+ }
+ else { // simple flashing
+ dwElapsed += 200;
+ if (dwElapsed >= 600) {
+ PluginConfig.m_TrayFlashState = !PluginConfig.m_TrayFlashState;
+ dwElapsed = 0;
+ FlashTrayIcon(PluginConfig.m_TrayFlashState ? 0 : hIconDefault); // restore default icon
+ }
+ }
+ Sleep(200);
+ idleTimer += 200;
+ }
+ if (idleTimer >= 2000) {
+ idleTimer = 0;
+ }
+ }
+ while (isAnimThreadRunning);
+ CloseHandle(hEvent);
+ return 0;
+}
+
+void TSAPI CreateTrayMenus(int mode)
+{
+ if (mode) {
+ mir_sntprintf(g_eventName, 100, _T("tsr_evt_%d"), GetCurrentThreadId());
+ g_hEvent = CreateEvent(NULL, FALSE, FALSE, g_eventName);
+ isAnimThreadRunning = TRUE;
+ hTrayAnimThread = (HANDLE)mir_forkthreadex(TrayAnimThread, NULL, 16000, NULL);
+
+ PluginConfig.g_hMenuTrayUnread = CreatePopupMenu();
+ PluginConfig.g_hMenuFavorites = CreatePopupMenu();
+ PluginConfig.g_hMenuRecent = CreatePopupMenu();
+ PluginConfig.g_hMenuTrayContext = GetSubMenu(PluginConfig.g_hMenuContext, 6);
+ ModifyMenu(PluginConfig.g_hMenuTrayContext, 0, MF_BYPOSITION | MF_POPUP,
+ (UINT_PTR)PluginConfig.g_hMenuFavorites, CTranslator::get(CTranslator::GEN_FAVORITES));
+ ModifyMenu(PluginConfig.g_hMenuTrayContext, 2, MF_BYPOSITION | MF_POPUP,
+ (UINT_PTR)PluginConfig.g_hMenuRecent, CTranslator::get(CTranslator::GEN_RECENT_SESSIONS));
+ LoadFavoritesAndRecent();
+ }
+ else {
+ isAnimThreadRunning = FALSE;
+ SetEvent(g_hEvent);
+ WaitForSingleObject(hTrayAnimThread, 5000);
+ CloseHandle(hTrayAnimThread);
+ CloseHandle(g_hEvent);
+ g_hEvent = 0;
+ hTrayAnimThread = 0;
+ if (PluginConfig.g_hMenuTrayUnread != 0) {
+ DestroyMenu(PluginConfig.g_hMenuTrayUnread);
+ PluginConfig.g_hMenuTrayUnread = 0;
+ }
+ if (PluginConfig.g_hMenuFavorites != 0) {
+ DestroyMenu(PluginConfig.g_hMenuFavorites);
+ PluginConfig.g_hMenuFavorites = 0;
+ }
+ if (PluginConfig.g_hMenuRecent != 0) {
+ DestroyMenu(PluginConfig.g_hMenuRecent);
+ PluginConfig.g_hMenuRecent = 0;
+ }
+ }
+}
+/*
+ * create a system tray icon, create all necessary submenus
+ */
+
+void TSAPI CreateSystrayIcon(int create)
+{
+ NOTIFYICONDATA nim;
+
+ nim.cbSize = sizeof(nim);
+ nim.hWnd = PluginConfig.g_hwndHotkeyHandler;
+ nim.uID = 100;
+ nim.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nim.hIcon = PluginConfig.g_iconContainer;
+ nim.uCallbackMessage = DM_TRAYICONNOTIFY;
+ mir_sntprintf(nim.szTip, 64, _T("%s"), _T("tabSRMM"));
+ if (create && !nen_options.bTrayExist) {
+ Shell_NotifyIcon(NIM_ADD, &nim);
+ nen_options.bTrayExist = TRUE;
+ hIconTrayCurrent = 0;
+ SetEvent(g_hEvent);
+ }
+ else if (create == FALSE && nen_options.bTrayExist) {
+ Shell_NotifyIcon(NIM_DELETE, &nim);
+ nen_options.bTrayExist = FALSE;
+ }
+}
+
+static BOOL CALLBACK FindTrayWnd(HWND hwnd, LPARAM lParam)
+{
+ TCHAR szClassName[256];
+ GetClassName(hwnd, szClassName, 255);
+
+ if (_tcscmp(szClassName, _T("TrayNotifyWnd")) == 0) {
+ RECT *pRect = (RECT *) lParam;
+ GetWindowRect(hwnd, pRect);
+ return TRUE;
+ }
+ if (_tcscmp(szClassName, _T("TrayClockWClass")) == 0) {
+ RECT *pRect = (RECT *) lParam;
+ RECT rectClock;
+ GetWindowRect(hwnd, &rectClock);
+ if (rectClock.bottom < pRect->bottom - 5) // 10 = random fudge factor.
+ pRect->top = rectClock.bottom;
+ else
+ pRect->right = rectClock.left;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void GetTrayWindowRect(LPRECT lprect)
+{
+ HWND hShellTrayWnd = FindWindow(_T("Shell_TrayWnd"), NULL);
+ if (hShellTrayWnd) {
+ GetWindowRect(hShellTrayWnd, lprect);
+ EnumChildWindows(hShellTrayWnd, FindTrayWnd, (LPARAM)lprect);
+ return;
+ }
+}
+
+/*
+ * flash the tray icon
+ * mode = 0 - continue to flash
+ * mode = 1 - restore the original icon
+ */
+
+void TSAPI FlashTrayIcon(HICON hIcon)
+{
+ NOTIFYICONDATA nim;
+
+ hIconTrayCurrent = hIcon;
+
+ if (nen_options.bTraySupport) {
+ nim.cbSize = sizeof(nim);
+ nim.hWnd = PluginConfig.g_hwndHotkeyHandler;
+ nim.uID = 100;
+ nim.uFlags = NIF_ICON;
+ nim.hIcon = hIcon;
+ Shell_NotifyIcon(NIM_MODIFY, &nim);
+ }
+}
+
+/*
+ * add a contact to recent or favorites menu
+ * mode = 1, add
+ * mode = 0, only modify it..
+ * hMenu specifies the menu handle (the menus are identical...)
+ * cares about updating the menu entry. It sets the hIcon (proto status icon) in
+ * dwItemData of the the menu entry, so that the WM_DRAWITEM handler can retrieve it
+ * w/o costly service calls.
+ *
+ * Also, the function does housekeeping on the Recent Sessions menu to enforce the
+ * maximum number of allowed entries (20 at the moment). The oldest (topmost) entry
+ * is deleted, if necessary.
+ */
+
+void TSAPI AddContactToFavorites(HANDLE hContact, const TCHAR *szNickname, const char *szProto, TCHAR *szStatus, WORD wStatus, HICON hIcon, BOOL mode, HMENU hMenu)
+{
+ MENUITEMINFO mii = {0};
+ TCHAR szMenuEntry[80];
+ TCHAR szFinalNick[100];
+
+ if (szNickname == NULL) {
+ mir_sntprintf(szFinalNick, safe_sizeof(szFinalNick), _T("%s"), (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR));
+ }
+ else {
+ _tcsncpy(szFinalNick, szNickname, 100);
+ szFinalNick[99] = 0;
+ }
+
+ if (szProto == NULL)
+ szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (szProto) {
+ if (wStatus == 0)
+ wStatus = DBGetContactSettingWord((HANDLE)hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ if (szStatus == NULL)
+ szStatus = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, wStatus, GSMDF_TCHAR);
+ }
+ else
+ return;
+
+ if (hIcon == 0)
+ hIcon = LoadSkinnedProtoIcon(szProto, wStatus);
+
+ PROTOACCOUNT *acc = (PROTOACCOUNT *)CallService(MS_PROTO_GETACCOUNT, (WPARAM)0, (LPARAM)szProto);
+
+ if(acc && acc->tszAccountName) {
+ mii.cbSize = sizeof(mii);
+ mir_sntprintf(szMenuEntry, safe_sizeof(szMenuEntry), _T("%s: %s (%s)"), acc->tszAccountName, szFinalNick, szStatus);
+ if (mode) {
+ if (hMenu == PluginConfig.g_hMenuRecent) {
+ if (CheckMenuItem(hMenu, (UINT_PTR)hContact, MF_BYCOMMAND | MF_UNCHECKED) == 0) {
+ DeleteMenu(hMenu, (UINT_PTR)hContact, MF_BYCOMMAND);
+ goto addnew; // move to the end of the menu...
+ }
+ if (GetMenuItemCount(PluginConfig.g_hMenuRecent) > nen_options.wMaxRecent) { // throw out oldest entry in the recent menu...
+ UINT uid = GetMenuItemID(hMenu, 0);
+ if (uid) {
+ DeleteMenu(hMenu, (UINT_PTR)0, MF_BYPOSITION);
+ M->WriteDword((HANDLE)uid, SRMSGMOD_T, "isRecent", 0);
+ }
+ }
+ addnew:
+ M->WriteDword(hContact, SRMSGMOD_T, "isRecent", time(NULL));
+ AppendMenu(hMenu, MF_BYCOMMAND, (UINT_PTR)hContact, szMenuEntry);
+ }
+ else if (hMenu == PluginConfig.g_hMenuFavorites) { // insert the item sorted...
+ MENUITEMINFO mii2 = {0};
+ TCHAR szBuffer[142];
+ int i, c = GetMenuItemCount(PluginConfig.g_hMenuFavorites);
+ mii2.fMask = MIIM_STRING;
+ mii2.cbSize = sizeof(mii2);
+ if (c == 0)
+ InsertMenu(PluginConfig.g_hMenuFavorites, 0, MF_BYPOSITION, (UINT_PTR)hContact, szMenuEntry);
+ else {
+ for (i = 0; i <= c; i++) {
+ mii2.cch = 0;
+ mii2.dwTypeData = NULL;
+ GetMenuItemInfo(PluginConfig.g_hMenuFavorites, i, TRUE, &mii2);
+ mii2.cch++;
+ mii2.dwTypeData = szBuffer;
+ GetMenuItemInfo(PluginConfig.g_hMenuFavorites, i, TRUE, &mii2);
+ if (_tcsncmp((TCHAR *)mii2.dwTypeData, szMenuEntry, 140) > 0 || i == c) {
+ InsertMenu(PluginConfig.g_hMenuFavorites, i, MF_BYPOSITION, (UINT_PTR)hContact, szMenuEntry);
+ break;
+ }
+ }
+ }
+ }
+ }
+ mii.fMask = MIIM_BITMAP | MIIM_DATA;
+ if (!mode) {
+ mii.fMask |= MIIM_STRING;
+ mii.dwTypeData = (LPTSTR)szMenuEntry;
+ mii.cch = lstrlen(szMenuEntry) + 1;
+ }
+ mii.hbmpItem = HBMMENU_CALLBACK;
+ mii.dwItemData = (ULONG_PTR)hIcon;
+ SetMenuItemInfo(hMenu, (UINT)hContact, FALSE, &mii);
+ }
+}
+
+/*
+ * called by CreateSysTrayIcon(), usually on startup or when you activate tray support
+ * at runtime.
+ * scans the contact db for favorites or recent session entries and builds the menus.
+ */
+
+typedef struct _recentEntry {
+ DWORD dwTimestamp;
+ HANDLE hContact;
+} RCENTRY;
+
+void TSAPI LoadFavoritesAndRecent()
+{
+ RCENTRY *recentEntries, rceTemp;
+ DWORD dwRecent;
+ int iIndex = 0, i, j;
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ recentEntries = new RCENTRY[nen_options.wMaxRecent + 1];
+ if (recentEntries != NULL) {
+ while (hContact != 0) {
+ if (M->GetByte(hContact, SRMSGMOD_T, "isFavorite", 0))
+ AddContactToFavorites(hContact, NULL, NULL, NULL, 0, 0, 1, PluginConfig.g_hMenuFavorites);
+ if ((dwRecent = M->GetDword(hContact, "isRecent", 0)) != 0 && iIndex < nen_options.wMaxRecent) {
+ recentEntries[iIndex].dwTimestamp = dwRecent;
+ recentEntries[iIndex++].hContact = hContact;
+ }
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+ if (iIndex == 0) {
+ free(recentEntries);
+ return;
+ }
+
+ for (i = 0; i < iIndex - 1; i++) {
+ for (j = 0; j < iIndex - 1; j++) {
+ if (recentEntries[j].dwTimestamp > recentEntries[j+1].dwTimestamp) {
+ rceTemp = recentEntries[j];
+ recentEntries[j] = recentEntries[j+1];
+ recentEntries[j+1] = rceTemp;
+ }
+ }
+ }
+ for (i = 0; i < iIndex; i++)
+ AddContactToFavorites(recentEntries[i].hContact, NULL, NULL, NULL, 0, 0, 1, PluginConfig.g_hMenuRecent);
+
+ delete[] recentEntries;
+ }
+}
+
diff --git a/plugins/TabSRMM/src/typingnotify.cpp b/plugins/TabSRMM/src/typingnotify.cpp
new file mode 100644
index 0000000000..ac6550c01f
--- /dev/null
+++ b/plugins/TabSRMM/src/typingnotify.cpp
@@ -0,0 +1,573 @@
+#include "commonheaders.h"
+#pragma hdrstop
+HANDLE hTypingNotify;
+
+static INT_PTR EnableDisableMenuCommand(WPARAM wParam,LPARAM lParam)
+{
+ Disabled = !(Disabled);
+
+ if (PopupService) {
+
+ CLISTMENUITEM mi = { 0 };
+
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_ICON | CMIM_NAME;
+
+ if (!Disabled) {
+ mi.pszName = LPGEN("Disable &typing notification");
+ mi.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ENABLED));
+ } else {
+ mi.pszName = LPGEN("Enable &typing notification");
+ mi.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_DISABLED));
+ }
+
+ CallService(MS_CLIST_MODIFYMENUITEM,(WPARAM)hDisableMenu,(LPARAM)&mi);
+ }
+
+ return 0;
+}
+
+static int CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_COMMAND:
+ if (HIWORD(wParam) == STN_CLICKED) {
+ HANDLE hContact = PUGetContact(hWnd);
+ CallService(MS_MSG_SENDMESSAGE "W",(WPARAM)hContact,0);
+ PUDeletePopUp(hWnd);
+ return 1;
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ PUDeletePopUp(hWnd);
+ return 1;
+
+ case UM_INITPOPUP: {
+ HANDLE hContact = PUGetContact(hWnd);
+ WindowList_Add(hPopUpsList, hWnd, hContact);
+ }
+ return 1;
+
+ case UM_FREEPLUGINDATA:
+ WindowList_Remove(hPopUpsList, hWnd);
+ return 1;
+ default:
+ break;
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+int TN_TypingMessage(WPARAM wParam, LPARAM lParam)
+{
+ POPUPDATAT_V2 ppd = { 0 };
+ TCHAR *szContactName = NULL;
+ HWND hPopUpWnd = NULL;
+ int notyping;
+
+ // hidden & ignored contacts check
+ if (M->GetByte((HANDLE)wParam, "CList", "Hidden", 0) || (M->GetDword((HANDLE)wParam, "Ignore", "Mask1",0) & 1)) // 9 - online notification
+ return 0;
+
+ szContactName = (TCHAR*) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, wParam, GSMDF_TCHAR);
+
+ if (PopupService && !Disabled) {
+ if (OnePopUp) {
+ hPopUpWnd = WindowList_Find(hPopUpsList, (HANDLE) wParam);
+ while (hPopUpWnd) {
+ PUDeletePopUp(hPopUpWnd);
+ hPopUpWnd = WindowList_Find(hPopUpsList, (HANDLE) wParam);
+ }
+ }
+
+ switch (lParam) {
+ case PROTOTYPE_CONTACTTYPING_OFF:
+ if (StopDisabled)
+ return 0;
+ lstrcpyn(ppd.lptzContactName, szContactName, MAX_CONTACTNAME);
+ lstrcpyn(ppd.lptzText, szStop, MAX_SECONDLINE);
+ ppd.hNotification = hntfStopped;
+ notyping = 1;
+ break;
+ default:
+ if (StartDisabled)
+ return 0;
+ lstrcpyn(ppd.lptzContactName, szContactName, MAX_CONTACTNAME);
+ lstrcpyn(ppd.lptzText, szStart, MAX_SECONDLINE);
+ ppd.hNotification = hntfStarted;
+ notyping = 0;
+ break;
+ }
+
+ switch (ColorMode) {
+ case COLOR_OWN:
+ ppd.colorBack = colorPicker[2* notyping ].color;
+ ppd.colorText = colorPicker[2* notyping + 1].color;
+ break;
+ case COLOR_WINDOWS:
+ ppd.colorBack = GetSysColor(COLOR_BTNFACE);
+ ppd.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ break;
+ case COLOR_POPUP:
+ default:
+ ppd.colorBack = ppd.colorText = 0;
+ break;
+ }
+
+ if (notyping)
+ switch (TimeoutMode2) {
+ case TIMEOUT_CUSTOM:
+ ppd.iSeconds = Timeout2;
+ break;
+ case TIMEOUT_PERMANENT:
+ ppd.iSeconds = -1;
+ break;
+ case TIMEOUT_POPUP:
+ default:
+ ppd.iSeconds = 0;
+ break;
+ }
+ else
+ switch (TimeoutMode) {
+ case TIMEOUT_CUSTOM:
+ ppd.iSeconds = Timeout;
+ break;
+ case TIMEOUT_PROTO:
+ ppd.iSeconds = (DWORD) lParam;
+ break;
+ case TIMEOUT_PERMANENT:
+ ppd.iSeconds = -1;
+ break;
+ case TIMEOUT_POPUP:
+ default:
+ ppd.iSeconds = 0;
+ break;
+ }
+
+ ppd.lchIcon = PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING];
+ ppd.lchContact = (HANDLE) wParam;
+ ppd.PluginWindowProc = (WNDPROC) PopupDlgProc;
+ ppd.PluginData = NULL;
+
+ ppd.cbSize = sizeof(ppd);
+
+ CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&ppd, APF_NEWDATA);
+ }
+ return 0;
+}
+
+static INT_PTR CALLBACK DlgProcOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WORD i;
+
+ switch (msg) {
+ case WM_INITDIALOG: {
+ TranslateDialogDefault(hwndDlg);
+
+ if (!ServiceExists(MS_POPUP_ADDPOPUPT))
+ SetDlgItemText(hwndDlg, IDC_INFO, CTranslator::get(CTranslator::GEN_MTN_POPUP_WARNING));
+ else if (!PopupService)
+ SetDlgItemText(hwndDlg, IDC_INFO, CTranslator::get(CTranslator::GEN_MTN_POPUP_UNSUPPORTED));
+ if (ColorMode == COLOR_WINDOWS) {
+ CheckDlgButton(hwndDlg, IDC_USEWINCOLORS, BST_CHECKED);
+ Utils::enableDlgControl(hwndDlg, IDC_USEPOPUPCOLORS, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_USEWINCOLORS, TRUE);
+ CheckDlgButton(hwndDlg, IDC_USEPOPUPCOLORS, BST_UNCHECKED);
+ } else if (ColorMode == COLOR_POPUP) {
+ CheckDlgButton(hwndDlg, IDC_USEWINCOLORS, BST_UNCHECKED);
+ Utils::enableDlgControl(hwndDlg, IDC_USEWINCOLORS, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_USEPOPUPCOLORS, TRUE);
+ CheckDlgButton(hwndDlg, IDC_USEPOPUPCOLORS, BST_CHECKED);
+ }
+
+ for (i = 0; i < sizeof(colorPicker) / sizeof(colorPicker[0]); i++) {
+ SendDlgItemMessage(hwndDlg, colorPicker[i].res, CPM_SETCOLOUR, 0, colorPicker[i].color);
+ Utils::enableDlgControl(hwndDlg, colorPicker[i].res, (ColorMode == COLOR_OWN));
+ }
+
+ CheckDlgButton(hwndDlg, IDC_TIMEOUT_PERMANENT, (TimeoutMode == TIMEOUT_PERMANENT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_TIMEOUT_POPUP, (TimeoutMode == TIMEOUT_POPUP) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_TIMEOUT_PROTO, (TimeoutMode == TIMEOUT_PROTO) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_TIMEOUT_CUSTOM, (TimeoutMode == TIMEOUT_CUSTOM) ? BST_CHECKED : BST_UNCHECKED);
+ SetDlgItemInt(hwndDlg, IDC_TIMEOUT_VALUE, Timeout, 0);
+ Utils::enableDlgControl(hwndDlg, IDC_TIMEOUT_VALUE, TimeoutMode == TIMEOUT_CUSTOM);
+
+ CheckDlgButton(hwndDlg, IDC_TIMEOUT_PERMANENT2, (TimeoutMode2 == TIMEOUT_PERMANENT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_TIMEOUT_POPUP2, (TimeoutMode2 == TIMEOUT_POPUP) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_TIMEOUT_CUSTOM2, (TimeoutMode2 == TIMEOUT_CUSTOM) ? BST_CHECKED : BST_UNCHECKED);
+ SetDlgItemInt(hwndDlg, IDC_TIMEOUT_VALUE2, Timeout2, 0);
+ Utils::enableDlgControl(hwndDlg, IDC_TIMEOUT_VALUE2, TimeoutMode2 == TIMEOUT_CUSTOM);
+
+ CheckDlgButton(hwndDlg, IDC_START, (StartDisabled) ? BST_UNCHECKED : BST_CHECKED);
+ CheckDlgButton(hwndDlg, IDC_STOP, (StopDisabled) ? BST_UNCHECKED : BST_CHECKED);
+
+ CheckDlgButton(hwndDlg, IDC_ONEPOPUP, (OnePopUp) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SHOWMENU, (ShowMenu) ? BST_CHECKED : BST_UNCHECKED);
+
+ Utils::enableDlgControl(hwndDlg, IDC_ONEPOPUP, PopupService);
+ Utils::enableDlgControl(hwndDlg, IDC_SHOWMENU, PopupService);
+ Utils::enableDlgControl(hwndDlg, IDC_PREVIEW, PopupService/*&&!ServiceExists(MS_POPUP_REGISTERNOTIFICATION)*/);
+
+ newTimeout = Timeout;
+ newTimeoutMode = TimeoutMode;
+ newTimeout2 = Timeout2;
+ newTimeoutMode2 = TimeoutMode2;
+ newColorMode = ColorMode;
+ }
+ break;
+
+ case WM_COMMAND: {
+ WORD idCtrl = LOWORD(wParam), wNotifyCode = HIWORD(wParam);
+
+ if (wNotifyCode == CPN_COLOURCHANGED) {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ return TRUE;
+ }
+
+ switch (idCtrl) {
+ case IDC_USEWINCOLORS: {
+ BOOL bEnableOthers = FALSE;
+
+ if (wNotifyCode != BN_CLICKED)
+ break;
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_USEWINCOLORS)) {
+ newColorMode = COLOR_WINDOWS;
+ bEnableOthers = FALSE;
+ } else {
+ newColorMode = COLOR_OWN;
+ bEnableOthers = TRUE;
+ }
+
+ for (i = 0; i < sizeof(colorPicker) / sizeof(colorPicker[0]); i++)
+ Utils::enableDlgControl(hwndDlg, colorPicker[i].res, bEnableOthers);
+
+ Utils::enableDlgControl(hwndDlg, IDC_USEPOPUPCOLORS, bEnableOthers);
+
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ case IDC_USEPOPUPCOLORS: {
+ BOOL bEnableOthers = FALSE;
+ if (wNotifyCode != BN_CLICKED)
+ break;
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_USEPOPUPCOLORS)) {
+ newColorMode = COLOR_POPUP;
+ bEnableOthers = FALSE;
+ } else {
+ newColorMode = COLOR_OWN;
+ bEnableOthers = TRUE;
+ }
+
+ for (i = 0; i < sizeof(colorPicker) / sizeof(colorPicker[0]); i++)
+ Utils::enableDlgControl(hwndDlg, colorPicker[i].res, bEnableOthers);
+
+ Utils::enableDlgControl(hwndDlg, IDC_USEWINCOLORS, bEnableOthers);
+
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ case IDC_ONEPOPUP:
+ case IDC_CLIST:
+ case IDC_DISABLED:
+ case IDC_SHOWMENU:
+ case IDC_START:
+ case IDC_STOP:
+ case IDC_WOCL:
+ if (wNotifyCode == BN_CLICKED)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_PREVIEW: {
+ POPUPDATAT_V2 ppd = { 0 };
+ char *szProto = NULL;
+ int i, notyping;
+
+ HANDLE hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+
+ if (!PopupService)
+ break;
+
+ while (hContact) {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (szProto != NULL)
+ break;
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+
+ for (i = 0; i < 2; i++) {
+
+ switch (i) {
+ case PROTOTYPE_CONTACTTYPING_OFF:
+ lstrcpy(ppd.lptzContactName, CTranslator::get(CTranslator::GEN_CONTACT));
+ lstrcpyn(ppd.lptzText, szStop, MAX_SECONDLINE);
+ notyping = 1;
+ break;
+ default:
+ lstrcpy(ppd.lptzContactName, CTranslator::get(CTranslator::GEN_CONTACT));
+ lstrcpyn(ppd.lptzText, szStart, MAX_SECONDLINE);
+ notyping = 0;
+ break;
+ }
+
+ switch (newColorMode) {
+ case COLOR_OWN:
+ ppd.colorText = SendDlgItemMessage(hwndDlg, colorPicker[2* notyping + 1].res, CPM_GETCOLOUR, 0, 0);
+ ppd.colorBack = SendDlgItemMessage(hwndDlg, colorPicker[2* notyping ].res, CPM_GETCOLOUR, 0, 0);
+ break;
+ case COLOR_WINDOWS:
+ ppd.colorBack = GetSysColor(COLOR_BTNFACE);
+ ppd.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ break;
+ case COLOR_POPUP:
+ default:
+ ppd.colorBack = ppd.colorText = 0;
+ break;
+ }
+
+ if (notyping)
+ switch (newTimeoutMode2) {
+ case TIMEOUT_CUSTOM:
+ ppd.iSeconds = newTimeout2;
+ break;
+ case TIMEOUT_PERMANENT:
+ ppd.iSeconds = -1;
+ break;
+ case TIMEOUT_POPUP:
+ default:
+ ppd.iSeconds = 0;
+ break;
+ }
+ else
+ switch (newTimeoutMode) {
+ case TIMEOUT_CUSTOM:
+ ppd.iSeconds = newTimeout;
+ break;
+ case TIMEOUT_PROTO:
+ ppd.iSeconds = 10;
+ break;
+ case TIMEOUT_PERMANENT:
+ ppd.iSeconds = -1;
+ break;
+ case TIMEOUT_POPUP:
+ default:
+ ppd.iSeconds = 0;
+ break;
+ }
+
+ ppd.lchIcon = PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING];
+ ppd.lchContact = (HANDLE) wParam;
+ ppd.PluginWindowProc = NULL;
+ ppd.PluginData = NULL;
+
+ CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&ppd, 0);
+
+ }
+ break;
+ }
+ case IDC_TIMEOUT_POPUP2:
+ if (wNotifyCode != BN_CLICKED)
+ break;
+ newTimeoutMode2 = TIMEOUT_POPUP;
+ Utils::enableDlgControl(hwndDlg, IDC_TIMEOUT_VALUE2, 0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_TIMEOUT_CUSTOM2:
+ if (wNotifyCode != BN_CLICKED)
+ break;
+ newTimeoutMode2 = TIMEOUT_CUSTOM;
+ Utils::enableDlgControl(hwndDlg, IDC_TIMEOUT_VALUE2, 1);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_TIMEOUT_POPUP:
+ if (wNotifyCode != BN_CLICKED)
+ break;
+ newTimeoutMode = TIMEOUT_POPUP;
+ Utils::enableDlgControl(hwndDlg, IDC_TIMEOUT_VALUE, 0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_TIMEOUT_PERMANENT:
+ if (wNotifyCode != BN_CLICKED)
+ break;
+ newTimeoutMode = TIMEOUT_PERMANENT;
+ Utils::enableDlgControl(hwndDlg, IDC_TIMEOUT_VALUE, 0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_TIMEOUT_PERMANENT2:
+ if (wNotifyCode != BN_CLICKED)
+ break;
+ newTimeoutMode2 = TIMEOUT_PERMANENT;
+ Utils::enableDlgControl(hwndDlg, IDC_TIMEOUT_VALUE2, 0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_TIMEOUT_CUSTOM:
+ if (wNotifyCode != BN_CLICKED)
+ break;
+ newTimeoutMode = TIMEOUT_CUSTOM;
+ Utils::enableDlgControl(hwndDlg, IDC_TIMEOUT_VALUE, 1);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_TIMEOUT_PROTO:
+ if (wNotifyCode != BN_CLICKED)
+ break;
+ newTimeoutMode = TIMEOUT_PROTO;
+ Utils::enableDlgControl(hwndDlg, IDC_TIMEOUT_VALUE, 0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_TIMEOUT_VALUE:
+ case IDC_TIMEOUT_VALUE2: {
+ int newValue = GetDlgItemInt(hwndDlg, idCtrl, NULL, 0);
+
+ if (wNotifyCode == EN_KILLFOCUS) {
+ int oldValue;
+
+ if (idCtrl == IDC_TIMEOUT_VALUE)
+ oldValue = newTimeout;
+ else
+ oldValue = newTimeout2;
+
+ if (newValue != oldValue)
+ SetDlgItemInt(hwndDlg, idCtrl, oldValue, 0);
+ return TRUE;
+ }
+ if (wNotifyCode != EN_CHANGE || (HWND) lParam != GetFocus())
+ return TRUE;
+
+ if (newValue > TIMEOUT_MAXVALUE)
+ newValue = TIMEOUT_MAXVALUE;
+ else if (newValue < TIMEOUT_MINVALUE)
+ newValue = TIMEOUT_MINVALUE;
+
+ if (idCtrl == IDC_TIMEOUT_VALUE)
+ newTimeout = newValue;
+ else
+ newTimeout2 = newValue;
+
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+
+ }
+ break;
+ }
+ case WM_NOTIFY: {
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ for (i = 0; i < sizeof(colorPicker) / sizeof(colorPicker[0]); i++) {
+ colorPicker[i].color = SendDlgItemMessage(hwndDlg, colorPicker[i].res, CPM_GETCOLOUR, 0, 0);
+ M->WriteDword(Module, colorPicker[i].desc, colorPicker[i].color);
+ }
+
+ Timeout = newTimeout;
+ TimeoutMode = newTimeoutMode;
+ Timeout2 = newTimeout2;
+ TimeoutMode2 = newTimeoutMode2;
+ ColorMode = newColorMode;
+
+ if (Disabled != IsDlgButtonChecked(hwndDlg, IDC_DISABLED))
+ EnableDisableMenuCommand(0, 0);
+
+ StartDisabled = IsDlgButtonChecked(hwndDlg, IDC_START) ? 0 : 2;
+ StopDisabled = IsDlgButtonChecked(hwndDlg, IDC_STOP) ? 0 : 4;
+ OnePopUp = IsDlgButtonChecked(hwndDlg, IDC_ONEPOPUP);
+ ShowMenu = IsDlgButtonChecked(hwndDlg, IDC_SHOWMENU);
+
+ M->WriteByte(Module, SET_ONEPOPUP, OnePopUp);
+ M->WriteByte(Module, SET_SHOWDISABLEMENU, ShowMenu);
+ M->WriteByte(Module, SET_DISABLED, (BYTE) (StartDisabled | StopDisabled));
+ M->WriteByte(Module, SET_COLOR_MODE, ColorMode);
+ M->WriteByte(Module, SET_TIMEOUT_MODE, TimeoutMode);
+ M->WriteByte(Module, SET_TIMEOUT, (BYTE) Timeout);
+ M->WriteByte(Module, SET_TIMEOUT_MODE2, TimeoutMode2);
+ M->WriteByte(Module, SET_TIMEOUT2, (BYTE) Timeout2);
+
+ return TRUE;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+int TN_OptionsInitialize(WPARAM wParam, LPARAM lParam)
+{
+
+ OPTIONSDIALOGPAGE odp = { 0 };
+
+ if (PluginConfig.g_PopupAvail) {
+ odp.cbSize = sizeof(odp);
+ odp.position = 100000000;
+ odp.hInstance = g_hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_TYPINGNOTIFYPOPUP);
+ odp.pszTitle = LPGEN("Typing Notify");
+ odp.pszGroup = LPGEN("PopUps");
+ odp.groupPosition = 910000000;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.pfnDlgProc = DlgProcOpts;
+ CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp);
+ }
+ return 0;
+}
+
+int TN_ModuleInit()
+{
+ WORD i;
+
+ PopupService = (PluginConfig.g_PopupWAvail || PluginConfig.g_PopupAvail);
+
+ hPopUpsList = (HANDLE) CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+
+ OnePopUp = M->GetByte(Module,SET_ONEPOPUP,DEF_ONEPOPUP);
+ ShowMenu = M->GetByte(Module,SET_SHOWDISABLEMENU,DEF_SHOWDISABLEMENU);
+
+ i = M->GetByte(Module,SET_DISABLED,DEF_DISABLED);
+ Disabled = i & 1;
+ StartDisabled = i & 2;
+ StopDisabled = i & 4;
+
+ ColorMode = M->GetByte(Module,SET_COLOR_MODE,DEF_COLOR_MODE);
+ TimeoutMode = M->GetByte(Module,SET_TIMEOUT_MODE,DEF_TIMEOUT_MODE);
+ Timeout = M->GetByte(Module,SET_TIMEOUT,DEF_TIMEOUT);
+ TimeoutMode2 = M->GetByte(Module,SET_TIMEOUT_MODE2,DEF_TIMEOUT_MODE2);
+ Timeout2 = M->GetByte(Module,SET_TIMEOUT2,DEF_TIMEOUT2);
+
+ if (!(M->GetDword(Module, colorPicker[0].desc, 1) && !M->GetDword(Module, colorPicker[0].desc, 0)))
+ for (i = 0; i < sizeof(colorPicker) / sizeof(colorPicker[0]); i++)
+ colorPicker[i].color = M->GetDword(Module,colorPicker[i].desc,0);
+
+ mir_sntprintf(szStart, sizeof(szStart), CTranslator::get(CTranslator::GEN_MTN_START));
+ mir_sntprintf(szStop, sizeof(szStop), CTranslator::get(CTranslator::GEN_MTN_STOP));
+
+ if (PopupService && ShowMenu) {
+ CLISTMENUITEM mi = { 0 };
+ hTypingNotify = CreateServiceFunction("TypingNotify/EnableDisableMenuCommand", EnableDisableMenuCommand);
+
+ mi.cbSize = sizeof(mi);
+ mi.flags = 0;
+
+ if (!Disabled) {
+ mi.pszName = LPGEN("Disable &typing notification");
+ mi.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ENABLED));
+ } else {
+ mi.pszName = LPGEN("Enable &typing notification");
+ mi.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_DISABLED));
+ }
+ mi.pszService = "TypingNotify/EnableDisableMenuCommand";
+ mi.pszPopupName = LPGEN("PopUps");
+ hDisableMenu = (HANDLE) CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ }
+ SkinAddNewSoundEx("TNStart", "Instant messages", "Contact started typing");
+ SkinAddNewSoundEx("TNStop", "Instant messages", "Contact stopped typing");
+
+ return 0;
+}
+
+int TN_ModuleDeInit()
+{
+ M->WriteByte(Module, SET_DISABLED, (BYTE) (Disabled | StartDisabled | StopDisabled));
+ return 0;
+}
diff --git a/plugins/TabSRMM/src/userprefs.cpp b/plugins/TabSRMM/src/userprefs.cpp
new file mode 100644
index 0000000000..5691e71a65
--- /dev/null
+++ b/plugins/TabSRMM/src/userprefs.cpp
@@ -0,0 +1,593 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: userprefs.cpp 12893 2010-10-04 06:19:57Z silvercircle $
+ *
+ *
+ * global/local message log options
+ * local (per user) template overrides
+ * view mode (ieview/default)
+ * text formatting
+ *
+ */
+
+#include "commonheaders.h"
+
+#pragma hdrstop
+#include <uxtheme.h>
+
+#define UPREF_ACTION_APPLYOPTIONS 1
+#define UPREF_ACTION_REMAKELOG 2
+#define UPREF_ACTION_SWITCHLOGVIEWER 4
+
+extern HANDLE hUserPrefsWindowList;
+extern struct TCpTable cpTable[];
+
+static HWND hCpCombo;
+
+static BOOL CALLBACK FillCpCombo(LPCTSTR str)
+{
+ int i;
+ UINT cp;
+
+ cp = _ttoi(str);
+ for (i = 0; cpTable[i].cpName != NULL && cpTable[i].cpId != cp; i++);
+ if (cpTable[i].cpName != NULL) {
+ LRESULT iIndex = SendMessage(hCpCombo, CB_ADDSTRING, -1, (LPARAM) TranslateTS(cpTable[i].cpName));
+ SendMessage(hCpCombo, CB_SETITEMDATA, (WPARAM)iIndex, cpTable[i].cpId);
+ }
+ return TRUE;
+}
+
+static int have_ieview = 0, have_hpp = 0;
+
+static INT_PTR CALLBACK DlgProcUserPrefs(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg) {
+ case WM_INITDIALOG: {
+ DWORD sCodePage;
+ int i;
+ DWORD maxhist = M->GetDword((HANDLE)lParam, "maxhist", 0);
+ BYTE bIEView = M->GetByte((HANDLE)lParam, "ieview", 0);
+ BYTE bHPP = M->GetByte((HANDLE)lParam, "hpplog", 0);
+ int iLocalFormat = M->GetDword((HANDLE)lParam, "sendformat", 0);
+ BYTE bRTL = M->GetByte((HANDLE)lParam, "RTL", 0);
+ BYTE bLTR = M->GetByte((HANDLE)lParam, "RTL", 1);
+ BYTE bSplit = M->GetByte((HANDLE)lParam, "splitoverride", 0);
+ BYTE bInfoPanel = M->GetByte((HANDLE)lParam, "infopanel", 0);
+ BYTE bAvatarVisible = M->GetByte((HANDLE)lParam, "hideavatar", -1);
+ char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)lParam, 0);
+ int def_log_index = 1, hpp_log_index = 1, ieview_log_index = 1;
+
+ have_ieview = ServiceExists(MS_IEVIEW_WINDOW);
+ have_hpp = ServiceExists("History++/ExtGrid/NewWindow");
+
+ hContact = (HANDLE)lParam;
+
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
+
+ SendDlgItemMessage(hwndDlg, IDC_INFOPANEL, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_IPGLOBAL));
+ SendDlgItemMessage(hwndDlg, IDC_INFOPANEL, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_IPON));
+ SendDlgItemMessage(hwndDlg, IDC_INFOPANEL, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_IPOFF));
+ SendDlgItemMessage(hwndDlg, IDC_INFOPANEL, CB_SETCURSEL, bInfoPanel == 0 ? 0 : (bInfoPanel == 1 ? 1 : 2), 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_SHOWAVATAR, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_IPGLOBAL));
+ SendDlgItemMessage(hwndDlg, IDC_SHOWAVATAR, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_AVON));
+ SendDlgItemMessage(hwndDlg, IDC_SHOWAVATAR, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_AVOFF));
+ SendDlgItemMessage(hwndDlg, IDC_SHOWAVATAR, CB_SETCURSEL, bAvatarVisible == 0xff ? 0 : (bAvatarVisible == 1 ? 1 : 2), 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_IPGLOBAL));
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_FORCEDEFAULT));
+
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_SETITEMDATA, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_SETITEMDATA, 1, 1);
+
+ if(have_hpp) {
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_FORCEHPP));
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_SETITEMDATA, 2, 2);
+ }
+
+ if(have_ieview) {
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_FORCEIEV));
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_SETITEMDATA, have_hpp ? 3 : 2, 3);
+ }
+
+ if (bIEView == 0 && bHPP == 0)
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_SETCURSEL, 0, 0);
+ else if (bIEView == 0xff && bHPP == 0xff)
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_SETCURSEL, 1, 0);
+ else {
+ if(bHPP == 1)
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_SETCURSEL, have_hpp ? 2 : 0, 0);
+ if(bIEView == 1)
+ SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_SETCURSEL, (have_hpp && have_ieview) ? 3 : (have_ieview ? 2 : 0), 0);
+ }
+
+ SendDlgItemMessage(hwndDlg, IDC_TEXTFORMATTING, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_IPGLOBAL));
+ SendDlgItemMessage(hwndDlg, IDC_TEXTFORMATTING, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_BBCODE));
+ SendDlgItemMessage(hwndDlg, IDC_TEXTFORMATTING, CB_INSERTSTRING, -1, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_FORMATTING_OFF));
+
+ SendDlgItemMessage(hwndDlg, IDC_TEXTFORMATTING, CB_SETCURSEL, iLocalFormat == 0 ? 0 : (iLocalFormat == -1 ? 2 : (1)), 0);
+
+ if (CheckMenuItem(PluginConfig.g_hMenuFavorites, (UINT_PTR)lParam, MF_BYCOMMAND | MF_UNCHECKED) == -1)
+ CheckDlgButton(hwndDlg, IDC_ISFAVORITE, FALSE);
+ else
+ CheckDlgButton(hwndDlg, IDC_ISFAVORITE, TRUE);
+
+ CheckDlgButton(hwndDlg, IDC_PRIVATESPLITTER, bSplit);
+ CheckDlgButton(hwndDlg, IDC_TEMPLOVERRIDE, M->GetByte(hContact, TEMPLATES_MODULE, "enabled", 0));
+ CheckDlgButton(hwndDlg, IDC_RTLTEMPLOVERRIDE, M->GetByte(hContact, RTLTEMPLATES_MODULE, "enabled", 0));
+
+ //MAD
+ CheckDlgButton(hwndDlg, IDC_LOADONLYACTUAL, M->GetByte(hContact, "ActualHistory", 0));
+ //
+ SendDlgItemMessage(hwndDlg, IDC_TRIMSPIN, UDM_SETRANGE, 0, MAKELONG(1000, 5));
+ SendDlgItemMessage(hwndDlg, IDC_TRIMSPIN, UDM_SETPOS, 0, maxhist);
+ Utils::enableDlgControl(hwndDlg, IDC_TRIMSPIN, maxhist != 0);
+ Utils::enableDlgControl(hwndDlg, IDC_TRIM, maxhist != 0);
+ CheckDlgButton(hwndDlg, IDC_ALWAYSTRIM2, maxhist != 0);
+
+ hCpCombo = GetDlgItem(hwndDlg, IDC_CODEPAGES);
+ sCodePage = M->GetDword(hContact, "ANSIcodepage", 0);
+ EnumSystemCodePages((CODEPAGE_ENUMPROC)FillCpCombo, CP_INSTALLED);
+ SendDlgItemMessage(hwndDlg, IDC_CODEPAGES, CB_INSERTSTRING, 0, (LPARAM)CTranslator::getOpt(CTranslator::OPT_UPREFS_DEFAULTCP));
+ if (sCodePage == 0)
+ SendDlgItemMessage(hwndDlg, IDC_CODEPAGES, CB_SETCURSEL, (WPARAM)0, 0);
+ else {
+ for (i = 0; i < SendDlgItemMessage(hwndDlg, IDC_CODEPAGES, CB_GETCOUNT, 0, 0); i++) {
+ if (SendDlgItemMessage(hwndDlg, IDC_CODEPAGES, CB_GETITEMDATA, (WPARAM)i, 0) == (LRESULT)sCodePage)
+ SendDlgItemMessage(hwndDlg, IDC_CODEPAGES, CB_SETCURSEL, (WPARAM)i, 0);
+ }
+ }
+ CheckDlgButton(hwndDlg, IDC_FORCEANSI, M->GetByte(hContact, "forceansi", 0) ? 1 : 0);
+ CheckDlgButton(hwndDlg, IDC_IGNORETIMEOUTS, M->GetByte(hContact, "no_ack", 0));
+
+ ShowWindow(hwndDlg, SW_SHOW);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_ALWAYSTRIM2:
+ Utils::enableDlgControl(hwndDlg, IDC_TRIMSPIN, IsDlgButtonChecked(hwndDlg, IDC_ALWAYSTRIM2));
+ Utils::enableDlgControl(hwndDlg, IDC_TRIM, IsDlgButtonChecked(hwndDlg, IDC_ALWAYSTRIM2));
+ break;
+ case WM_USER + 100: {
+ struct TWindowData *dat = 0;
+ DWORD *pdwActionToTake = (DWORD *)lParam;
+ int iIndex = CB_ERR, iMode = -1;
+ DWORD newCodePage;
+ unsigned int iOldIEView;
+ HWND hWnd = M->FindWindow(hContact);
+ DWORD sCodePage = M->GetDword(hContact, "ANSIcodepage", 0);
+ BYTE bInfoPanel, bOldInfoPanel = M->GetByte(hContact, "infopanel", 0);
+ BYTE bAvatarVisible = 0;
+
+ if (hWnd) {
+ dat = (struct TWindowData *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ if (dat)
+ iOldIEView = GetIEViewMode(hWnd, dat->hContact);
+ }
+ iIndex = SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_GETCURSEL, 0, 0);
+ iMode = SendDlgItemMessage(hwndDlg, IDC_IEVIEWMODE, CB_GETITEMDATA, iIndex, 0);
+
+ if (iIndex != CB_ERR && (iMode >= 0 && iMode <= 3)) {
+ unsigned int iNewIEView;
+
+ switch (iMode) {
+ case 0:
+ M->WriteByte(hContact, SRMSGMOD_T, "ieview", 0);
+ M->WriteByte(hContact, SRMSGMOD_T, "hpplog", 0);
+ break;
+ case 1:
+ M->WriteByte(hContact, SRMSGMOD_T, "ieview", -1);
+ M->WriteByte(hContact, SRMSGMOD_T, "hpplog", -1);
+ break;
+ case 2:
+ M->WriteByte(hContact, SRMSGMOD_T, "ieview", -1);
+ M->WriteByte(hContact, SRMSGMOD_T, "hpplog", 1);
+ break;
+ case 3:
+ M->WriteByte(hContact, SRMSGMOD_T, "ieview", 1);
+ M->WriteByte(hContact, SRMSGMOD_T, "hpplog", -1);
+ break;
+ default:
+ break;
+ }
+ if (hWnd && dat) {
+ iNewIEView = GetIEViewMode(hWnd, dat->hContact);
+ if (iNewIEView != iOldIEView) {
+ if(pdwActionToTake)
+ *pdwActionToTake |= UPREF_ACTION_SWITCHLOGVIEWER;
+ }
+ }
+ }
+ if ((iIndex = SendDlgItemMessage(hwndDlg, IDC_TEXTFORMATTING, CB_GETCURSEL, 0, 0)) != CB_ERR) {
+ if (iIndex == 0)
+ DBDeleteContactSetting(hContact, SRMSGMOD_T, "sendformat");
+ else
+ M->WriteDword(hContact, SRMSGMOD_T, "sendformat", iIndex == 2 ? -1 : 1);
+ }
+ iIndex = SendDlgItemMessage(hwndDlg, IDC_CODEPAGES, CB_GETCURSEL, 0, 0);
+ if ((newCodePage = (DWORD)SendDlgItemMessage(hwndDlg, IDC_CODEPAGES, CB_GETITEMDATA, (WPARAM)iIndex, 0)) != sCodePage) {
+ M->WriteDword(hContact, SRMSGMOD_T, "ANSIcodepage", (DWORD)newCodePage);
+ if (hWnd && dat) {
+ dat->codePage = newCodePage;
+ SendMessage(hWnd, DM_UPDATETITLE, 0, 1);
+ }
+ }
+ if ((IsDlgButtonChecked(hwndDlg, IDC_FORCEANSI) ? 1 : 0) != M->GetByte(hContact, "forceansi", 0)) {
+ M->WriteByte(hContact, SRMSGMOD_T, "forceansi", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_FORCEANSI) ? 1 : 0));
+ if (hWnd && dat)
+ dat->sendMode = IsDlgButtonChecked(hwndDlg, IDC_FORCEANSI) ? dat->sendMode | SMODE_FORCEANSI : dat->sendMode & ~SMODE_FORCEANSI;
+ }
+ if (IsDlgButtonChecked(hwndDlg, IDC_ISFAVORITE)) {
+ if (!M->GetByte(hContact, SRMSGMOD_T, "isFavorite", 0))
+ AddContactToFavorites(hContact, NULL, NULL, NULL, 0, 0, 1, PluginConfig.g_hMenuFavorites);
+ } else
+ DeleteMenu(PluginConfig.g_hMenuFavorites, (UINT_PTR)hContact, MF_BYCOMMAND);
+
+ M->WriteByte(hContact, SRMSGMOD_T, "isFavorite", (WORD)(IsDlgButtonChecked(hwndDlg, IDC_ISFAVORITE) ? 1 : 0));
+ M->WriteByte(hContact, SRMSGMOD_T, "splitoverride", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_PRIVATESPLITTER) ? 1 : 0));
+
+ M->WriteByte(hContact, TEMPLATES_MODULE, "enabled", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_TEMPLOVERRIDE)));
+ M->WriteByte(hContact, RTLTEMPLATES_MODULE, "enabled", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_RTLTEMPLOVERRIDE)));
+
+ bAvatarVisible = (BYTE)SendDlgItemMessage(hwndDlg, IDC_SHOWAVATAR, CB_GETCURSEL, 0, 0);
+ if(bAvatarVisible == 0)
+ DBDeleteContactSetting(hContact, SRMSGMOD_T, "hideavatar");
+ else
+ M->WriteByte(hContact, SRMSGMOD_T, "hideavatar", (BYTE)(bAvatarVisible == 1 ? 1 : 0));
+
+ bInfoPanel = (BYTE)SendDlgItemMessage(hwndDlg, IDC_INFOPANEL, CB_GETCURSEL, 0, 0);
+ if (bInfoPanel != bOldInfoPanel) {
+ M->WriteByte(hContact, SRMSGMOD_T, "infopanel", (BYTE)(bInfoPanel == 0 ? 0 : (bInfoPanel == 1 ? 1 : -1)));
+ if (hWnd && dat)
+ SendMessage(hWnd, DM_SETINFOPANEL, 0, 0);
+ }
+ if (IsDlgButtonChecked(hwndDlg, IDC_ALWAYSTRIM2))
+ M->WriteDword(hContact, SRMSGMOD_T, "maxhist", (DWORD)SendDlgItemMessage(hwndDlg, IDC_TRIMSPIN, UDM_GETPOS, 0, 0));
+ else
+ M->WriteDword(hContact, SRMSGMOD_T, "maxhist", 0);
+
+ //MAD
+ if (IsDlgButtonChecked(hwndDlg, IDC_LOADONLYACTUAL)){
+ M->WriteByte(hContact, SRMSGMOD_T, "ActualHistory", 1);
+ if (hWnd && dat) dat->bActualHistory=TRUE;
+ }else{
+ M->WriteByte(hContact, SRMSGMOD_T, "ActualHistory", 0);
+ if (hWnd && dat) dat->bActualHistory=FALSE;
+ }
+ //
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_IGNORETIMEOUTS)) {
+ M->WriteByte(hContact, SRMSGMOD_T, "no_ack", 1);
+ if (hWnd && dat)
+ dat->sendMode |= SMODE_NOACK;
+ } else {
+ DBDeleteContactSetting(hContact, SRMSGMOD_T, "no_ack");
+ if (hWnd && dat)
+ dat->sendMode &= ~SMODE_NOACK;
+ }
+ if (hWnd && dat) {
+ SendMessage(hWnd, DM_CONFIGURETOOLBAR, 0, 1);
+ dat->panelWidth = -1;
+ ShowPicture(dat, FALSE);
+ SendMessage(hWnd, WM_SIZE, 0, 0);
+ DM_ScrollToBottom(dat, 0, 1);
+ }
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static struct _checkboxes {
+ UINT uId;
+ UINT uFlag;
+} checkboxes[] = {
+ IDC_UPREFS_GRID, MWF_LOG_GRID,
+ IDC_UPREFS_SHOWICONS, MWF_LOG_SHOWICONS,
+ IDC_UPREFS_SHOWSYMBOLS, MWF_LOG_SYMBOLS,
+ IDC_UPREFS_INOUTICONS, MWF_LOG_INOUTICONS,
+ IDC_UPREFS_SHOWTIMESTAMP, MWF_LOG_SHOWTIME,
+ IDC_UPREFS_SHOWDATES, MWF_LOG_SHOWDATES,
+ IDC_UPREFS_SHOWSECONDS, MWF_LOG_SHOWSECONDS,
+ IDC_UPREFS_LOCALTIME, MWF_LOG_LOCALTIME,
+ IDC_UPREFS_INDENT, MWF_LOG_INDENT,
+ IDC_UPREFS_GROUPING, MWF_LOG_GROUPMODE,
+ IDC_UPREFS_BBCODE, MWF_LOG_BBCODE,
+ IDC_UPREFS_RTL, MWF_LOG_RTL,
+ IDC_UPREFS_LOGSTATUS, MWF_LOG_STATUSCHANGES,
+ IDC_UPREFS_NORMALTEMPLATES, MWF_LOG_NORMALTEMPLATES,
+ 0, 0
+};
+
+/*
+ * loads message log and other "per contact" flags
+ * it uses the global flag value (0, mwflags) and then merges per contact settings
+ * based on the mask value.
+
+ * ALWAYS mask dat->dwFlags with MWF_LOG_ALL to only affect real flag bits and
+ * ignore temporary bits.
+ */
+
+int TSAPI LoadLocalFlags(HWND hwnd, struct TWindowData *dat)
+{
+ int i = 0;
+ DWORD dwMask = M->GetDword(dat->hContact, "mwmask", 0);
+ DWORD dwLocal = M->GetDword(dat->hContact, "mwflags", 0);
+ DWORD dwGlobal = M->GetDword("mwflags", 0);
+ DWORD maskval;
+
+ if(dat) {
+ dat->dwFlags &= ~MWF_LOG_ALL;
+ if(dat->pContainer->theme.isPrivate)
+ dat->dwFlags |= (dat->pContainer->theme.dwFlags & MWF_LOG_ALL);
+ else
+ dat->dwFlags |= (dwGlobal & MWF_LOG_ALL);
+ while(checkboxes[i].uId) {
+ maskval = checkboxes[i].uFlag;
+ if(dwMask & maskval)
+ dat->dwFlags = (dwLocal & maskval) ? dat->dwFlags | maskval : dat->dwFlags & ~maskval;
+ i++;
+ }
+ return(dat->dwFlags & MWF_LOG_ALL);
+ }
+ return 0;
+}
+
+/**
+ * dialog procedure for the user preferences dialog (2nd page,
+ * "per contact" message log options)
+ *
+ * @params: Win32 window procedure conform
+ *
+ * @return LRESULT
+ */
+static INT_PTR CALLBACK DlgProcUserPrefsLogOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ switch(msg) {
+ case WM_INITDIALOG: {
+
+ hContact = (HANDLE)lParam;
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)hContact);
+ SendMessage(hwndDlg, WM_COMMAND, WM_USER + 200, 0);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case WM_USER + 200: {
+ DWORD dwLocalFlags, dwLocalMask, maskval;
+ int i = 0;
+
+ dwLocalFlags = M->GetDword(hContact, "mwflags", 0);
+ dwLocalMask = M->GetDword(hContact, "mwmask", 0);
+
+ while(checkboxes[i].uId) {
+ maskval = checkboxes[i].uFlag;
+
+ if(dwLocalMask & maskval)
+ CheckDlgButton(hwndDlg, checkboxes[i].uId, (dwLocalFlags & maskval) ? BST_CHECKED : BST_UNCHECKED);
+ else
+ CheckDlgButton(hwndDlg, checkboxes[i].uId, BST_INDETERMINATE);
+ i++;
+ }
+ break;
+ }
+ case WM_USER + 100: {
+ int i = 0;
+ LRESULT state;
+ HWND hwnd = M->FindWindow(hContact);
+ struct TWindowData *dat = NULL;
+ DWORD *dwActionToTake = (DWORD *)lParam, dwMask = 0, dwFlags = 0, maskval;
+
+ if(hwnd)
+ dat = (struct TWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ while(checkboxes[i].uId) {
+ maskval = checkboxes[i].uFlag;
+
+ state = IsDlgButtonChecked(hwndDlg, checkboxes[i].uId);
+ if(state != BST_INDETERMINATE) {
+ dwMask |= maskval;
+ dwFlags = (state == BST_CHECKED) ? (dwFlags | maskval) : (dwFlags & ~maskval);
+ }
+ i++;
+ }
+ if(dwMask) {
+ M->WriteDword(hContact, SRMSGMOD_T, "mwmask", dwMask);
+ M->WriteDword(hContact, SRMSGMOD_T, "mwflags", dwFlags);
+ }
+ else {
+ DBDeleteContactSetting(hContact, SRMSGMOD_T, "mwmask");
+ DBDeleteContactSetting(hContact, SRMSGMOD_T, "mwflags");
+ }
+ if(hwnd && dat) {
+ if(dwMask)
+ *dwActionToTake |= (DWORD)UPREF_ACTION_REMAKELOG;
+ if((dat->dwFlags & MWF_LOG_RTL) != (dwFlags & MWF_LOG_RTL))
+ *dwActionToTake |= (DWORD)UPREF_ACTION_APPLYOPTIONS;
+ }
+ break;
+ }
+ case IDC_REVERTGLOBAL:
+ DBDeleteContactSetting(hContact, SRMSGMOD_T, "mwmask");
+ DBDeleteContactSetting(hContact, SRMSGMOD_T, "mwflags");
+ SendMessage(hwndDlg, WM_COMMAND, WM_USER + 200, 0);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/**
+ * dialog procedure for the user preferences dialog. Handles the top
+ * level window (a tab control with 2 subpages)
+ *
+ * @params: like any Win32 window procedure
+ *
+ * @return LRESULT (ignored for dialog procs, use
+ * DWLP_MSGRESULT)
+ */
+INT_PTR CALLBACK DlgProcUserPrefsFrame(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch(msg) {
+ case WM_INITDIALOG: {
+ TCITEM tci = {0};
+ RECT rcClient;
+ TCHAR szBuffer[180];
+
+ hContact = (HANDLE)lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)hContact);
+
+ WindowList_Add(PluginConfig.hUserPrefsWindowList, hwndDlg, hContact);
+ TranslateDialogDefault(hwndDlg);
+
+ GetClientRect(hwndDlg, &rcClient);
+
+ mir_sntprintf(szBuffer, safe_sizeof(szBuffer), CTranslator::getOpt(CTranslator::OPT_UPREFS_TITLE),
+ (TCHAR *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR));
+
+ SetWindowText(hwndDlg, szBuffer);
+
+ tci.cchTextMax = 100;
+ tci.mask = TCIF_PARAM | TCIF_TEXT;
+ tci.lParam = (LPARAM)CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_USERPREFS), hwndDlg, DlgProcUserPrefs, (LPARAM)hContact);
+ tci.pszText = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_UPREFS_GENERIC));
+ TabCtrl_InsertItem(GetDlgItem(hwndDlg, IDC_OPTIONSTAB), 0, &tci);
+ MoveWindow((HWND)tci.lParam, 6, DPISCALEY_S(32), rcClient.right - 12, rcClient.bottom - DPISCALEY_S(80), 1);
+ ShowWindow((HWND)tci.lParam, SW_SHOW);
+ if (CMimAPI::m_pfnEnableThemeDialogTexture)
+ CMimAPI::m_pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+
+
+ tci.lParam = (LPARAM)CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_USERPREFS1), hwndDlg, DlgProcUserPrefsLogOptions, (LPARAM)hContact);
+ tci.pszText = const_cast<TCHAR *>(CTranslator::getOpt(CTranslator::OPT_UPREFS_MSGLOG));
+ TabCtrl_InsertItem(GetDlgItem(hwndDlg, IDC_OPTIONSTAB), 1, &tci);
+ MoveWindow((HWND)tci.lParam, 6, DPISCALEY_S(32), rcClient.right - 12, rcClient.bottom - DPISCALEY_S(80), 1);
+ ShowWindow((HWND)tci.lParam, SW_HIDE);
+ if (CMimAPI::m_pfnEnableThemeDialogTexture)
+ CMimAPI::m_pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+ TabCtrl_SetCurSel(GetDlgItem(hwndDlg, IDC_OPTIONSTAB), 0);
+ ShowWindow(hwndDlg, SW_SHOW);
+ return TRUE;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case IDC_OPTIONSTAB:
+ switch (((LPNMHDR)lParam)->code) {
+ case TCN_SELCHANGING: {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+
+ TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_OPTIONSTAB), TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_OPTIONSTAB)), &tci);
+ ShowWindow((HWND)tci.lParam, SW_HIDE);
+ }
+ break;
+ case TCN_SELCHANGE: {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+
+ TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_OPTIONSTAB), TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_OPTIONSTAB)), &tci);
+ ShowWindow((HWND)tci.lParam, SW_SHOW);
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND: {
+ switch(LOWORD(wParam)) {
+ case IDOK: {
+ TCITEM tci;
+ int i, count;
+ DWORD dwActionToTake = 0; // child pages request which action to take
+ HWND hwnd = M->FindWindow(hContact);
+
+ tci.mask = TCIF_PARAM;
+
+ count = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_OPTIONSTAB));
+ for (i = 0;i < count;i++) {
+ TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_OPTIONSTAB), i, &tci);
+ SendMessage((HWND)tci.lParam, WM_COMMAND, WM_USER + 100, (LPARAM)&dwActionToTake);
+ }
+ if(hwnd) {
+ struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if(dat) {
+ DWORD dwOldFlags = (dat->dwFlags & MWF_LOG_ALL);
+
+ SetDialogToType(hwnd);
+#if defined(__FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER)
+ if(dwActionToTake & UPREF_ACTION_SWITCHLOGVIEWER) {
+ unsigned int mode = GetIEViewMode(hwndDlg, dat->hContact);
+ SwitchMessageLog(dat, mode);
+ }
+#endif
+ LoadLocalFlags(hwnd, dat);
+ if((dat->dwFlags & MWF_LOG_ALL) != dwOldFlags) {
+ BOOL fShouldHide = TRUE;
+
+ if(IsIconic(dat->pContainer->hwnd))
+ fShouldHide = FALSE;
+ else
+ ShowWindow(dat->pContainer->hwnd, SW_HIDE);
+ SendMessage(hwnd, DM_OPTIONSAPPLIED, 0, 0);
+ SendMessage(hwnd, DM_DEFERREDREMAKELOG, (WPARAM)hwnd, 0);
+ if(fShouldHide)
+ ShowWindow(dat->pContainer->hwnd, SW_SHOWNORMAL);
+ }
+ }
+ }
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+ }
+ case WM_DESTROY:
+ WindowList_Remove(PluginConfig.hUserPrefsWindowList, hwndDlg);
+ break;
+ }
+ return FALSE;
+}
diff --git a/plugins/TabSRMM/src/utils.cpp b/plugins/TabSRMM/src/utils.cpp
new file mode 100644
index 0000000000..f4bd5ab118
--- /dev/null
+++ b/plugins/TabSRMM/src/utils.cpp
@@ -0,0 +1,1513 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: utils.cpp 13428 2011-03-10 13:15:44Z borkra $
+ *
+ * generic utility functions
+ *
+ */
+
+#include "commonheaders.h"
+#include <string>
+
+#define MWF_LOG_BBCODE 1
+#define MWF_LOG_TEXTFORMAT 0x2000000
+#define MSGDLGFONTCOUNT 22
+
+int Utils::rtf_ctable_size = 0;
+TRTFColorTable* Utils::rtf_ctable = 0;
+
+HANDLE CWarning::hWindowList = 0;
+
+static TCHAR *w_bbcodes_begin[] = { _T("[b]"), _T("[i]"), _T("[u]"), _T("[s]"), _T("[color=") };
+static TCHAR *w_bbcodes_end[] = { _T("[/b]"), _T("[/i]"), _T("[/u]"), _T("[/s]"), _T("[/color]") };
+
+static TCHAR *formatting_strings_begin[] = { _T("b1 "), _T("i1 "), _T("u1 "), _T("s1 "), _T("c1 ") };
+static TCHAR *formatting_strings_end[] = { _T("b0 "), _T("i0 "), _T("u0 "), _T("s0 "), _T("c0 ") };
+
+#define NR_CODES 5
+
+LRESULT TSAPI _dlgReturn(HWND hWnd, LRESULT result)
+{
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, result);
+ return(result);
+}
+
+void* Utils::safeAlloc(const size_t size)
+{
+ __try {
+ unsigned char* _p = reinterpret_cast<unsigned char*>(malloc(size));
+ *_p = 0;
+
+ return(reinterpret_cast<void*>(_p));
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"MEMORY_ALLOCATION", false)) {
+ return(0);
+ }
+}
+
+void* Utils::safeCalloc(const size_t size)
+{
+ __try {
+ void* _p = safeAlloc(size);
+ ::ZeroMemory(_p, size);
+ return(_p);
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"MEMORY_ALLOCATION", false)) {
+ return(0);
+ }
+}
+
+void* Utils::safeMirAlloc(const size_t size)
+{
+ __try {
+ unsigned char* _p = reinterpret_cast<unsigned char*>(mir_alloc(size));
+ *_p = 0;
+
+ return(reinterpret_cast<void*>(_p));
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"MIR_MEMORY_ALLOCATION", false)) {
+ return(0);
+ }
+}
+
+void* Utils::safeMirCalloc(const size_t size)
+{
+ __try {
+ void* _p = safeMirAlloc(size);
+ ::ZeroMemory(_p, size);
+ return(_p);
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"MIR_MEMORY_ALLOCATION", false)) {
+ return(0);
+ }
+}
+
+TCHAR* Utils::FilterEventMarkers(TCHAR *wszText)
+{
+ tstring text(wszText);
+ INT_PTR beginmark = 0, endmark = 0;
+
+ while (TRUE) {
+ if ((beginmark = text.find(_T("~-+"))) != text.npos) {
+ endmark = text.find(_T("+-~"), beginmark);
+ if (endmark != text.npos && (endmark - beginmark) > 5) {
+ text.erase(beginmark, (endmark - beginmark) + 3);
+ continue;
+ } else
+ break;
+ } else
+ break;
+ }
+ //mad
+
+ while (TRUE) {
+ if ((beginmark = text.find( _T("\xAA"))) != text.npos) {
+ endmark = beginmark+2;
+ if (endmark != text.npos && (endmark - beginmark) > 1) {
+ text.erase(beginmark, endmark - beginmark);
+ continue;
+ } else
+ break;
+ } else
+ break;
+ }
+ //
+
+ lstrcpy(wszText, text.c_str());
+ return wszText;
+}
+
+/**
+ * this translates formatting tags into rtf sequences...
+ * flags: loword = words only for simple * /_ formatting
+ * hiword = bbcode support (strip bbcodes if 0)
+ */
+const TCHAR* Utils::FormatRaw(TWindowData *dat, const TCHAR *msg, int flags, BOOL isSent)
+{
+ bool clr_was_added = false, was_added;
+ static tstring message(msg);
+ INT_PTR beginmark = 0, endmark = 0, tempmark = 0, index;
+ int i, endindex;
+ TCHAR endmarker;
+ DWORD dwFlags = dat->dwFlags;
+ message.assign(msg);
+ int haveMathMod = PluginConfig.m_MathModAvail;
+ TCHAR* mathModDelimiter = PluginConfig.m_MathModStartDelimiter;
+
+
+ if (haveMathMod && mathModDelimiter[0] && message.find(mathModDelimiter) != message.npos)
+ return(message.c_str());
+
+ if(dwFlags & MWF_LOG_BBCODE) {
+ if (haveMathMod && mathModDelimiter[0]) {
+ INT_PTR mark = 0;
+ int nrDelims = 0;
+ while ((mark = message.find(mathModDelimiter, mark)) != message.npos) {
+ nrDelims++;
+ mark += lstrlen(mathModDelimiter);
+ }
+ if (nrDelims > 0 && (nrDelims % 2) != 0)
+ message.append(mathModDelimiter);
+ }
+ beginmark = 0;
+ while (TRUE) {
+ for (i = 0; i < NR_CODES; i++) {
+ if ((tempmark = message.find(w_bbcodes_begin[i], 0)) != message.npos)
+ break;
+ }
+ if (i >= NR_CODES)
+ break;
+ beginmark = tempmark;
+ endindex = i;
+ endmark = message.find(w_bbcodes_end[i], beginmark);
+ if (endindex == 4) { // color
+ size_t closing = message.find_first_of(_T("]"), beginmark);
+ was_added = false;
+
+ if (closing == message.npos) { // must be an invalid [color=] tag w/o closing bracket
+ message[beginmark] = ' ';
+ continue;
+ } else {
+ tstring colorname = message.substr(beginmark + 7, 8);
+search_again:
+ bool clr_found = false;
+ int ii = 0;
+ TCHAR szTemp[5];
+ for (ii = 0; ii < rtf_ctable_size; ii++) {
+ if (!_tcsnicmp((TCHAR *)colorname.c_str(), rtf_ctable[ii].szName, lstrlen(rtf_ctable[ii].szName))) {
+ closing = beginmark + 7 + lstrlen(rtf_ctable[ii].szName);
+ if (endmark != message.npos) {
+ message.erase(endmark, 4);
+ message.replace(endmark, 4, _T("c0 "));
+ }
+ message.erase(beginmark, (closing - beginmark));
+ message.insert(beginmark, _T("cxxx "));
+ _sntprintf(szTemp, 4, _T("%02d"), MSGDLGFONTCOUNT + 13 + ii);
+ message[beginmark + 3] = szTemp[0];
+ message[beginmark + 4] = szTemp[1];
+ clr_found = true;
+ if (was_added) {
+ TCHAR wszTemp[100];
+ _sntprintf(wszTemp, 100, _T("##col##%06u:%04u"), endmark - closing, ii);
+ wszTemp[99] = 0;
+ message.insert(beginmark, wszTemp);
+ }
+ break;
+ }
+ }
+ if (!clr_found) {
+ size_t c_closing = colorname.find_first_of(_T("]"), 0);
+ if (c_closing == colorname.npos)
+ c_closing = colorname.length();
+ const TCHAR *wszColname = colorname.c_str();
+ if (endmark != message.npos && c_closing > 2 && c_closing <= 6 && iswalnum(colorname[0]) && iswalnum(colorname[c_closing -1])) {
+ RTF_ColorAdd(wszColname, c_closing);
+ if (!was_added) {
+ clr_was_added = was_added = true;
+ goto search_again;
+ } else
+ goto invalid_code;
+ } else {
+invalid_code:
+ if (endmark != message.npos)
+ message.erase(endmark, 8);
+ if (closing != message.npos && closing < (size_t)endmark)
+ message.erase(beginmark, (closing - beginmark) + 1);
+ else
+ message[beginmark] = ' ';
+ }
+ }
+ continue;
+ }
+ }
+ if (endmark != message.npos)
+ message.replace(endmark, 4, formatting_strings_end[i]);
+ message.insert(beginmark, _T(" "));
+ message.replace(beginmark, 4, formatting_strings_begin[i]);
+ }
+ }
+
+ if (!(dwFlags & MWF_LOG_TEXTFORMAT) || message.find(_T("://")) != message.npos) {
+ dat->clr_added = clr_was_added ? TRUE : FALSE;
+ return(message.c_str());
+ }
+
+
+ while ((beginmark = message.find_first_of(_T("*/_"), beginmark)) != message.npos) {
+ endmarker = message[beginmark];
+ if (LOWORD(flags)) {
+ if (beginmark > 0 && !_istspace(message[beginmark - 1]) && !_istpunct(message[beginmark - 1])) {
+ beginmark++;
+ continue;
+ }
+ // search a corresponding endmarker which fulfills the criteria
+ INT_PTR tempmark = beginmark + 1;
+ while ((endmark = message.find(endmarker, tempmark)) != message.npos) {
+ if (_istpunct(message[endmark + 1]) || _istspace(message[endmark + 1]) || message[endmark + 1] == 0 || _tcschr(_T("*/_"), message[endmark + 1]) != NULL)
+ goto ok;
+ tempmark = endmark + 1;
+ }
+ break;
+ } else {
+ if ((endmark = message.find(endmarker, beginmark + 1)) == message.npos)
+ break;
+ }
+ok:
+ if ((endmark - beginmark) < 2) {
+ beginmark++;
+ continue;
+ }
+ index = 0;
+ switch (endmarker) {
+ case '*':
+ index = 0;
+ break;
+ case '/':
+ index = 1;
+ break;
+ case '_':
+ index = 2;
+ break;
+ }
+
+ /*
+ * check if the code enclosed by simple formatting tags is a valid smiley code and skip formatting if
+ * it really is one.
+ */
+
+ if (PluginConfig.g_SmileyAddAvail && (endmark > (beginmark + 1))) {
+ tstring smcode;
+ smcode.assign(message, beginmark, (endmark - beginmark) + 1);
+ SMADD_BATCHPARSE2 smbp = {0};
+ SMADD_BATCHPARSERES *smbpr;
+
+ smbp.cbSize = sizeof(smbp);
+ smbp.Protocolname = dat->cache->getActiveProto();
+ smbp.flag = SAFL_TCHAR | SAFL_PATH | (isSent ? SAFL_OUTGOING : 0);
+ smbp.str = (TCHAR *)smcode.c_str();
+ smbp.hContact = dat->hContact;
+ smbpr = (SMADD_BATCHPARSERES *)CallService(MS_SMILEYADD_BATCHPARSE, 0, (LPARAM) & smbp);
+ if (smbpr) {
+ CallService(MS_SMILEYADD_BATCHFREE, 0, (LPARAM)smbpr);
+ beginmark = endmark + 1;
+ continue;
+ }
+ }
+ message.insert(endmark, _T("%%%"));
+ message.replace(endmark, 4, formatting_strings_end[index]);
+ message.insert(beginmark, _T("%%%"));
+ message.replace(beginmark, 4, formatting_strings_begin[index]);
+ }
+ dat->clr_added = clr_was_added ? TRUE : FALSE;
+ return(message.c_str());
+}
+
+/**
+ * format the title bar string for IM chat sessions using placeholders.
+ * the caller must free() the returned string
+ */
+const TCHAR* Utils::FormatTitleBar(const TWindowData *dat, const TCHAR *szFormat)
+{
+ TCHAR *szResult = 0;
+ INT_PTR length = 0;
+ INT_PTR tempmark = 0;
+ TCHAR szTemp[512];
+
+ if(dat == 0)
+ return(0);
+
+ tstring title(szFormat);
+
+ for ( size_t curpos = 0; curpos < title.length(); ) {
+ if(title[curpos] != '%') {
+ curpos++;
+ continue;
+ }
+ tempmark = curpos;
+ curpos++;
+ if(title[curpos] == 0)
+ break;
+
+ switch (title[curpos]) {
+ case 'n': {
+ const TCHAR *tszNick = dat->cache->getNick();
+ if (tszNick[0])
+ title.insert(tempmark + 2, tszNick);
+ title.erase(tempmark, 2);
+ curpos = tempmark + lstrlen(tszNick);
+ break;
+ }
+ case 'p':
+ case 'a': {
+ const TCHAR *szAcc = dat->cache->getRealAccount();
+ if (szAcc)
+ title.insert(tempmark + 2, szAcc);
+ title.erase(tempmark, 2);
+ curpos = tempmark + lstrlen(szAcc);
+ break;
+ }
+ case 's': {
+ if (dat->szStatus && dat->szStatus[0])
+ title.insert(tempmark + 2, dat->szStatus);
+ title.erase(tempmark, 2);
+ curpos = tempmark + lstrlen(dat->szStatus);
+ break;
+ }
+ case 'u': {
+ const TCHAR *szUIN = dat->cache->getUIN();
+ if (szUIN[0])
+ title.insert(tempmark + 2, szUIN);
+ title.erase(tempmark, 2);
+ curpos = tempmark + lstrlen(szUIN);
+ break;
+ }
+ case 'c': {
+ TCHAR *c = (!_tcscmp(dat->pContainer->szName, _T("default")) ? const_cast<TCHAR *>(CTranslator::get(CTranslator::GEN_DEFAULT_CONTAINER_NAME)) : dat->pContainer->szName);
+ title.insert(tempmark + 2, c);
+ title.erase(tempmark, 2);
+ curpos = tempmark + lstrlen(c);
+ break;
+ }
+ case 'o': {
+ const TCHAR* szProto = dat->cache->getActiveProtoT();
+ if (szProto)
+ title.insert(tempmark + 2, szProto);
+ title.erase(tempmark, 2);
+ curpos = tempmark + (szProto ? lstrlen(szProto) : 0);
+ break;
+ }
+ case 'x': {
+ TCHAR *szFinalStatus = NULL;
+ BYTE xStatus = dat->cache->getXStatusId();
+
+ if (dat->wStatus != ID_STATUS_OFFLINE && xStatus > 0 && xStatus <= 31) {
+ DBVARIANT dbv = {0};
+
+ if (!M->GetTString(dat->hContact, (char *)dat->szProto, "XStatusName", &dbv)) {
+ _tcsncpy(szTemp, dbv.ptszVal, 500);
+ szTemp[500] = 0;
+ DBFreeVariant(&dbv);
+ title.insert(tempmark + 2, szTemp);
+ curpos = tempmark + lstrlen(szTemp);
+ }
+ else {
+ title.insert(tempmark + 2, xStatusDescr[xStatus - 1]);
+ curpos = tempmark + lstrlen(xStatusDescr[xStatus - 1]);
+ }
+ }
+ title.erase(tempmark, 2);
+ break;
+ }
+ case 'm': {
+ TCHAR *szFinalStatus = NULL;
+ BYTE xStatus = dat->cache->getXStatusId();
+
+ if (dat->wStatus != ID_STATUS_OFFLINE && xStatus > 0 && xStatus <= 31) {
+ DBVARIANT dbv = {0};
+
+ if (!M->GetTString(dat->hContact, (char *)dat->szProto, "XStatusName", &dbv)) {
+ _tcsncpy(szTemp, dbv.ptszVal, 500);
+ szTemp[500] = 0;
+ DBFreeVariant(&dbv);
+ title.insert(tempmark + 2, szTemp);
+ } else
+ szFinalStatus = xStatusDescr[xStatus - 1];
+ } else
+ szFinalStatus = (TCHAR *)(dat->szStatus && dat->szStatus[0] ? dat->szStatus : _T("(undef)"));
+
+ if (szFinalStatus) {
+ title.insert(tempmark + 2, szFinalStatus);
+ curpos = tempmark + lstrlen(szFinalStatus);
+ }
+
+ title.erase(tempmark, 2);
+ break;
+ }
+ /*
+ * status message (%T will skip the "No status message" for empty
+ * messages)
+ */
+ case 't':
+ case 'T': {
+ TCHAR *tszStatusMsg = dat->cache->getNormalizedStatusMsg(dat->cache->getStatusMsg(), true);
+
+ if(tszStatusMsg) {
+ title.insert(tempmark + 2, tszStatusMsg);
+ curpos = tempmark + lstrlen(tszStatusMsg);
+ }
+ else if(title[curpos] == 't') {
+ const TCHAR* tszStatusMsg = CTranslator::get(CTranslator::GEN_NO_STATUS);
+ title.insert(tempmark + 2, tszStatusMsg);
+ curpos = tempmark + lstrlen(tszStatusMsg);
+ }
+ title.erase(tempmark, 2);
+ if(tszStatusMsg)
+ mir_free(tszStatusMsg);
+ break;
+ }
+ default:
+ title.erase(tempmark, 1);
+ break;
+ }
+ }
+ length = title.length();
+
+ szResult = (TCHAR *)malloc((length + 2) * sizeof(TCHAR));
+ if (szResult) {
+ _tcsncpy(szResult, title.c_str(), length);
+ szResult[length] = 0;
+ }
+ return szResult;
+}
+
+char* Utils::FilterEventMarkers(char *szText)
+{
+ std::string text(szText);
+ INT_PTR beginmark = 0, endmark = 0;
+
+ while (TRUE) {
+ if ((beginmark = text.find("~-+")) != text.npos) {
+ endmark = text.find("+-~", beginmark);
+ if (endmark != text.npos && (endmark - beginmark) > 5) {
+ text.erase(beginmark, (endmark - beginmark) + 3);
+ continue;
+ } else
+ break;
+ } else
+ break;
+ }
+ //mad
+ while (TRUE) {
+ if ((beginmark = text.find( "\xAA")) != text.npos) {
+ endmark = beginmark+2;
+ if (endmark != text.npos && (endmark - beginmark) > 1) {
+ text.erase(beginmark, endmark - beginmark);
+ continue;
+ } else
+ break;
+ } else
+ break;
+ }
+ //
+ lstrcpyA(szText, text.c_str());
+ return szText;
+}
+
+const TCHAR* Utils::DoubleAmpersands(TCHAR *pszText)
+{
+ tstring text(pszText);
+
+ INT_PTR textPos = 0;
+
+ while (TRUE) {
+ if ((textPos = text.find(_T("&"),textPos)) != text.npos) {
+ text.insert(textPos,_T("%"));
+ text.replace(textPos, 2, _T("&&"));
+ textPos+=2;
+ continue;
+ } else
+ break;
+ }
+ _tcscpy(pszText, text.c_str());
+ return pszText;
+}
+
+/**
+ * Get a preview of the text with an ellipsis appended (...)
+ *
+ * @param szText source text
+ * @param iMaxLen max length of the preview
+ * @return TCHAR* result (caller must mir_free() it)
+ */
+TCHAR* Utils::GetPreviewWithEllipsis(TCHAR *szText, size_t iMaxLen)
+{
+ size_t uRequired;
+ TCHAR* p = 0, cSaved;
+ bool fEllipsis = false;
+
+ if(_tcslen(szText) <= iMaxLen)
+ uRequired = _tcslen(szText) + 4;
+ else {
+ TCHAR *p = &szText[iMaxLen - 1];
+ fEllipsis = true;
+
+ while(p >= szText && *p != ' ')
+ p--;
+ if(p == szText)
+ p = szText + iMaxLen - 1;
+
+ cSaved = *p;
+ *p = 0;
+ uRequired = (p - szText) + 6;
+ }
+ TCHAR *szResult = reinterpret_cast<TCHAR *>(mir_alloc(uRequired * sizeof(TCHAR)));
+ mir_sntprintf(szResult, uRequired, fEllipsis ? _T("%s...") : _T("%s"), szText);
+
+ if(p)
+ *p = cSaved;
+
+ return(szResult);
+}
+
+/*
+ * returns != 0 when one of the installed keyboard layouts belongs to an rtl language
+ * used to find out whether we need to configure the message input box for bidirectional mode
+ */
+
+int Utils::FindRTLLocale(TWindowData *dat)
+{
+ HKL layouts[20];
+ int i, result = 0;
+ LCID lcid;
+ WORD wCtype2[5];
+
+ if (dat->iHaveRTLLang == 0) {
+ ZeroMemory(layouts, 20 * sizeof(HKL));
+ GetKeyboardLayoutList(20, layouts);
+ for (i = 0; i < 20 && layouts[i]; i++) {
+ lcid = MAKELCID(LOWORD(layouts[i]), 0);
+ GetStringTypeA(lcid, CT_CTYPE2, "���", 3, wCtype2);
+ if (wCtype2[0] == C2_RIGHTTOLEFT || wCtype2[1] == C2_RIGHTTOLEFT || wCtype2[2] == C2_RIGHTTOLEFT)
+ result = 1;
+ }
+ dat->iHaveRTLLang = (result ? 1 : -1);
+ } else
+ result = dat->iHaveRTLLang == 1 ? 1 : 0;
+
+ return result;
+}
+
+/*
+ * init default color table. the table may grow when using custom colors via bbcodes
+ */
+
+void Utils::RTF_CTableInit()
+{
+ int iSize = sizeof(TRTFColorTable) * RTF_CTABLE_DEFSIZE;
+
+ rtf_ctable = (TRTFColorTable *)malloc(iSize);
+ ZeroMemory(rtf_ctable, iSize);
+ CopyMemory(rtf_ctable, _rtf_ctable, iSize);
+ rtf_ctable_size = RTF_CTABLE_DEFSIZE;
+}
+
+/*
+ * add a color to the global rtf color table
+ */
+
+void Utils::RTF_ColorAdd(const TCHAR *tszColname, size_t length)
+{
+ TCHAR *stopped;
+ COLORREF clr;
+
+ rtf_ctable_size++;
+ rtf_ctable = (TRTFColorTable *)realloc(rtf_ctable, sizeof(TRTFColorTable) * rtf_ctable_size);
+ clr = _tcstol(tszColname, &stopped, 16);
+ mir_sntprintf(rtf_ctable[rtf_ctable_size - 1].szName, length + 1, _T("%06x"), clr);
+ rtf_ctable[rtf_ctable_size - 1].menuid = rtf_ctable[rtf_ctable_size - 1].index = 0;
+
+ clr = _tcstol(tszColname, &stopped, 16);
+ rtf_ctable[rtf_ctable_size - 1].clr = (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)));
+}
+
+void Utils::CreateColorMap(TCHAR *Text)
+{
+ TCHAR * pszText = Text;
+ TCHAR * p1;
+ TCHAR * p2;
+ TCHAR * pEnd;
+ int iIndex = 1, i = 0;
+ COLORREF default_color;
+
+ static const TCHAR *lpszFmt = _T("\\red%[^ \x5b\\]\\green%[^ \x5b\\]\\blue%[^ \x5b;];");
+ TCHAR szRed[10], szGreen[10], szBlue[10];
+
+ p1 = _tcsstr(pszText, _T("\\colortbl"));
+ if (!p1)
+ return;
+
+ pEnd = _tcschr(p1, '}');
+
+ p2 = _tcsstr(p1, _T("\\red"));
+
+ for (i = 0; i < RTF_CTABLE_DEFSIZE; i++)
+ rtf_ctable[i].index = 0;
+
+ default_color = (COLORREF)M->GetDword(FONTMODULE, "Font16Col", 0);
+
+ while (p2 && p2 < pEnd) {
+ if (_stscanf(p2, lpszFmt, &szRed, &szGreen, &szBlue) > 0) {
+ int i;
+ for (i = 0; i < RTF_CTABLE_DEFSIZE; i++) {
+ if (rtf_ctable[i].clr == RGB(_ttoi(szRed), _ttoi(szGreen), _ttoi(szBlue)))
+ rtf_ctable[i].index = iIndex;
+ }
+ }
+ iIndex++;
+ p1 = p2;
+ p1 ++;
+
+ p2 = _tcsstr(p1, _T("\\red"));
+ }
+ return ;
+}
+
+int Utils::RTFColorToIndex(int iCol)
+{
+ int i = 0;
+ for (i = 0; i < RTF_CTABLE_DEFSIZE; i++) {
+ if (rtf_ctable[i].index == iCol)
+ return i + 1;
+ }
+ return 0;
+}
+
+/**
+ * generic error popup dialog procedure
+ */
+INT_PTR CALLBACK Utils::PopupDlgProcError(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, (LPARAM)&hContact);
+
+ switch (message) {
+ case WM_COMMAND:
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_HANDLECLISTEVENT, (WPARAM)hContact, 0);
+ PUDeletePopUp(hWnd);
+ break;
+ case WM_CONTEXTMENU:
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_HANDLECLISTEVENT, (WPARAM)hContact, 0);
+ PUDeletePopUp(hWnd);
+ break;
+ case WM_MOUSEWHEEL:
+ break;
+ case WM_SETCURSOR:
+ break;
+ default:
+ break;
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+/**
+ * read a blob from db into the container settings structure
+ * @param hContact: contact handle (0 = read global)
+ * @param cs TContainerSettings* target structure
+ * @return 0 on success, 1 failure (blob does not exist OR is not a valid private setting structure
+ */
+int Utils::ReadContainerSettingsFromDB(const HANDLE hContact, TContainerSettings *cs, const char *szKey)
+{
+ DBVARIANT dbv = {0};
+
+ CopyMemory(cs, &PluginConfig.globalContainerSettings, sizeof(TContainerSettings));
+
+ if(0 == DBGetContactSetting(hContact, SRMSGMOD_T, szKey ? szKey : CNT_KEYNAME, &dbv)) {
+ if(dbv.type == DBVT_BLOB && dbv.cpbVal > 0 && dbv.cpbVal <= sizeof(TContainerSettings)) {
+ ::CopyMemory((void *)cs, (void *)dbv.pbVal, dbv.cpbVal);
+ ::DBFreeVariant(&dbv);
+ if(hContact == 0 && szKey == 0)
+ cs->fPrivate = false;
+ return(0);
+ }
+ cs->fPrivate = false;
+ DBFreeVariant(&dbv);
+ return(1);
+ }
+ else {
+ cs->fPrivate = false;
+ return(1);
+ }
+}
+
+int Utils::WriteContainerSettingsToDB(const HANDLE hContact, TContainerSettings *cs, const char *szKey)
+{
+ DBWriteContactSettingBlob(hContact, SRMSGMOD_T, szKey ? szKey : CNT_KEYNAME, cs, sizeof(TContainerSettings));
+ return(0);
+}
+
+void Utils::SettingsToContainer(TContainerData *pContainer)
+{
+ pContainer->dwFlags = pContainer->settings->dwFlags;
+ pContainer->dwFlagsEx = pContainer->settings->dwFlagsEx;
+ pContainer->avatarMode = pContainer->settings->avatarMode;
+ pContainer->ownAvatarMode = pContainer->settings->ownAvatarMode;
+}
+
+void Utils::ContainerToSettings(TContainerData *pContainer)
+{
+ pContainer->settings->dwFlags = pContainer->dwFlags;
+ pContainer->settings->dwFlagsEx = pContainer->dwFlagsEx;
+ pContainer->settings->avatarMode = pContainer->avatarMode;
+ pContainer->settings->ownAvatarMode = pContainer->ownAvatarMode;
+}
+
+/**
+ * read settings for a container with private settings enabled.
+ *
+ * @param pContainer container window info struct
+ * @param fForce true -> force them private, even if they were not marked as private in the db
+ */
+void Utils::ReadPrivateContainerSettings(TContainerData *pContainer, bool fForce)
+{
+ char szCname[50];
+ TContainerSettings csTemp = {0};
+
+ mir_snprintf(szCname, 40, "%s%d_Blob", CNT_BASEKEYNAME, pContainer->iContainerIndex);
+ Utils::ReadContainerSettingsFromDB(0, &csTemp, szCname);
+ if(csTemp.fPrivate || fForce) {
+ if(pContainer->settings == 0 || pContainer->settings == &PluginConfig.globalContainerSettings)
+ pContainer->settings = (TContainerSettings *)malloc(sizeof(TContainerSettings));
+ CopyMemory((void *)pContainer->settings, (void *)&csTemp, sizeof(TContainerSettings));
+ pContainer->settings->fPrivate = true;
+ }
+ else
+ pContainer->settings = &PluginConfig.globalContainerSettings;
+}
+
+void Utils::SaveContainerSettings(TContainerData *pContainer, const char *szSetting)
+{
+ char szCName[50];
+
+ pContainer->dwFlags &= ~(CNT_DEFERREDCONFIGURE | CNT_CREATE_MINIMIZED | CNT_DEFERREDSIZEREQUEST | CNT_CREATE_CLONED);
+ if(pContainer->settings->fPrivate) {
+ _snprintf(szCName, 40, "%s%d_Blob", szSetting, pContainer->iContainerIndex);
+ WriteContainerSettingsToDB(0, pContainer->settings, szCName);
+ }
+ mir_snprintf(szCName, 40, "%s%d_theme", szSetting, pContainer->iContainerIndex);
+ if (lstrlen(pContainer->szRelThemeFile) > 1) {
+ if(pContainer->fPrivateThemeChanged == TRUE) {
+ M->pathToRelative(pContainer->szRelThemeFile, pContainer->szAbsThemeFile);
+ M->WriteTString(NULL, SRMSGMOD_T, szCName, pContainer->szAbsThemeFile);
+ pContainer->fPrivateThemeChanged = FALSE;
+ }
+ }
+ else {
+ ::DBDeleteContactSetting(NULL, SRMSGMOD_T, szCName);
+ pContainer->fPrivateThemeChanged = FALSE;
+ }
+}
+
+/**
+ * calculate new width and height values for a user picture (avatar)
+ *
+ * @param: maxHeight - determines maximum height for the picture, width will
+ * be scaled accordingly.
+ */
+void Utils::scaleAvatarHeightLimited(const HBITMAP hBm, double& dNewWidth, double& dNewHeight, LONG maxHeight)
+{
+ BITMAP bm;
+ double dAspect;
+
+ GetObject(hBm, sizeof(bm), &bm);
+
+ if (bm.bmHeight > bm.bmWidth) {
+ if (bm.bmHeight > 0)
+ dAspect = (double)(maxHeight) / (double)bm.bmHeight;
+ else
+ dAspect = 1.0;
+ dNewWidth = (double)bm.bmWidth * dAspect;
+ dNewHeight = (double)maxHeight;
+ } else {
+ if (bm.bmWidth > 0)
+ dAspect = (double)(maxHeight) / (double)bm.bmWidth;
+ else
+ dAspect = 1.0;
+ dNewHeight = (double)bm.bmHeight * dAspect;
+ dNewWidth = (double)maxHeight;
+ }
+}
+
+/**
+ * convert the avatar bitmap to icon format so that it can be used on the task bar
+ * tries to keep correct aspect ratio of the avatar image
+ *
+ * @param dat: _MessageWindowData* pointer to the window data
+ * @return HICON: the icon handle
+ */
+HICON Utils::iconFromAvatar(const TWindowData *dat)
+{
+ double dNewWidth, dNewHeight;
+ bool fFree = false;
+ HIMAGELIST hIml_c = 0;
+ HICON hIcon = 0;
+
+ if(!ServiceExists(MS_AV_GETAVATARBITMAP))
+ return(0);
+
+ if(dat) {
+ AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)dat->hContact, 0);
+ LONG lIconSize = Win7Taskbar->getIconSize();
+
+ if(ace && ace->hbmPic) {
+ scaleAvatarHeightLimited(ace->hbmPic, dNewWidth, dNewHeight, lIconSize);
+ /*
+ * resize picture to fit it on the task bar, use an image list for converting it to
+ * 32bpp icon format
+ * dat->hTaskbarIcon will cache it until avatar is changed
+ */
+ HBITMAP hbmResized = CSkin::ResizeBitmap(ace->hbmPic, (LONG)dNewWidth, (LONG)dNewHeight, fFree);
+ hIml_c = ::ImageList_Create(lIconSize, lIconSize, ILC_COLOR32 | ILC_MASK, 1, 0);
+
+ RECT rc = {0, 0, lIconSize, lIconSize};
+
+ HDC hdc = ::GetDC(dat->pContainer->hwnd);
+ HDC dc = ::CreateCompatibleDC(hdc);
+ HDC dcResized = ::CreateCompatibleDC(hdc);
+
+ ReleaseDC(dat->pContainer->hwnd, hdc);
+
+ HBITMAP hbmNew = CSkin::CreateAeroCompatibleBitmap(rc, dc);
+ HBITMAP hbmOld = reinterpret_cast<HBITMAP>(::SelectObject(dc, hbmNew));
+ HBITMAP hbmOldResized = reinterpret_cast<HBITMAP>(::SelectObject(dcResized, hbmResized));
+
+ LONG ix = (lIconSize - (LONG)dNewWidth) / 2;
+ LONG iy = (lIconSize - (LONG)dNewHeight) / 2;
+ CSkin::m_default_bf.SourceConstantAlpha = M->GetByte("taskBarIconAlpha", 255);
+ CMimAPI::m_MyAlphaBlend(dc, ix, iy, (LONG)dNewWidth, (LONG)dNewHeight, dcResized,
+ 0, 0, (LONG)dNewWidth, (LONG)dNewHeight, CSkin::m_default_bf);
+
+ CSkin::m_default_bf.SourceConstantAlpha = 255;
+ ::SelectObject(dc, hbmOld);
+ ::ImageList_Add(hIml_c, hbmNew, 0);
+ ::DeleteObject(hbmNew);
+ ::DeleteDC(dc);
+
+ ::SelectObject(dcResized, hbmOldResized);
+ if(hbmResized != ace->hbmPic)
+ ::DeleteObject(hbmResized);
+ ::DeleteDC(dcResized);
+ hIcon = ::ImageList_GetIcon(hIml_c, 0, ILD_NORMAL);
+ ::ImageList_RemoveAll(hIml_c);
+ ::ImageList_Destroy(hIml_c);
+ }
+ }
+ return(hIcon);
+}
+
+AVATARCACHEENTRY* Utils::loadAvatarFromAVS(const HANDLE hContact)
+{
+ if(ServiceExists(MS_AV_GETAVATARBITMAP))
+ return(reinterpret_cast<AVATARCACHEENTRY *>(CallService(MS_AV_GETAVATARBITMAP, (WPARAM)hContact, 0)));
+ else
+ return(0);
+}
+
+void Utils::getIconSize(HICON hIcon, int& sizeX, int& sizeY)
+{
+ ICONINFO ii;
+ BITMAP bm;
+ ::GetIconInfo(hIcon, &ii);
+ ::GetObject(ii.hbmColor, sizeof(bm), &bm);
+ sizeX = bm.bmWidth;
+ sizeY = bm.bmHeight;
+ ::DeleteObject(ii.hbmMask);
+ ::DeleteObject(ii.hbmColor);
+}
+
+/**
+ * add a menu item to a ownerdrawn menu. mii must be pre-initialized
+ *
+ * @param m menu handle
+ * @param mii menu item info structure
+ * @param hIcon the icon (0 allowed -> no icon)
+ * @param szText menu item text (must NOT be 0)
+ * @param uID the item command id
+ * @param pos zero-based position index
+ */
+void Utils::addMenuItem(const HMENU& m, MENUITEMINFO& mii, HICON hIcon, const TCHAR *szText, UINT uID, UINT pos)
+{
+ mii.wID = uID;
+ mii.dwItemData = (ULONG_PTR)hIcon;
+ mii.dwTypeData = const_cast<TCHAR *>(szText);
+ mii.cch = lstrlen(mii.dwTypeData) + 1;
+
+ ::InsertMenuItem(m, pos, TRUE, &mii);
+}
+
+/**
+ * return != 0 when the sound effect must be played for the given
+ * session. Uses container sound settings
+ */
+int TSAPI Utils::mustPlaySound(const TWindowData *dat)
+{
+ if(!dat)
+ return(0);
+
+ if(dat->pContainer->fHidden) // hidden container is treated as closed, so play the sound
+ return(1);
+
+ if(dat->pContainer->dwFlags & CNT_NOSOUND || nen_options.iNoSounds)
+ return(0);
+
+ bool fActiveWindow = (dat->pContainer->hwnd == ::GetForegroundWindow() ? true : false);
+ bool fActiveTab = (dat->pContainer->hwndActive == dat->hwnd ? true : false);
+ bool fIconic = (::IsIconic(dat->pContainer->hwnd) ? true : false);
+
+ /*
+ * window minimized, check if sound has to be played
+ */
+ if(fIconic)
+ return(dat->pContainer->dwFlagsEx & CNT_EX_SOUNDS_MINIMIZED ? 1 : 0);
+
+ /*
+ * window in foreground
+ */
+ if(fActiveWindow) {
+ if(fActiveTab)
+ return(dat->pContainer->dwFlagsEx & CNT_EX_SOUNDS_FOCUSED ? 1 : 0);
+ else
+ return(dat->pContainer->dwFlagsEx & CNT_EX_SOUNDS_INACTIVETABS ? 1 : 0);
+ }
+ else
+ return(dat->pContainer->dwFlagsEx & CNT_EX_SOUNDS_UNFOCUSED ? 1 : 0);
+
+ return(1);
+}
+
+/**
+ * enable or disable a dialog control
+ */
+void TSAPI Utils::enableDlgControl(const HWND hwnd, UINT id, BOOL fEnable)
+{
+ ::EnableWindow(::GetDlgItem(hwnd, id), fEnable);
+}
+
+/**
+ * show or hide a dialog control
+ */
+void TSAPI Utils::showDlgControl(const HWND hwnd, UINT id, int showCmd)
+{
+ ::ShowWindow(::GetDlgItem(hwnd, id), showCmd);
+}
+
+/*
+ * stream function to write the contents of the message log to an rtf file
+ */
+DWORD CALLBACK Utils::StreamOut(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb)
+{
+ HANDLE hFile;
+ TCHAR *szFilename = (TCHAR *)dwCookie;
+ if ((hFile = CreateFile(szFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) {
+ SetFilePointer(hFile, 0, NULL, FILE_END);
+ FilterEventMarkers(reinterpret_cast<TCHAR *>(pbBuff));
+ WriteFile(hFile, pbBuff, cb, (DWORD *)pcb, NULL);
+ *pcb = cb;
+ CloseHandle(hFile);
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * extract a resource from the given module
+ * tszPath must end with \
+ */
+void TSAPI Utils::extractResource(const HMODULE h, const UINT uID, const TCHAR *tszName, const TCHAR *tszPath,
+ const TCHAR *tszFilename, bool fForceOverwrite)
+{
+ HRSRC hRes;
+ HGLOBAL hResource;
+ TCHAR szFilename[MAX_PATH];
+
+ hRes = FindResource(h, MAKEINTRESOURCE(uID), tszName);
+
+ if(hRes) {
+ hResource = LoadResource(h, hRes);
+ if(hResource) {
+ HANDLE hFile;
+ char *pData = (char *)LockResource(hResource);
+ DWORD dwSize = SizeofResource(g_hInst, hRes), written = 0;
+ mir_sntprintf(szFilename, MAX_PATH, _T("%s%s"), tszPath, tszFilename);
+ if(!fForceOverwrite) {
+ if(PathFileExists(szFilename))
+ return;
+ }
+ if((hFile = CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
+ WriteFile(hFile, (void *)pData, dwSize, &written, NULL);
+ CloseHandle(hFile);
+ }
+ else
+ throw(CRTException("Error while extracting aero skin images, Aero mode disabled.", szFilename));
+ }
+ }
+}
+
+/**
+ * extract the clicked URL from a rich edit control. Return the URL as TCHAR*
+ * caller MUST mir_free() the returned string
+ * @param hwndRich - rich edit window handle
+ * @return wchar_t* extracted URL
+ */
+const wchar_t* Utils::extractURLFromRichEdit(const ENLINK* _e, const HWND hwndRich)
+{
+ TEXTRANGEW tr = {0};
+ CHARRANGE sel = {0};
+
+ ::SendMessageW(hwndRich, EM_EXGETSEL, 0, (LPARAM) & sel);
+ if (sel.cpMin != sel.cpMax)
+ return(0);
+
+ tr.chrg = _e->chrg;
+ tr.lpstrText = (wchar_t *)mir_alloc(2 * (tr.chrg.cpMax - tr.chrg.cpMin + 8));
+ ::SendMessageW(hwndRich, EM_GETTEXTRANGE, 0, (LPARAM) & tr);
+ if (wcschr(tr.lpstrText, '@') != NULL && wcschr(tr.lpstrText, ':') == NULL && wcschr(tr.lpstrText, '/') == NULL) {
+ ::MoveMemory(tr.lpstrText + 7, tr.lpstrText, sizeof(wchar_t) * (tr.chrg.cpMax - tr.chrg.cpMin + 1));
+ ::CopyMemory(tr.lpstrText, L"mailto:", 7 * sizeof(wchar_t));
+ }
+ return(tr.lpstrText);
+}
+
+/**
+ * generic command dispatcher
+ * used in various places (context menus, info panel menus etc.)
+ */
+LRESULT Utils::CmdDispatcher(UINT uType, HWND hwndDlg, UINT cmd, WPARAM wParam, LPARAM lParam, TWindowData *dat, TContainerData *pContainer)
+{
+ switch(uType) {
+ case CMD_CONTAINER:
+ if(pContainer && hwndDlg)
+ return(DM_ContainerCmdHandler(pContainer, cmd, wParam, lParam));
+ break;
+ case CMD_MSGDIALOG:
+ if(pContainer && hwndDlg && dat)
+ return(DM_MsgWindowCmdHandler(hwndDlg, pContainer, dat, cmd, wParam, lParam));
+ break;
+ case CMD_INFOPANEL:
+ if(MsgWindowMenuHandler(dat, cmd, MENU_LOGMENU) == 0) {
+ return(DM_MsgWindowCmdHandler(hwndDlg, pContainer, dat, cmd, wParam, lParam));
+ }
+ break;
+ }
+ return(0);
+}
+
+/**
+ * filter out invalid characters from a string used as part of a file
+ * or folder name. All invalid characters will be replaced by spaces.
+ *
+ * @param tszFilename - string to filter.
+ */
+void Utils::sanitizeFilename(wchar_t* tszFilename)
+{
+ static wchar_t *forbiddenCharacters = L"%/\\':|\"<>?";
+ int i;
+
+ for (i = 0; i < lstrlenW(forbiddenCharacters); i++) {
+ wchar_t* szFound = 0;
+
+ while ((szFound = wcschr(tszFilename, (int)forbiddenCharacters[i])) != NULL)
+ *szFound = ' ';
+ }
+}
+
+/**
+ * ensure that a path name ends on a trailing backslash
+ * @param szPathname - pathname to check
+ */
+void Utils::ensureTralingBackslash(wchar_t *szPathname)
+{
+ if(szPathname[lstrlenW(szPathname) - 1] != '\\')
+ wcscat(szPathname, L"\\");
+}
+
+/**
+ * load a system library from the Windows system path and return its module
+ * handle.
+ *
+ * return 0 and throw an exception if something goes wrong.
+ */
+HMODULE Utils::loadSystemLibrary(const wchar_t* szFilename)
+{
+ wchar_t sysPathName[MAX_PATH + 2];
+ HMODULE _h = 0;
+
+ try {
+ if(0 == ::GetSystemDirectoryW(sysPathName, MAX_PATH))
+ throw(CRTException("Error while loading system library", szFilename));
+
+ sysPathName[MAX_PATH - 1] = 0;
+ if(wcslen(sysPathName) + wcslen(szFilename) >= MAX_PATH)
+ throw(CRTException("Error while loading system library", szFilename));
+
+ lstrcatW(sysPathName, szFilename);
+ _h = LoadLibraryW(sysPathName);
+ if(0 == _h)
+ throw(CRTException("Error while loading system library", szFilename));
+ }
+ catch(CRTException& ex) {
+ ex.display();
+ return(0);
+ }
+ return(_h);
+}
+/**
+ * implementation of the CWarning class
+ */
+CWarning::CWarning(const wchar_t *tszTitle, const wchar_t *tszText, const UINT uId, const DWORD dwFlags)
+{
+ m_szTitle = new std::basic_string<wchar_t>(tszTitle);
+ m_szText = new std::basic_string<wchar_t>(tszText);
+ m_uId = uId;
+ m_hFontCaption = 0;
+ m_dwFlags = dwFlags;
+
+ m_fIsModal = ((m_dwFlags & MB_YESNO || m_dwFlags & MB_YESNOCANCEL) ? true : false);
+}
+
+CWarning::~CWarning()
+{
+ delete m_szText;
+ delete m_szTitle;
+
+ if(m_hFontCaption)
+ ::DeleteObject(m_hFontCaption);
+
+#if defined(__LOGDEBUG_)
+ _DebugTraceW(L"destroy object");
+#endif
+}
+
+LRESULT CWarning::ShowDialog() const
+{
+ if(!m_fIsModal) {
+ ::CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_WARNING), 0, stubDlgProc, reinterpret_cast<LPARAM>(this));
+ return(0);
+ }
+ else {
+ LRESULT res = ::DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_WARNING), 0, stubDlgProc, reinterpret_cast<LPARAM>(this));
+ return(res);
+ }
+}
+
+__int64 CWarning::getMask()
+{
+ __int64 mask = 0;
+
+ DWORD dwLow = M->GetDword("cWarningsL", 0);
+ DWORD dwHigh = M->GetDword("cWarningsH", 0);
+
+ mask = ((((__int64)dwHigh) << 32) & 0xffffffff00000000) | dwLow;
+
+ return(mask);
+}
+
+/**
+ * send cancel message to all open warning dialogs so they are destroyed
+ * before TabSRMM is unloaded.
+ *
+ * called by the OkToExit handler in globals.cpp
+ */
+void CWarning::destroyAll()
+{
+ if(hWindowList)
+ WindowList_Broadcast(hWindowList, WM_COMMAND, MAKEWPARAM(IDCANCEL, 0), 0);
+}
+/**
+ * show a CWarning dialog using the id value. Check whether the user has chosen to
+ * not show this message again. This has room for 64 different warning dialogs, which
+ * should be enough in the first place. Extending it should not be too hard though.
+ */
+LRESULT CWarning::show(const int uId, DWORD dwFlags, const wchar_t* tszTxt)
+{
+ wchar_t* separator_pos = 0;
+ __int64 mask = 0, val = 0;
+ LRESULT result = 0;
+ wchar_t* _s = 0;
+
+ if(0 == hWindowList)
+ hWindowList = reinterpret_cast<HANDLE>(::CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0));
+
+ /*
+ * don't open new warnings when shutdown was initiated (modal ones will otherwise
+ * block the shutdown)
+ */
+ if(CMimAPI::m_shutDown)
+ return(-1);
+
+ if(tszTxt)
+ _s = const_cast<wchar_t *>(tszTxt);
+ else {
+ if(uId != -1) {
+ if(dwFlags & CWF_UNTRANSLATED)
+ _s = const_cast<wchar_t *>(CTranslator::getUntranslatedWarning(uId));
+ else {
+ /*
+ * revert to untranslated warning when the translated message
+ * is not well-formatted.
+ */
+ _s = const_cast<wchar_t *>(CTranslator::getWarning(uId));
+
+ if(wcslen(_s) < 3 || 0 == wcschr(_s, '|'))
+ _s = const_cast<wchar_t *>(CTranslator::getUntranslatedWarning(uId));
+ }
+ }
+ else if(-1 == uId && tszTxt) {
+ dwFlags |= CWF_NOALLOWHIDE;
+ _s = (dwFlags & CWF_UNTRANSLATED ? const_cast<wchar_t *>(tszTxt) : TranslateW(tszTxt));
+ }
+ else
+ return(-1);
+ }
+
+ if((wcslen(_s) > 3) && ((separator_pos = wcschr(_s, '|')) != 0)) {
+
+ if(uId >= 0) {
+ mask = getMask();
+ val = ((__int64)1L) << uId;
+ }
+ else
+ mask = val = 0;
+
+ if(0 == (mask & val) || dwFlags & CWF_NOALLOWHIDE) {
+
+ wchar_t *s = reinterpret_cast<wchar_t *>(mir_alloc((wcslen(_s) + 1) * 2));
+ wcscpy(s, _s);
+ separator_pos = wcschr(s, '|');
+
+ if(separator_pos) {
+ separator_pos[0] = 0;
+
+ CWarning *w = new CWarning(s, &separator_pos[1], uId, dwFlags);
+ if(!(dwFlags & MB_YESNO || dwFlags & MB_YESNOCANCEL)) {
+ w->ShowDialog();
+ mir_free(s);
+ }
+ else {
+ result = w->ShowDialog();
+ mir_free(s);
+ return(result);
+ }
+ }
+ else
+ mir_free(s);
+ }
+ }
+ return(-1);
+}
+
+/**
+ * stub dlg procedure. Just register the object pointer in WM_INITDIALOG
+ */
+INT_PTR CALLBACK CWarning::stubDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CWarning *w = reinterpret_cast<CWarning *>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
+ if(w)
+ return(w->dlgProc(hwnd, msg, wParam, lParam));
+
+ switch(msg) {
+ case WM_INITDIALOG: {
+ w = reinterpret_cast<CWarning *>(lParam);
+ if(w) {
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
+ return(w->dlgProc(hwnd, msg, wParam, lParam));
+ }
+ break;
+ }
+
+#if defined(__LOGDEBUG_)
+ case WM_NCDESTROY:
+ _DebugTraceW(L"window destroyed");
+ break;
+#endif
+
+ default:
+ break;
+ }
+ return(FALSE);
+}
+
+/**
+ * dialog procedure for the warning dialog box
+ */
+INT_PTR CALLBACK CWarning::dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG: {
+ HICON hIcon = 0;
+ UINT uResId = 0;
+ TCHAR temp[1024];
+ SETTEXTEX stx = {ST_SELECTION, CP_UTF8};
+ size_t pos = 0;
+
+ m_hwnd = hwnd;
+
+ ::SetWindowTextW(hwnd, CTranslator::get(CTranslator::GEN_STRING_WARNING_TITLE));
+ ::SendMessage(hwnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(::LoadSkinnedIconBig(SKINICON_OTHER_MIRANDA)));
+ ::SendMessage(hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(::LoadSkinnedIcon(SKINICON_OTHER_MIRANDA)));
+ ::SendDlgItemMessage(hwnd, IDC_WARNTEXT, EM_AUTOURLDETECT, (WPARAM) TRUE, 0);
+ ::SendDlgItemMessage(hwnd, IDC_WARNTEXT, EM_SETEVENTMASK, 0, ENM_LINK);
+
+ mir_sntprintf(temp, 1024, RTF_DEFAULT_HEADER, 0, 0, 0, 30*15);
+ tstring *str = new tstring(temp);
+
+ str->append(m_szText->c_str());
+ str->append(L"}");
+
+ TranslateDialogDefault(hwnd);
+
+ /*
+ * convert normal line breaks to rtf
+ */
+ while((pos = str->find(L"\n")) != str->npos) {
+ str->erase(pos, 1);
+ str->insert(pos, L"\\line ");
+ }
+
+ char *utf8 = M->utf8_encodeT(str->c_str());
+ ::SendDlgItemMessage(hwnd, IDC_WARNTEXT, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)utf8);
+ mir_free(utf8);
+ delete str;
+
+ ::SetDlgItemTextW(hwnd, IDC_CAPTION, m_szTitle->c_str());
+
+ if(m_dwFlags & CWF_NOALLOWHIDE)
+ Utils::showDlgControl(hwnd, IDC_DONTSHOWAGAIN, SW_HIDE);
+ if(m_dwFlags & MB_YESNO || m_dwFlags & MB_YESNOCANCEL) {
+ Utils::showDlgControl(hwnd, IDOK, SW_HIDE);
+ ::SetFocus(::GetDlgItem(hwnd, IDCANCEL));
+ }
+ else {
+ Utils::showDlgControl(hwnd, IDCANCEL, SW_HIDE);
+ Utils::showDlgControl(hwnd, IDYES, SW_HIDE);
+ Utils::showDlgControl(hwnd, IDNO, SW_HIDE);
+ ::SetFocus(::GetDlgItem(hwnd, IDOK));
+ }
+ if(m_dwFlags & MB_ICONERROR || m_dwFlags & MB_ICONHAND)
+ uResId = 32513;
+ else if(m_dwFlags & MB_ICONEXCLAMATION || m_dwFlags & MB_ICONWARNING)
+ uResId = 32515;
+ else if(m_dwFlags & MB_ICONASTERISK || m_dwFlags & MB_ICONINFORMATION)
+ uResId = 32516;
+ else if(m_dwFlags & MB_ICONQUESTION)
+ uResId = 32514;
+
+ if(uResId)
+ hIcon = reinterpret_cast<HICON>(::LoadImage(0, MAKEINTRESOURCE(uResId), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
+ else
+ hIcon = ::LoadSkinnedIconBig(SKINICON_EVENT_MESSAGE);
+
+ ::SendDlgItemMessageW(hwnd, IDC_WARNICON, STM_SETICON, reinterpret_cast<WPARAM>(hIcon), 0);
+ if(!(m_dwFlags & MB_YESNO || m_dwFlags & MB_YESNOCANCEL))
+ ::ShowWindow(hwnd, SW_SHOWNORMAL);
+
+ WindowList_Add(hWindowList, hwnd, hwnd);
+ return(TRUE);
+ }
+
+ case WM_CTLCOLORSTATIC: {
+ HWND hwndChild = reinterpret_cast<HWND>(lParam);
+ UINT id = ::GetDlgCtrlID(hwndChild);
+ if(0 == m_hFontCaption) {
+ HFONT hFont = reinterpret_cast<HFONT>(::SendDlgItemMessage(hwnd, IDC_CAPTION, WM_GETFONT, 0, 0));
+ LOGFONT lf = {0};
+
+ ::GetObject(hFont, sizeof(lf), &lf);
+ lf.lfHeight = (int)((double)lf.lfHeight * 1.7f);
+ m_hFontCaption = ::CreateFontIndirect(&lf);
+ ::SendDlgItemMessage(hwnd, IDC_CAPTION, WM_SETFONT, (WPARAM)m_hFontCaption, FALSE);
+ }
+
+ if(IDC_CAPTION == id) {
+ ::SetTextColor(reinterpret_cast<HDC>(wParam), ::GetSysColor(COLOR_HIGHLIGHT));
+ ::SendMessage(hwndChild, WM_SETFONT, (WPARAM)m_hFontCaption, FALSE);
+ }
+
+ if(IDC_WARNGROUP != id && IDC_DONTSHOWAGAIN != id) {
+ ::SetBkColor((HDC)wParam, ::GetSysColor(COLOR_WINDOW));
+ return reinterpret_cast<INT_PTR>(::GetSysColorBrush(COLOR_WINDOW));
+ }
+ break;
+ }
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ case IDYES:
+ case IDNO:
+ if(!m_fIsModal && (IDOK == LOWORD(wParam) || IDCANCEL == LOWORD(wParam))) { // modeless dialogs can receive a IDCANCEL from destroyAll()
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ delete this;
+ WindowList_Remove(hWindowList, hwnd);
+ ::DestroyWindow(hwnd);
+ }
+ else {
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ delete this;
+ WindowList_Remove(hWindowList, hwnd);
+ ::EndDialog(hwnd, LOWORD(wParam));
+ }
+ break;
+
+ case IDC_DONTSHOWAGAIN: {
+ __int64 mask = getMask(), val64 = ((__int64)1L << m_uId), newVal = 0;
+
+ newVal = mask | val64;
+
+ if(::IsDlgButtonChecked(hwnd, IDC_DONTSHOWAGAIN)) {
+ DWORD val = (DWORD)(newVal & 0x00000000ffffffff);
+ M->WriteDword(SRMSGMOD_T, "cWarningsL", val);
+ val = (DWORD)((newVal >> 32) & 0x00000000ffffffff);
+ M->WriteDword(SRMSGMOD_T, "cWarningsH", val);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+
+ case WM_NOTIFY: {
+ switch (((NMHDR *) lParam)->code) {
+ case EN_LINK:
+ switch (((ENLINK *) lParam)->msg) {
+ case WM_LBUTTONUP: {
+ ENLINK* e = reinterpret_cast<ENLINK *>(lParam);
+
+ const wchar_t* wszUrl = Utils::extractURLFromRichEdit(e, ::GetDlgItem(hwnd, IDC_WARNTEXT));
+ if(wszUrl) {
+ char* szUrl = mir_t2a(wszUrl);
+
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM)szUrl);
+ mir_free(szUrl);
+ mir_free(const_cast<TCHAR *>(wszUrl));
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return(FALSE);
+}
diff --git a/plugins/TabSRMM/tabmodplus/icons/imgclose.ico b/plugins/TabSRMM/tabmodplus/icons/imgclose.ico
new file mode 100644
index 0000000000..615b00a98e
--- /dev/null
+++ b/plugins/TabSRMM/tabmodplus/icons/imgclose.ico
Binary files differ
diff --git a/plugins/TabSRMM/tabmodplus/icons/imgopen.ico b/plugins/TabSRMM/tabmodplus/icons/imgopen.ico
new file mode 100644
index 0000000000..c1a5c7514e
--- /dev/null
+++ b/plugins/TabSRMM/tabmodplus/icons/imgopen.ico
Binary files differ
diff --git a/plugins/TabSRMM/tabmodplus/modplus.cpp b/plugins/TabSRMM/tabmodplus/modplus.cpp
new file mode 100644
index 0000000000..b20b17c99e
--- /dev/null
+++ b/plugins/TabSRMM/tabmodplus/modplus.cpp
@@ -0,0 +1,276 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: modplus.cpp 11848 2010-05-27 14:57:22Z silvercircle $
+ *
+ * implements features of the tabSRMM "MADMOD" patch, developed by
+ * Mad Cluster in May 2008
+ *
+ * the "mad mod" patch added the following features:
+ *
+ * ) typing sounds
+ * ) support for animated avatars through ACC (avs)
+ * ) a fully customizable tool bar providing services useable by external plugins
+ * to add and change buttons
+ * ) toolbar on the bottom
+ * ) image tag button
+ * ) client icon in status bar
+ * ) close tab/window on send and the "hide container feature"
+ * ) bug fixes
+ *
+ */
+
+#include "../src/commonheaders.h"
+
+static HANDLE hEventCBButtonPressed,hEventCBInit, hEventDbOptionsInit, hEventDbPluginsLoaded;
+
+int g_bStartup=0;
+
+BOOL g_bIMGtagButton;
+
+static char* getMirVer(HANDLE hContact)
+{
+ char *szProto = NULL;
+ char *msg = NULL;
+ DBVARIANT dbv = {0};
+
+ szProto = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if ( !szProto )
+ return (NULL);
+
+ if ( !DBGetContactSettingString(hContact, szProto, "MirVer", &dbv) ) {
+ msg=mir_strdup(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ return (msg);
+}
+
+static TCHAR* getMenuEntry(int i) {
+ TCHAR *msg = NULL;
+ char MEntry[256] = {'\0'};
+ DBVARIANT dbv = {0};
+
+ mir_snprintf(MEntry, 255, "MenuEntry_%u", i);
+ if ( !M->GetTString(NULL, "tabmodplus",MEntry, &dbv) ) {
+ msg = mir_tstrdup(dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ return (msg);
+}
+
+int ChangeClientIconInStatusBar(const TWindowData *dat)
+{
+ if(!ServiceExists(MS_FP_GETCLIENTICON))
+ return(S_FALSE);
+
+ char *msg = getMirVer(dat->hContact);
+
+ if ( !msg )
+ return (S_FALSE);
+
+ StatusIconData sid = {0};
+
+ sid.cbSize = sizeof(sid);
+ sid.szModule = (char *)"tabmodplus";
+ sid.hIcon = sid.hIconDisabled = dat->hClientIcon;
+ sid.dwId = 1;
+ sid.szTooltip = msg;
+ sid.flags = MBF_OWNERSTATE;
+ CallService(MS_MSG_MODIFYICON,(WPARAM)dat->hContact, (LPARAM)&sid);
+ mir_free(msg);
+ return (S_OK);
+}
+
+
+int ModPlus_PreShutdown(WPARAM wparam, LPARAM lparam)
+{
+ if ( hEventCBButtonPressed )
+ UnhookEvent(hEventCBButtonPressed);
+ if ( hEventCBInit )
+ UnhookEvent(hEventCBInit);
+ UnhookEvent(hEventDbPluginsLoaded);
+ UnhookEvent(hEventDbOptionsInit);
+
+ return (0);
+}
+
+static int RegisterCustomButton(WPARAM wParam,LPARAM lParam)
+{
+ if ( ServiceExists(MS_BB_ADDBUTTON) ) {
+ BBButton bbd = {0};
+ bbd.cbSize = sizeof(BBButton);
+ bbd.bbbFlags = BBBF_ISIMBUTTON|BBBF_ISLSIDEBUTTON|BBBF_ISPUSHBUTTON;
+ bbd.dwButtonID = 1;
+ bbd.dwDefPos =200;
+ bbd.hIcon = PluginConfig.g_buttonBarIconHandles[3];
+ bbd.pszModuleName = (char *)"Tabmodplus";
+ bbd.ptszTooltip = const_cast<TCHAR *>(CTranslator::get(CTranslator::GEN_BB_IMGTOOLTIP));
+
+ return (CallService(MS_BB_ADDBUTTON, 0, (LPARAM)&bbd));
+ }
+ return (1);
+}
+
+static int CustomButtonPressed(WPARAM wParam,LPARAM lParam)
+{
+ CustomButtonClickData *cbcd=(CustomButtonClickData *)lParam;
+
+ CHARRANGE cr;
+ TCHAR* pszMenu[256]={0};//=NULL;
+ int i=0;
+ TCHAR* pszText = (TCHAR *)_T("");
+ TCHAR* pszFormatedText=NULL;
+ UINT textlenght=0;
+ BBButton bbd={0};
+
+ int state=0;
+
+ if ( strcmp(cbcd->pszModule,"Tabmodplus")||cbcd->dwButtonId!=1 ) return (0);
+
+ bbd.cbSize=sizeof(BBButton);
+ bbd.dwButtonID=1;
+ bbd.pszModuleName = (char *)"Tabmodplus";
+ CallService(MS_BB_GETBUTTONSTATE, wParam, (LPARAM)&bbd);
+
+ cr.cpMin = cr.cpMax = 0;
+ SendDlgItemMessage(cbcd->hwndFrom,IDC_MESSAGE, EM_EXGETSEL, 0, (LPARAM)&cr);
+ textlenght=cr.cpMax-cr.cpMin;
+ if ( textlenght ) {
+ pszText = (TCHAR *)mir_alloc((textlenght+1)*sizeof(TCHAR));
+ ZeroMemory(pszText,(textlenght+1)*sizeof(TCHAR));
+ SendDlgItemMessage(cbcd->hwndFrom, IDC_MESSAGE,EM_GETSELTEXT, 0, (LPARAM)pszText);
+ }
+
+ if ( cbcd->flags & BBCF_RIGHTBUTTON )
+ state=1;
+ else if ( textlenght )
+ state = 2;
+ else if ( bbd.bbbFlags & BBSF_PUSHED )
+ state = 3;
+ else
+ state = 4;
+
+ switch ( state ) {
+ case 1:
+ {
+ int res=0;
+ int menunum;
+ int menulimit;
+ HMENU hMenu=NULL;
+
+ menulimit = M->GetByte("tabmodplus","MenuCount", 0);
+ if ( menulimit ) {
+ hMenu = CreatePopupMenu();
+ //pszMenu=malloc(menulimit*sizeof(TCHAR*));
+ } else break;
+ for ( menunum=0;menunum<menulimit;menunum++ ) {
+ pszMenu[menunum]=getMenuEntry(menunum);
+ AppendMenu(hMenu, MF_STRING,menunum+1, pszMenu[menunum]);
+ }
+ res = TrackPopupMenu(hMenu, TPM_RETURNCMD, cbcd->pt.x, cbcd->pt.y, 0, cbcd->hwndFrom, NULL);
+ if ( res==0 ) break;
+
+ pszFormatedText = (TCHAR *)mir_alloc((textlenght+lstrlen(pszMenu[res-1])+2)*sizeof(TCHAR));
+ ZeroMemory(pszFormatedText,(textlenght+lstrlen(pszMenu[res-1])+2)*sizeof(TCHAR));
+
+ mir_sntprintf(pszFormatedText,(textlenght+lstrlen(pszMenu[res-1])+2)*sizeof(TCHAR),pszMenu[res-1],pszText);
+
+ }break;
+ case 2:
+ {
+ pszFormatedText = (TCHAR *)mir_alloc((textlenght+12)*sizeof(TCHAR));
+ ZeroMemory(pszFormatedText,(textlenght+12)*sizeof(TCHAR));
+
+ SendDlgItemMessage(cbcd->hwndFrom, IDC_MESSAGE,EM_GETSELTEXT, 0, (LPARAM)pszText);
+ mir_sntprintf(pszFormatedText,(textlenght+12)*sizeof(TCHAR),_T("[img]%s[/img]"),pszText);
+
+ bbd.ptszTooltip=0;
+ bbd.hIcon=0;
+ bbd.bbbFlags=BBSF_RELEASED;
+ CallService(MS_BB_SETBUTTONSTATE, wParam, (LPARAM)&bbd);
+ }break;
+
+ case 3:
+ {
+ pszFormatedText = (TCHAR *)mir_alloc(6*sizeof(TCHAR));
+ ZeroMemory(pszFormatedText,6*sizeof(TCHAR));
+
+ _sntprintf(pszFormatedText,6*sizeof(TCHAR),_T("%s"),_T("[img]"));
+
+ bbd.ptszTooltip = const_cast<TCHAR *>(CTranslator::get(CTranslator::GEN_BB_IMGTOOLTIP));
+ CallService(MS_BB_SETBUTTONSTATE, wParam, (LPARAM)&bbd);
+
+ }break;
+ case 4:
+ {
+
+ pszFormatedText = (TCHAR *)mir_alloc(7*sizeof(TCHAR));
+ ZeroMemory(pszFormatedText,7*sizeof(TCHAR));
+ _sntprintf(pszFormatedText,7*sizeof(TCHAR),_T("%s"),_T("[/img]"));
+
+ bbd.ptszTooltip = const_cast<TCHAR *>(CTranslator::get(CTranslator::GEN_BB_IMGTOOLTIP));
+ CallService(MS_BB_SETBUTTONSTATE, wParam, (LPARAM)&bbd);
+
+ }break;
+ }
+
+ while ( pszMenu[i] ) {
+ mir_free(pszMenu[i]);
+ i++;
+ }
+
+ if ( pszFormatedText ) SendDlgItemMessage(cbcd->hwndFrom, IDC_MESSAGE, EM_REPLACESEL, TRUE, (LPARAM)pszFormatedText);
+
+ if ( textlenght ) mir_free(pszText);
+ if ( pszFormatedText ) mir_free(pszFormatedText);
+ return (1);
+
+}
+
+#define MBF_OWNERSTATE 0x04
+
+int ModPlus_Init(WPARAM wparam,LPARAM lparam)
+{
+ g_bStartup = 1;
+
+ hEventCBButtonPressed=HookEvent(ME_MSG_BUTTONPRESSED,CustomButtonPressed);
+ hEventCBInit=HookEvent(ME_MSG_TOOLBARLOADED,RegisterCustomButton);
+
+ if (PluginConfig.g_bClientInStatusBar&&ServiceExists(MS_MSG_ADDICON) ) {
+ StatusIconData sid = {0};
+ sid.cbSize = sizeof(sid);
+ sid.szModule = (char *)"tabmodplus";
+ sid.flags = MBF_OWNERSTATE|MBF_HIDDEN;
+ sid.dwId = 1;
+ sid.szTooltip = 0;
+ sid.hIcon = sid.hIconDisabled = 0;
+ CallService(MS_MSG_ADDICON, 0, (LPARAM)&sid);
+ }
+ g_bStartup = 0;
+ return (0);
+}
diff --git a/plugins/TabSRMM/tabmodplus/msgoptions_plus.cpp b/plugins/TabSRMM/tabmodplus/msgoptions_plus.cpp
new file mode 100644
index 0000000000..7b2c19bd26
--- /dev/null
+++ b/plugins/TabSRMM/tabmodplus/msgoptions_plus.cpp
@@ -0,0 +1,207 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: msgoptions_plus.cpp 13034 2010-10-24 20:39:04Z silvercircle $
+ *
+ * implements the "advanced tweak" option page
+ *
+ * originally developed by Mad Cluster for the tabSRMM "MADMOD" patch in
+ * May 2008.
+ *
+ */
+
+#include "../src/commonheaders.h"
+
+extern HINSTANCE hinstance;
+extern BOOL g_bIMGtagButton;
+extern HIMAGELIST g_himlOptions, CreateStateImageList();
+
+INT_PTR CALLBACK PlusOptionsProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+
+ case WM_INITDIALOG: {
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PLUS_CHECKTREE), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PLUS_CHECKTREE), GWL_STYLE) | (TVS_NOHSCROLL | TVS_CHECKBOXES));
+
+ g_himlOptions = (HIMAGELIST)SendDlgItemMessage(hwndDlg, IDC_PLUS_CHECKTREE, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)CreateStateImageList());
+ ImageList_Destroy(g_himlOptions);
+
+ /*
+ * fill the list box, create groups first, then add items
+ */
+
+ SendMessage(hwndDlg, WM_USER + 100, 0, 0);
+
+ return TRUE;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case IDC_PLUS_CHECKTREE:
+ if (((LPNMHDR)lParam)->code == NM_CLICK || (((LPNMHDR)lParam)->code == TVN_KEYDOWN && ((LPNMTVKEYDOWN)lParam)->wVKey == VK_SPACE)) {
+ TVHITTESTINFO hti;
+ TVITEM item = {0};
+
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ item.stateMask = TVIS_STATEIMAGEMASK | TVIS_BOLD;
+ hti.pt.x = (short)LOWORD(GetMessagePos());
+ hti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt);
+ if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti) || ((LPNMHDR)lParam)->code == TVN_KEYDOWN) {
+ if (((LPNMHDR)lParam)->code == TVN_KEYDOWN) {
+ hti.flags |= TVHT_ONITEMSTATEICON;
+ item.hItem = TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom);
+ } else
+ item.hItem = (HTREEITEM)hti.hItem;
+ SendDlgItemMessageA(hwndDlg, IDC_PLUS_CHECKTREE, TVM_GETITEMA, 0, (LPARAM)&item);
+ if (item.state & TVIS_BOLD && hti.flags & TVHT_ONITEMSTATEICON) {
+ item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_BOLD;
+ SendDlgItemMessageA(hwndDlg, IDC_PLUS_CHECKTREE, TVM_SETITEMA, 0, (LPARAM)&item);
+ } else if (hti.flags & TVHT_ONITEMSTATEICON) {
+
+ if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 3) {
+ item.state = INDEXTOSTATEIMAGEMASK(1);
+ SendDlgItemMessageA(hwndDlg, IDC_PLUS_CHECKTREE, TVM_SETITEMA, 0, (LPARAM)&item);
+ }
+
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ }
+ break;
+ default:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ int i = 0;
+ TVITEM item = {0};
+ DWORD msgTimeout;
+ /*
+ * scan the tree view and obtain the options...
+ */
+ TOptionListItem* lvItems = CTranslator::getTree(CTranslator::TREE_MODPLUS);
+
+ while (lvItems[i].szName != NULL) {
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ item.hItem = (HTREEITEM)lvItems[i].handle;
+ item.stateMask = TVIS_STATEIMAGEMASK;
+
+ SendDlgItemMessageA(hwndDlg, IDC_PLUS_CHECKTREE, TVM_GETITEMA, 0, (LPARAM)&item);
+ if (lvItems[i].uType == LOI_TYPE_SETTING)
+ M->WriteByte(SRMSGMOD_T, (char *)lvItems[i].lParam, (BYTE)((item.state >> 12) == 3/*2*/ ? 1 : 0)); // NOTE: state image masks changed
+ i++;
+ }
+
+ msgTimeout = 1000 * GetDlgItemInt(hwndDlg, IDC_SECONDS, NULL, FALSE);
+ PluginConfig.m_MsgTimeout = msgTimeout >= SRMSGSET_MSGTIMEOUT_MIN ? msgTimeout : SRMSGSET_MSGTIMEOUT_MIN;
+ M->WriteDword(SRMSGMOD, SRMSGSET_MSGTIMEOUT, PluginConfig.m_MsgTimeout);
+
+ M->WriteByte(SRMSGMOD_T, "historysize", (BYTE)SendDlgItemMessage(hwndDlg, IDC_HISTORYSIZESPIN, UDM_GETPOS, 0, 0));
+ PluginConfig.reloadAdv();
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND: {
+ if(LOWORD(wParam) == IDC_PLUS_HELP) {
+ CallService(MS_UTILS_OPENURL, 0, (LPARAM)"http://wiki.miranda.or.at/TabSRMM/AdvancedTweaks");
+ break;
+ }
+ else if(LOWORD(wParam) == IDC_PLUS_REVERT) { // revert to defaults...
+ int i = 0;
+
+ TOptionListItem *lvItems = CTranslator::getTree(CTranslator::TREE_MODPLUS);
+
+ while(lvItems[i].szName) {
+ if(lvItems[i].uType == LOI_TYPE_SETTING)
+ M->WriteByte(SRMSGMOD_T, (char *)lvItems[i].lParam, (BYTE)lvItems[i].id);
+ i++;
+ }
+ TreeView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_PLUS_CHECKTREE));
+ SendMessage(hwndDlg, WM_USER + 100, 0, 0); // fill dialog
+ break;
+ }
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return TRUE;
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ /*
+ * fill dialog
+ */
+ case WM_USER + 100: {
+ TVINSERTSTRUCT tvi = {0};
+ int i = 0;
+
+ TOptionListGroup *lvGroups = CTranslator::getGroupTree(CTranslator::TREE_MODPLUS);
+
+ while (lvGroups[i].szName != NULL) {
+ tvi.hParent = 0;
+ tvi.hInsertAfter = TVI_LAST;
+ tvi.item.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.item.pszText = lvGroups[i].szName;
+ tvi.item.stateMask = TVIS_STATEIMAGEMASK | TVIS_EXPANDED | TVIS_BOLD;
+ tvi.item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_EXPANDED | TVIS_BOLD;
+ lvGroups[i++].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_PLUS_CHECKTREE), &tvi);
+ }
+
+ i = 0;
+
+ TOptionListItem *lvItems = CTranslator::getTree(CTranslator::TREE_MODPLUS);
+
+ while (lvItems[i].szName != 0) {
+ tvi.hParent = (HTREEITEM)lvGroups[lvItems[i].uGroup].handle;
+ tvi.hInsertAfter = TVI_LAST;
+ tvi.item.pszText = lvItems[i].szName;
+ tvi.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvi.item.lParam = i;
+ tvi.item.stateMask = TVIS_STATEIMAGEMASK;
+ //if (lvItems[i].uType == LOI_TYPE_FLAG)
+ // tvi.item.state = INDEXTOSTATEIMAGEMASK((dwFlags & (UINT)lvItems[i].lParam) ? 3 : 2);
+ if (lvItems[i].uType == LOI_TYPE_SETTING)
+ tvi.item.state = INDEXTOSTATEIMAGEMASK(M->GetByte((char *)lvItems[i].lParam, lvItems[i].id) ? 3 : 2); // NOTE: was 2 : 1 without state image mask
+ lvItems[i].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_PLUS_CHECKTREE), &tvi);
+ i++;
+ }
+ PluginConfig.g_bClientInStatusBar = M->GetByte("adv_ClientIconInStatusBar", 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_TIMEOUTSPIN, UDM_SETRANGE, 0, MAKELONG(300, SRMSGSET_MSGTIMEOUT_MIN / 1000));
+ SendDlgItemMessage(hwndDlg, IDC_TIMEOUTSPIN, UDM_SETPOS, 0, PluginConfig.m_MsgTimeout / 1000);
+
+ SendDlgItemMessage(hwndDlg, IDC_HISTORYSIZESPIN, UDM_SETRANGE, 0, MAKELONG(255, 15));
+ SendDlgItemMessage(hwndDlg, IDC_HISTORYSIZESPIN, UDM_SETPOS, 0, (int)M->GetByte("historysize", 0));
+
+ return 0;
+ }
+ case WM_CLOSE:
+ EndDialog(hwndDlg,0);
+ return 0;
+ }
+ return 0;
+}
diff --git a/plugins/TabSRMM/tabsrmm_10.vcxproj b/plugins/TabSRMM/tabsrmm_10.vcxproj
new file mode 100644
index 0000000000..ab91489a7c
--- /dev/null
+++ b/plugins/TabSRMM/tabsrmm_10.vcxproj
@@ -0,0 +1,627 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>TabSRMM</ProjectName>
+ <ProjectGuid>{99D26CA1-BFD4-4E77-9A1E-919E54CF33F7}</ProjectGuid>
+ <RootNamespace>srmm</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <UseOfAtl>false</UseOfAtl>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <UseOfAtl>false</UseOfAtl>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)/Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)/Obj/$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</IgnoreImportLibrary>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64/Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</IgnoreImportLibrary>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)/Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)/Obj/$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64/Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkIncremental>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Release/srmm.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <OmitFramePointers>false</OmitFramePointers>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <AdditionalIncludeDirectories>../../include;../include;../ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <FloatingPointModel>Strict</FloatingPointModel>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <AssemblerListingLocation>
+ </AssemblerListingLocation>
+ <BrowseInformation>
+ </BrowseInformation>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0809</Culture>
+ <AdditionalIncludeDirectories>./../../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalManifestDependencies>type=%27Win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27X86%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(TargetDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapFileName>
+ </MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+ <BaseAddress>0x6a540000</BaseAddress>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>.\Release/srmm.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <OmitFramePointers>true</OmitFramePointers>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <AdditionalIncludeDirectories>../../include;../include;../ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WIN64;_AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
+ <FloatingPointModel>Strict</FloatingPointModel>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <AssemblerListingLocation>
+ </AssemblerListingLocation>
+ <BrowseInformation>
+ </BrowseInformation>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_WIN64;_AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0809</Culture>
+ <AdditionalIncludeDirectories>./../../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalManifestDependencies>type=%27Win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(TargetDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>
+ </MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+ <BaseAddress>
+ </BaseAddress>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Debug/srmm.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../../include;../include;../ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>false</StringPooling>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <FloatingPointModel>Precise</FloatingPointModel>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <AssemblerListingLocation>
+ </AssemblerListingLocation>
+ <BrowseInformation>
+ </BrowseInformation>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0809</Culture>
+ <AdditionalIncludeDirectories>./../../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(TargetDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapFileName>
+ </MapFileName>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>.\Debug/srmm.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../../include;../include;../ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WIN64;_AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>false</StringPooling>
+ <ExceptionHandling>Async</ExceptionHandling>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
+ <FloatingPointModel>Precise</FloatingPointModel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <AssemblerListingLocation>
+ </AssemblerListingLocation>
+ <BrowseInformation>
+ </BrowseInformation>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_WIN64;_AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0809</Culture>
+ <AdditionalIncludeDirectories>./../../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(TargetDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapFileName>
+ </MapFileName>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="src\buttonsbar.cpp" />
+ <ClCompile Include="src\contactcache.cpp" />
+ <ClCompile Include="src\container.cpp" />
+ <ClCompile Include="src\containeroptions.cpp" />
+ <ClCompile Include="src\controls.cpp" />
+ <ClCompile Include="src\eventpopups.cpp">
+ <ExceptionHandling Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Sync</ExceptionHandling>
+ </ClCompile>
+ <ClCompile Include="src\generic_msghandlers.cpp" />
+ <ClCompile Include="src\globals.cpp" />
+ <ClCompile Include="src\hotkeyhandler.cpp" />
+ <ClCompile Include="src\ImageDataObject.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ </PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ </PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\infopanel.cpp" />
+ <ClCompile Include="src\mim.cpp" />
+ <ClCompile Include="src\sendlater.cpp" />
+ <ClCompile Include="tabmodplus\modplus.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\msgdialog.cpp" />
+ <ClCompile Include="src\msgdlgutils.cpp" />
+ <ClCompile Include="src\msglog.cpp" />
+ <ClCompile Include="src\msgoptions.cpp" />
+ <ClCompile Include="tabmodplus\msgoptions_plus.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\msgs.cpp" />
+ <ClCompile Include="src\selectcontainer.cpp" />
+ <ClCompile Include="src\sendqueue.cpp" />
+ <ClCompile Include="src\sidebar.cpp" />
+ <ClCompile Include="src\srmm.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\tabctrl.cpp" />
+ <ClCompile Include="src\taskbar.cpp" />
+ <ClCompile Include="src\templates.cpp" />
+ <ClCompile Include="src\themeio.cpp" />
+ <ClCompile Include="src\themes.cpp" />
+ <ClCompile Include="src\translator.cpp" />
+ <ClCompile Include="src\trayicon.cpp" />
+ <ClCompile Include="src\TSButton.cpp" />
+ <ClCompile Include="src\typingnotify.cpp" />
+ <ClCompile Include="src\userprefs.cpp" />
+ <ClCompile Include="src\utils.cpp" />
+ <ClCompile Include="chat\clist.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="chat\colorchooser.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="chat\log.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="chat\main.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="chat\manager.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="chat\message.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="chat\muchighlight.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ </PrecompiledHeader>
+ <FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Speed</FavorSizeOrSpeed>
+ <ExceptionHandling Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Sync</ExceptionHandling>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </PrecompiledHeader>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Speed</FavorSizeOrSpeed>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ </PrecompiledHeader>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="chat\options.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="chat\services.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="chat\tools.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="chat\window.cpp">
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../src/commonheaders.h</PrecompiledHeaderFile>
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../src/commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="chat\chat.h" />
+ <ClInclude Include="chat\chat_resource.h" />
+ <ClInclude Include="chat\chatprototypes.h" />
+ <ClInclude Include="chat\muchighlight.h" />
+ <ClInclude Include="include\resource.h" />
+ <ClInclude Include="include\sendlater.h" />
+ <ClInclude Include="src\commonheaders.h" />
+ <ClInclude Include="include\contactcache.h" />
+ <ClInclude Include="include\controls.h" />
+ <ClInclude Include="include\functions.h" />
+ <ClInclude Include="include\generic_msghandlers.h" />
+ <ClInclude Include="include\globals.h" />
+ <ClInclude Include="include\ImageDataObject.h" />
+ <ClInclude Include="include\infopanel.h" />
+ <ClInclude Include="include\mim.h" />
+ <ClInclude Include="include\msgdlgutils.h" />
+ <ClInclude Include="include\msgs.h" />
+ <ClInclude Include="include\nen.h" />
+ <ClInclude Include="include\sendqueue.h" />
+ <ClInclude Include="include\sidebar.h" />
+ <ClInclude Include="include\taskbar.h" />
+ <ClInclude Include="include\templates.h" />
+ <ClInclude Include="include\themes.h" />
+ <ClInclude Include="include\translator.h" />
+ <ClInclude Include="include\typingnotify.h" />
+ <ClInclude Include="include\utils.h" />
+ <ClInclude Include="include\version.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="chat\chat.rc" />
+ <ResourceCompile Include="msgwindow.rc" />
+ <ResourceCompile Include="resource.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\src\res\cursor_drag_copy.CUR" />
+ <None Include="BuildScripts\VS_2010_Toolset9.bat" />
+ <None Include="chat\Icons\1.ico" />
+ <None Include="chat\Icons\2.ico" />
+ <None Include="chat\Icons\3.ico" />
+ <None Include="chat\Icons\4.ico" />
+ <None Include="chat\Icons\5.ico" />
+ <None Include="chat\Icons\6.ico" />
+ <None Include="chat\Icons\action.ico" />
+ <None Include="res\angeli-icons\Add.ico" />
+ <None Include="..\..\Miranda-IM\res\addcontact.ico" />
+ <None Include="chat\Icons\addmode.ico" />
+ <None Include="res\angeli-icons\AddXP.ico" />
+ <None Include="res\arrow-down.ico" />
+ <None Include="chat\Icons\bkgcolor.ico" />
+ <None Include="chat\Icons\blank.ico" />
+ <None Include="res\blocked.ico" />
+ <None Include="chat\Icons\bold.ico" />
+ <None Include="res\check.ico" />
+ <None Include="res\checked.ico" />
+ <None Include="res\Clock8.ico" />
+ <None Include="chat\Icons\close.ico" />
+ <None Include="res\angeli-icons\Close.ico" />
+ <None Include="chat\Icons\color.ico" />
+ <None Include="..\..\src\res\cursor_drop_user.cur" />
+ <None Include="..\..\src\res\cursor_hyperlink.cur" />
+ <None Include="res\delete.ico" />
+ <None Include="res\Details32.ico" />
+ <None Include="res\Details8.ico" />
+ <None Include="..\..\Miranda-IM\res\dragcopy.cur" />
+ <None Include="..\..\src\res\dragcopy.cur" />
+ <None Include="..\..\src\res\dropuser.cur" />
+ <None Include="..\..\Miranda-IM\res\dropuser.cur" />
+ <None Include="res\error.ico" />
+ <None Include="res\expand.ico" />
+ <None Include="chat\Icons\filter.ico" />
+ <None Include="chat\Icons\filter2.ico" />
+ <None Include="chat\Icons\highlight.ico" />
+ <None Include="..\..\Miranda-IM\res\history.ico" />
+ <None Include="res\angeli-icons\History.ico" />
+ <None Include="res\History32.ico" />
+ <None Include="res\History8.ico" />
+ <None Include="res\angeli-icons\HistoryXP.ico" />
+ <None Include="..\..\Miranda-IM\res\hyperlin.cur" />
+ <None Include="..\..\src\res\hyperlin.cur" />
+ <None Include="..\..\src\res\icon1.ico" />
+ <None Include="res\icon1.ico" />
+ <None Include="res\overlay_disabled.ico" />
+ <None Include="res\overlay_enabled.ico" />
+ <None Include="res\SKIN\tabskin_aero.png" />
+ <None Include="res\SKIN\tabskin_aero_button.png" />
+ <None Include="res\SKIN\tabskin_aero_glow.png" />
+ <None Include="res\SKIN\unknown.png" />
+ <None Include="tabmodplus\icons\imgclose.ico" />
+ <None Include="tabmodplus\icons\imgopen.ico" />
+ <None Include="res\in.ico" />
+ <None Include="res\angeli-icons\Incom.ico" />
+ <None Include="res\angeli-icons\Info.ico" />
+ <None Include="chat\Icons\info.ico" />
+ <None Include="chat\Icons\italics.ico" />
+ <None Include="chat\Icons\join.ico" />
+ <None Include="chat\Icons\kick.ico" />
+ <None Include="res\leftarrow.ico" />
+ <None Include="res\LOGO.bmp" />
+ <None Include="chat\Icons\message.ico" />
+ <None Include="chat\Icons\messageout.ico" />
+ <None Include="res\angeli-icons\Multi.ico" />
+ <None Include="..\..\Miranda-IM\res\multisend.ico" />
+ <None Include="res\Multisend32.ico" />
+ <None Include="res\Multisend8.ico" />
+ <None Include="res\angeli-icons\MultiXP.ico" />
+ <None Include="chat\Icons\nick.ico" />
+ <None Include="chat\Icons\nicklist.ico" />
+ <None Include="chat\Icons\nicklist2.ico" />
+ <None Include="chat\Icons\notice.ico" />
+ <None Include="res\angeli-icons\Opt.ico" />
+ <None Include="res\options.ico" />
+ <None Include="res\angeli-icons\OptXP.ico" />
+ <None Include="res\out.ico" />
+ <None Include="res\angeli-icons\Outg.ico" />
+ <None Include="chat\Icons\overlay.ico" />
+ <None Include="chat\Icons\part.ico" />
+ <None Include="res\angeli-icons\Pencil.ico" />
+ <None Include="res\Photo32.ico" />
+ <None Include="res\Photo8.ico" />
+ <None Include="res\angeli-icons\Pic.ico" />
+ <None Include="res\angeli-icons\PicXP.ico" />
+ <None Include="res\res_TN\popup.ico" />
+ <None Include="res\res_TN\popup_no.ico" />
+ <None Include="res\pulldown.ico" />
+ <None Include="res\pulldown1.ico" />
+ <None Include="res\pullup.ico" />
+ <None Include="chat\Icons\quit.ico" />
+ <None Include="res\quote.ico" />
+ <None Include="res\angeli-icons\Quote02.ico" />
+ <None Include="chat\Icons\removestatus.ico" />
+ <None Include="..\..\Miranda-IM\res\rename.ico" />
+ <None Include="res\rightarrow.ico" />
+ <None Include="res\angeli-icons\Save.ico" />
+ <None Include="res\save.ico" />
+ <None Include="res\angeli-icons\SaveXP.ico" />
+ <None Include="res\angeli-icons\Send.ico" />
+ <None Include="res\smbutton.ico" />
+ <None Include="chat\Icons\smiley.ico" />
+ <None Include="res\smiley_xp.ico" />
+ <None Include="res\status.ico" />
+ <None Include="chat\Icons\topic.ico" />
+ <None Include="chat\Icons\topicbut.ico" />
+ <None Include="res\Typing32.ico" />
+ <None Include="res\Typing8.ico" />
+ <None Include="res\unchecked.ico" />
+ <None Include="chat\Icons\underline.ico" />
+ <None Include="..\..\Miranda-IM\res\viewdetails.ico" />
+ <None Include="res\visible.ico" />
+ <None Include="chat\Icons\window.ico" />
+ <None Include="docs\changelog.txt" />
+ <None Include="docs\INSTALL" />
+ <None Include="langpacks\langpack_tabsrmm_german.txt" />
+ <None Include="Makefile.ansi" />
+ <None Include="docs\Popups.txt" />
+ <None Include="docs\Readme.icons" />
+ <None Include="docs\readme.txt" />
+ <None Include="skin\tabsrmm.tsk" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+ <ProjectExtensions>
+ <VisualStudio>
+ <UserProperties RESOURCE_FILE="resource.rc" />
+ </VisualStudio>
+ </ProjectExtensions>
+</Project> \ No newline at end of file
diff --git a/plugins/TabSRMM/tabsrmm_10.vcxproj.filters b/plugins/TabSRMM/tabsrmm_10.vcxproj.filters
new file mode 100644
index 0000000000..fb6d6a249d
--- /dev/null
+++ b/plugins/TabSRMM/tabsrmm_10.vcxproj.filters
@@ -0,0 +1,632 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{8f99453b-6906-4b5a-9eba-90fd1dd46947}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Source Files\Chat">
+ <UniqueIdentifier>{fd86b5ef-2dfa-441f-89d5-cc5eba70e3d0}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{383e316e-aa7a-4097-af16-2acd438c8fa6}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{c6aa9273-8563-4007-afa1-63e8d2164122}</UniqueIdentifier>
+ <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
+ </Filter>
+ <Filter Include="BuildScripts">
+ <UniqueIdentifier>{196b0a74-3839-43b9-a9e8-8220bd015468}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Docs">
+ <UniqueIdentifier>{34490cba-faaa-4738-91b7-f3f60bc24992}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files\Icons">
+ <UniqueIdentifier>{7dbf611a-769b-4495-9d7a-b7008268c0dc}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="src\buttonsbar.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\contactcache.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\container.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\containeroptions.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\controls.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\eventpopups.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\generic_msghandlers.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\globals.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\hotkeyhandler.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\ImageDataObject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\infopanel.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\mim.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="tabmodplus\modplus.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\msgdialog.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\msgdlgutils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\msglog.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\msgoptions.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="tabmodplus\msgoptions_plus.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\msgs.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\selectcontainer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\sendqueue.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\sidebar.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\srmm.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\tabctrl.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\taskbar.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\templates.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\themeio.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\themes.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\translator.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\trayicon.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\TSButton.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\typingnotify.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\userprefs.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="chat\clist.cpp">
+ <Filter>Source Files\Chat</Filter>
+ </ClCompile>
+ <ClCompile Include="chat\colorchooser.cpp">
+ <Filter>Source Files\Chat</Filter>
+ </ClCompile>
+ <ClCompile Include="chat\log.cpp">
+ <Filter>Source Files\Chat</Filter>
+ </ClCompile>
+ <ClCompile Include="chat\main.cpp">
+ <Filter>Source Files\Chat</Filter>
+ </ClCompile>
+ <ClCompile Include="chat\manager.cpp">
+ <Filter>Source Files\Chat</Filter>
+ </ClCompile>
+ <ClCompile Include="chat\message.cpp">
+ <Filter>Source Files\Chat</Filter>
+ </ClCompile>
+ <ClCompile Include="chat\muchighlight.cpp">
+ <Filter>Source Files\Chat</Filter>
+ </ClCompile>
+ <ClCompile Include="chat\options.cpp">
+ <Filter>Source Files\Chat</Filter>
+ </ClCompile>
+ <ClCompile Include="chat\services.cpp">
+ <Filter>Source Files\Chat</Filter>
+ </ClCompile>
+ <ClCompile Include="chat\tools.cpp">
+ <Filter>Source Files\Chat</Filter>
+ </ClCompile>
+ <ClCompile Include="chat\window.cpp">
+ <Filter>Source Files\Chat</Filter>
+ </ClCompile>
+ <ClCompile Include="src\sendlater.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="chat\chat.h">
+ <Filter>Source Files\Chat</Filter>
+ </ClInclude>
+ <ClInclude Include="chat\chat_resource.h">
+ <Filter>Source Files\Chat</Filter>
+ </ClInclude>
+ <ClInclude Include="chat\chatprototypes.h">
+ <Filter>Source Files\Chat</Filter>
+ </ClInclude>
+ <ClInclude Include="chat\muchighlight.h">
+ <Filter>Source Files\Chat</Filter>
+ </ClInclude>
+ <ClInclude Include="src\commonheaders.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\contactcache.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\controls.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\functions.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\generic_msghandlers.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\globals.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\ImageDataObject.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\infopanel.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\mim.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\msgdlgutils.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\msgs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\nen.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\sendqueue.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\sidebar.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\taskbar.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\templates.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\themes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\translator.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\typingnotify.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\utils.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\sendlater.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="chat\chat.rc">
+ <Filter>Source Files\Chat</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="msgwindow.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="resource.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\src\res\cursor_drop_user.cur">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="..\..\src\res\cursor_hyperlink.cur">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="..\..\Miranda-IM\res\dragcopy.cur">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="..\..\src\res\dragcopy.cur">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="..\..\src\res\dropuser.cur">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="..\..\Miranda-IM\res\dropuser.cur">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="..\..\Miranda-IM\res\hyperlin.cur">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="..\..\src\res\hyperlin.cur">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\LOGO.bmp">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="docs\changelog.txt">
+ <Filter>Docs</Filter>
+ </None>
+ <None Include="docs\INSTALL">
+ <Filter>Docs</Filter>
+ </None>
+ <None Include="langpacks\langpack_tabsrmm_german.txt">
+ <Filter>Docs</Filter>
+ </None>
+ <None Include="Makefile.ansi">
+ <Filter>Docs</Filter>
+ </None>
+ <None Include="docs\Popups.txt">
+ <Filter>Docs</Filter>
+ </None>
+ <None Include="docs\Readme.icons">
+ <Filter>Docs</Filter>
+ </None>
+ <None Include="docs\readme.txt">
+ <Filter>Docs</Filter>
+ </None>
+ <None Include="skin\tabsrmm.tsk">
+ <Filter>Docs</Filter>
+ </None>
+ <None Include="BuildScripts\VS_2010_Toolset9.bat">
+ <Filter>BuildScripts</Filter>
+ </None>
+ <None Include="..\..\src\res\cursor_drag_copy.CUR">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\SKIN\tabskin_aero.png">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\SKIN\tabskin_aero_button.png">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\SKIN\tabskin_aero_glow.png">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="chat\Icons\1.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\6.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\2.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\3.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\4.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\5.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\action.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\color.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Add.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="..\..\Miranda-IM\res\addcontact.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\addmode.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\AddXP.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\arrow-down.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\bkgcolor.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\blank.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\blocked.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\bold.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\check.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\checked.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\Clock8.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Close.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\close.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\delete.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\Details32.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\Details8.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\error.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\HistoryXP.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\expand.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\filter.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\filter2.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\highlight.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="..\..\Miranda-IM\res\history.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\History.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\History32.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\History8.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="..\..\src\res\icon1.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\leftarrow.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\icon1.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="tabmodplus\icons\imgclose.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="tabmodplus\icons\imgopen.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\in.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Incom.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\info.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Info.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\italics.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\join.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\kick.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\message.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\messageout.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Multi.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="..\..\Miranda-IM\res\multisend.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\Multisend32.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\Multisend8.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\MultiXP.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\nick.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\nicklist.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\nicklist2.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\notice.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Opt.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\options.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\res_TN\popup.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\OptXP.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\out.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Outg.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\overlay.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\overlay_disabled.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\overlay_enabled.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\part.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Pencil.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\Photo32.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\Photo8.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Pic.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\PicXP.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\res_TN\popup_no.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\pulldown.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\pulldown1.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\pullup.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\quit.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\quote.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Quote02.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\removestatus.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="..\..\Miranda-IM\res\rename.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\status.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\smiley_xp.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\smiley.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\smbutton.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Send.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\SaveXP.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\save.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\angeli-icons\Save.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\rightarrow.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\topic.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\topicbut.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\Typing32.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\Typing8.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\unchecked.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\underline.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="..\..\Miranda-IM\res\viewdetails.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\visible.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="chat\Icons\window.ico">
+ <Filter>Resource Files\Icons</Filter>
+ </None>
+ <None Include="res\SKIN\unknown.png" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/plugins/TabSRMM/tabsrmm_private.rc b/plugins/TabSRMM/tabsrmm_private.rc
new file mode 100644
index 0000000000..01a0741e03
--- /dev/null
+++ b/plugins/TabSRMM/tabsrmm_private.rc
@@ -0,0 +1,18 @@
+#define UDS_HOTTRACK 0x0100
+#define TCS_HOTTRACK 0x0040
+#define TVS_FULLROWSELECT 0x1000
+#define TVS_DISABLEDRAGDROP 0x0010
+#define TVS_SHOWSELALWAYS 0x0020
+#define TVS_NOTOOLTIPS 0x0080
+#define TVS_TRACKSELECT 0x0200
+#define TVS_FULLROWSELECT 0x1000
+
+#ifdef __GNUWIN32__
+ #define TVS_NONEVENHEIGHT 16384
+ #define TVS_CHECKBOXES 256
+ #define IDC_STATIC -1
+#endif
+
+#include "msgwindow.rc"
+#include "resource.rc"
+#include "chat/chat.rc"