The ModuleHook Interface
The ModuleHook Interface is really nothing more than a !bangcommand with a special
syntax. And it is relatively easy to add to existing code, depending on how many of
its features you want to use.
!CallMeWhatYouWant <Userdata[0..N]> <future options> <Path\to\BoxFile.box> <current Box HWND>
I suggest that you use <Modulename>LsBoxHook as BangCommand name, but that's up to you.
Everything but the userdata string is generated by lsbox.
The <Userdata> strings are optional - they are only needed if you want to pass additional
options from the *ModuleHook line in the box file. Label needs this to decide what Label should
be loaded/docked to the Box.
The <Path\to\BoxFile.box> string contains the full expanded path to the .box file. You
can use this together with LiteStep's LoadRC LSAPI to load options from the box file.
RabidVWM is currently the only Module to do this.
The <current Box HWND> argument is the Box's HWND converted to string
It is important that you evaluate the options that are created by LsBox END of the
string!!!!
I have <future options> planned that will break your module's ModuleHook support if
you evaluate from the front!
Don't evaluate the Userdata string from the end for the same reason.
Sample Code
Tasks
This is the code i used for hooking Tasks. Since Tasks already had a DockToWindow
option patching it for LsBox was easy - I just had to look at TasksDockToWindow and
add my own bang for the Hook interface.
void TasksBoxHook(HWND caller, LPCTSTR szArgs)
{
UNREFERENCED_PARAMETER(caller);
char *handle = strrchr(szArgs,' ');
if (handle)
{
HWND hWnd = (HWND)atoi(handle+1);
if (hWnd)
{
if (hWnd != ts.DockWindow){
for (int i=0;i<numTasks;i++){
SetWindowLong(tasks[i].hwnd, GWL_STYLE, (GetWindowLong(tasks[i].hwnd, GWL_STYLE) &~ WS_POPUP)|WS_CHILD);
SetParent(tasks[i].hwnd, hWnd);
//This is a Bad idea under Win2k SP2 - don't ask me why.....
//SetWindowLong(tasks[i].hwnd, GWL_STYLE, (GetWindowLong(tasks[i].hwnd, GWL_STYLE) &~ WS_CHILD)|WS_POPUP);
}
ts.DockWindow = hWnd;
}
}
}
return;
}
Well and that's really everything that is needed here - the way Tasks is build so that
it doesn't have to handle the WM_DESTROY case.....
LsXcommand
The Bang really isn't any different from the Task HookBang - it just handles a second
hidden state so the LsXcommand window only shows up when it is docked to a Box.
void BangBoxHook(HWND caller, const char *args)
{
char *handle = strrchr(args,' ');
if (handle)
{
HWND boxwnd = (HWND)atoi(handle+1);
if (boxwnd)
{
lsboxed = TRUE;
if (boxwnd != GetParent(hWnd))
{
SetWindowLong(hWnd, GWL_STYLE, (GetWindowLong(hWnd, GWL_STYLE) &~ WS_POPUP)|WS_CHILD);
SetParent(hWnd, boxwnd);
//This is a Bad idea under Win2k SP2 - don't ask me why.....
// SetWindowLong(hWnd, GWL_STYLE, (GetWindowLong(hWnd, GWL_STYLE) &~ WS_CHILD)|WS_POPUP);
if (cs->WaitForBox && visible)
{
ShowWindow(hWnd, SW_SHOWNORMAL);
cs->WaitForBox = FALSE;
}
}
}
}
return;
}
Since LsBox will send a WM_DESTROY message to it's Child Windows once a box
is destroyed we have to handle the WM_DESTROY Message so LsXcommmand isn't
actually destroyed.
case WM_DESTROY:
if (lsboxed)
{
cs->WaitForBox = TRUE;
visible = TRUE;
SetWindowLong(hWnd, GWL_STYLE, (GetWindowLong(hWnd, GWL_STYLE) &~ WS_CHILD)|WS_POPUP);
SetParent(hWnd, 0);
SetWindowPos(hWnd,HWND_TOP,cs->x,cs->y,0,0,SWP_NOSIZE|SWP_HIDEWINDOW);
lsboxed = FALSE;
return 0;
}
Label
Label was the most difficult of the three Modules to patch since it actually
used more than one window. AND it is written useing OOP. But aside from that
the only difference between the Label and the LsXcommand code is that it actually
uses an Userdata string to select the right Label
void LsBoxHookBangCommand(HWND caller, const char *arguments)
{
char labelName[MAX_LINE_LENGTH];
LPCTSTR nextToken[MAX_LINE_LENGTH];
GetToken(arguments,labelName,nextToken,false);
//check if the label is already running
Label *label = lookupLabel(labelName);
if (label == 0)
{
label = new Label(labelName);
label->load(hInstance);
labelList.insert(labelList.end(), label);
}
char *handle = strrchr(arguments,' ');
if ((label != 0)&&(handle))
{
HWND boxWnd = (HWND)atoi(handle+1);
if (boxWnd)
{
label->setBox(boxWnd);
label->show();
label->update();
}
}
}
The WM_DESTROY case has to be handld, too.
case WM_DESTROY:
{
if(box)
{
//hide or destroy is the Question - i take hide - blkhawk
this->hide();
this->setBox(0);
//Uncomment these to destroy the Label when the parent box gets killed
/*hWnd = 0;
labelList.remove(this);
delete this;*/
}
return false;
}
Why?
Well, frankly neither the *Module nor the *WharfModule Mode of LsBox really
do everything THEY NEED to do. *WharfMode is good for all old Modules THAT
haven't been updated in *years* or for new modules that only run in one
instance at a time. *ModuleMode was added by me to allow modules to have
more than one window on a given box.
(i did this to allow LsSlider to be loaded into a box)
One limitation of *WharfMode remains; since the Modules are loaded by lsbox
and the init and quit functions are modeled after the way *WharfMode works
multiple windows over several boxes from one module are impossible to do.
(at least not without causeing crashes)
Along came a Module that People *wanted* to be loadable into multiple boxes
(Label). I had patched the Label to be loadeable into a single box, but that
wasn't enough so Maduin added a simple interface that identified a box a label
should be docked to by it's class and it's windowtitle. And it worked
well enough at least until I switched to WinXP and noticed how good
Alphatransparency can look. To allow boxes to be made transparent i had to
unparent them from the Desktop window that caused them to show up in the
Windows Taskmanager. I fixed this by changing the windowtitle to null.
I think you can see what that caused with Label... since i neither wanted to give
up on Alphatrans nor wanted the boxes show up in TaskMan all the time i added some
options that set the Window title again. i also tried to get both the label
compability and the TaskHideing by adding a timed "TasksFlash" function.
But i wasn't satisfied by the solution because i felt that LsBox had become somewhat
bloated and unstable because of it's bloatness. I thought about rewriting some
functions to streamline the code a bit.
The long planned LsSlider rewrite was around the corner too and i wanted to add
Label-style freedocking of Sliders to boxes, but i didn't quite wanted to do it
exactly like Maduin did......
And that's why i did the !ModuleHook mode