Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Dark GDK / Minimise to taskbar icon

Author
Message
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 6th Jun 2008 17:24
I would like to minimize my game to the taskbar, and show an icon near the clock.

I know that I need to use dbHideWindow() and dbShowWindow() but apart from that I am lost.

I cannot seem to find any specific GDK related commands, so I think that I am stuck with Windows api calls.

Anyone can dorect me to some usable examples?

thanks
unitech
17
Years of Service
User Offline
Joined: 27th Jun 2007
Location:
Posted: 6th Jun 2008 17:52
I'm 100% sure you have to use WIN32 calls.. like so.

http://www.gidforums.com/t-9218.html

There is no GDK call to do this.
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 7th Jun 2008 08:55
It seems that I need to use Shell_NotifyIcon() which sounds pretty straightforward. However I need to fill the NOTIFYICONDATA structure, which amongst others needs a handle to the main GDK window.

Is the main Window set up by GDK simply called DARKGDK ?
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 7th Jun 2008 09:41 Edited at: 7th Jun 2008 09:58
I'm not sure if globstruct.h is included by default, but you can get the handle of the window from Windows, too. Here is how you can use globstruct, however...which has a lot of useful members:

#include <globstruct.h>

(I think it is in your include path.)

GlobStruct* ptrGlobStruct = NULL;
.
.
.
ptrGlobStruct = (GlobStruct*)dbGetGlobPtr();

Then, the window's handle is:
ptrGlobStruct->hWnd
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 7th Jun 2008 12:09
thanks a lot unitech & jinzai.

got it working however I still need to fix 2 small issues.

tnd.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_MYICON));

Cannot get this to work properly as I need to get an Instance instead of NULL. How can I do that?

IDI_MYICON is an icon in my resources.
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 7th Jun 2008 12:29
Same place you got the hWnd....
ptrGlobStruct->hInstance

...I was going to mention that when I stated that globstruct had alot of useful members. Sorry.
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 7th Jun 2008 12:44
thanks Jinzai. Works incredibly 100% now. I have learned a lot from this little project thanks to everyone's help.

just one last stumbling block...

i have set up 2 functions:




Now I need to wait for the user to click left/right mousebutton on my taskbar icon to reactivate it again.

I think my next step would be to do a loop at the very end of addtaskbaricon() to wait for a msg.

The code example suggested by unitech goes something like this:

Quote: " UINT uID; // The icon ID sending the message
 UINT uMouseMsg; //Mouse event
 POINT pt;
 uID=(UINT) wParam;
 uMouseMsg=(UINT) lParam;
 if(uMouseMsg==WM_RBUTTONDOWN)
 {
  switch(uID)
  {
  case IDR_MAINFRAME: // Only handle the message sent by our app's tray icon
   GetCursorPos(&pt);// Get mouse's current position
   // AfxGetApp( )-> m_pMainWnd->ShowWindow(SW_SHOWNORMAL);
// ...
   break;
   default:
  }
 }
 return;"


however i could not get it to work VC++ does not like the UINTs at the start.

what would be the simplest way to get the mouseclick msg?
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 7th Jun 2008 13:22 Edited at: 7th Jun 2008 13:26
That looks an awful lot like MFC code (because it is!), and you are not making an MFC app, unless I am very mistaken.

Anyway, I'd recommend that you begin by making the GlobStruct* global, and initializing it once. (Not a big deal, but it will shave some time off of your routines.)

Next, you can get mouse click information, and mouse position information from GDK, too. (Otherwise, you will want to hook the GDK's WndProc, by substituting your own that acts on some messages, but passes the rest back to GDK. That is a little complex, but...certainly doable.)

integer = dbMouseClick()
1 = left
2 = right
4 = button 3
8 = button 4

They are or'ed, so LEFT+RIGHT click would equal 3.

Position is dbMouseX() and dbMouseY(). There is a dbMouseZ() as well, but it is ordinarily the wheel and will take on a value of 0 to 100.

It is not in keeping with the event-driven programming model to remain in loops like you are suggesting. I don't mean to dis your theory, but it is best to let the thing run flat out, and use variable states to drive logic like you are implementing. (IMHO, and my experience, that is.)

If you study WndProcs, you will see that they don't ever loop in that fashion. The main thing that you want to keep in mind is that your display will not get redrawn when you are hogging the resources in a loop, unless you take rather drastic measures, which starts making the program lurch, and act weird. In general, it does not pay to fight Windows...its best to write your code to fit the model that most Windows apps follow, which is event driven as opposed to procedural.

If that makes no sense, I apologize. It is the nature of Windows programming, and not necessarily the most straight-forward.

What is it specifically that MSVC is complaining about with respect to the UINTs? (That's weird because UINTs are all over in Windows.)
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 7th Jun 2008 13:28
i thought of using dbMouseX() and dbMouseY() but it's nearly impossible to know the position of your icon on the user's taskbar as there are many variables, like screen resolution, other icons in the taskbar, etc...
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 7th Jun 2008 13:43
Yes, that's true. The GDK functions return positions relative to the GDK's window, so you are correct to use GetCursorPos in that case.

So, you are wanting to drop your app into the system tray, and have it act as other apps do when they occupy that slot?

If so, then you are probably going to want to hook the GDK's WndProc, like I mentioned above. Its a little involved, but start out by looking at the functions GetWindowLong and SetWindowLong, and also study WndProc.
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 7th Jun 2008 13:49
If you look at the help for SetWindowLong, there is a sample called Subclassing a window, which is what you are doing.
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 7th Jun 2008 13:59
this code should do all the necessary stuff i need, to wait for a mouse msg, but unfortunately i cannot get it to work in vc++ iget error messages on UINT uID etc


UINT uID; // The icon ID sending the message
 UINT uMouseMsg; //Mouse event
 POINT pt;
 uID=(UINT) wParam;
 uMouseMsg=(UINT) lParam;
 if(uMouseMsg==WM_RBUTTONDOWN)
 {
  switch(uID)
  {
  case IDR_MAINFRAME: // Only handle the message sent by our app's tray icon
   GetCursorPos(&pt);// Get mouse's current position
   // AfxGetApp( )-> m_pMainWnd->ShowWindow(SW_SHOWNORMAL);
// ...
   break;
   default:
  }
 }
 return;
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 7th Jun 2008 14:07
What error message?
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 7th Jun 2008 14:17
I get like 20 errors, to start off "Undeclared Identifier "on these 2 lines :

uID=(UINT) wParam;
uMouseMsg=(UINT) lParam;
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 7th Jun 2008 14:24 Edited at: 7th Jun 2008 14:30
Well, wParam and lParam are only passed to a wndproc, or you can call PeekMessage to get a message from the GDK's queue, but...you don't have any other access to messages. Its not the UINT that is the issue, its wParam and lParam.

Check out PeekMessage. You will need a MSG structure to pass into PeekMessage, and it will contain wParam and lParam as members, like this:

MSG mymsg;
.
.
.
if (PeekMessage(&mymsg, ptrGlobStruct->hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE) != 0)


wParam is mymsg.wParam
lParam is mymsg.lParam

You do not need to cast them, or use extra variables, you can use them straight out of the MSG structure, like I just did...

e.g.
switch (mymsg.message)

IDR_MAINFRAME is probably not going to be a valid ID, however...use the resource ID of your icon instead.

EDIT: Also, the cursor position is in the MSG structure, no need to get it yourself.
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 7th Jun 2008 15:29
I translated all the code, and looks pretty simple & straightforward now, but it's not working

if (mymsg.lParam==WM_LBUTTONDOWN) is not triggering at all


jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 7th Jun 2008 15:49 Edited at: 7th Jun 2008 15:51
It is not triggering because the message is not in lParam, its in LOWORD(mymsg.message)

Check the help for WM_LBUTTONDOWN to see what the message contains for wParam and lParam. It will also give you macros to use to extract the position from lParam...and also the position should be in mymsg.pt, as well.
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 7th Jun 2008 17:03
LOWORD(mymsg.lParam) contains MouseX co-ords and HIWORD(mymsg.lParam) the y values.

however i cannot get the code to trigger when the user presses lmb on my taskbar icon...
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 7th Jun 2008 21:05
I can't really help further without seeing all of the code, but...I'm fairly certain that what I said before holds true...you can't take control of the system like that and expect the Windows message pump to work; its not designed that way. You have to yield control at some point, and PeekMessage is a lame way to try to subclass a window behind its back. That's not the intent of PeekMessage anyway.

You are subclassing the window's behavior, and the only way I know that that can work is by hooking the window procedure of the GDK window, like I described above. That is the only way I'd even try to do anything involving the message pump.
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 8th Jun 2008 08:47
unfortunately it seems that PeekMessage() cannot supply the information I need.

So basically I am stuck.

I can create a taskbar icon and remove it (as per code supplied above). I can pass on msgs from my prog to the taskbar and change/animate icon.

However I cannot get to know when the user left or right mouse clicked on my taskbar icon... which basically renders all the above useless.
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 8th Jun 2008 15:37 Edited at: 8th Jun 2008 15:38
NOTIFYICONDATA has a member uCallbackMessage that is a user defined message that will be sent to the hWnd (GDK) you specify. Unless you hook the GDK window's WndProc, you will not be able to use that.

So, you are still lacking at least two things in your code:

You need to define a message id unique to your application. Acceptable values start at WM_USER, which is predefined. I don't think you can use a message that has already been defined. The help for it says application-defined.

Then, you need to hook the WndProc of the GDK.


One thing you might want to do is to restore the GDK's WndProc when you are done sitting in the system tray.
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 9th Jun 2008 08:58
I was already using a unique msg ID (because of NOTIFYICONDATA)

It was #define WM_MYMESSAGE (WM_USER + 1)


However I am getting an error on this line:

GDKWndProc = SetWindowLong(ptrGlobStruct->hWnd, GWL_WNDPROC, (LONG)MyWndProc);

error C2440: '=' : cannot convert from 'LONG' to 'WNDPROC'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 9th Jun 2008 09:28
I have put up a simple example code:



in resource.h I have defined (amongst the other things):

#define IDR_MAINFRAME 128

I also have a custom icon IDI_ICON2

If I keep the main window open, pressing lmb causes icon to appear in taskbar and pressing rmb removes icon (just to test that 2 functions work properly).

however the problem has always been that main window is hidden after taskbar icon appears!
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 11th Jun 2008 09:09
is dbGetGlobPtr() an undocumented command as I cannot find any info?
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 11th Jun 2008 09:23 Edited at: 11th Jun 2008 10:21
Sorry that I did not respond to your last post. I think that is normal behavior when you drop into the system tray like that. You could probably use Windows to get around that.

Yes, it is undocumented in DBPro, as well and requires a little chicanery to use it. It is however, a very useful function. The members of the GlobStruct structure are in the include file globstruct.h I think that it is undocumented because it exposes the core, but you cannot take advantage of all of it. For example, you cannot use it to make wholesale changes to how the engine works. The window handle and instance handle are a different matter, although there are certainly limitations there, too.

One other thing that is underdocumented is the DBO code in the folder DBO Format. There is also a function to get the pointer for a DBO object. That is also very useful. dbGetObject

EDIT: You might just as well add a menu for right click in the system tray WndProc. The menu resource is pretty easy to add, like the icon was. The main task, you've already done...define a WndProc. Now, you can add a menu in the place where you added the icon, and subclass in the same place. Also, you've almost got everything you need to create your own window class to use alongside the GDK, instead of inline with it. It is an optional way that I use to create my own window class with the EX style. That allows more powerful window styles to be used. You can use modeless dialogs, too which are visually more appealing over a 3D screen.

Here are a couple of snippets to show how to define a menu, and also an about box dialog.

In the .rc file:


In the resource.h file:


You load and add the resouce where your load the icon. You will need an HMENU to store the handle you load from the resource file. In that sample, the menu uses the default hot keys. That is what the ampersand indicates. ALT + the letter is the standard hot key comination in that case.

If you want to make your own window class(es), that is also the best place to do it.
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 11th Jun 2008 12:33
I still have not resolved this problem though...

GDKWndProc = SetWindowLong(ptrGlobStruct->hWnd, GWL_WNDPROC, (LONG)MyWndProc);

error C2440: '=' : cannot convert from 'LONG' to 'WNDPROC'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast

any ideas?
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 11th Jun 2008 16:21 Edited at: 11th Jun 2008 16:40
Sure, try it this way:
GDKWndProc = (WNDPROC)SetWindowLong(ptrGlobStruct->hWnd, GWL_WNDPROC, (LONG)MyWndProc);

See, you have to cast MyWndProc to a LONG because that is what SetWindowLong wants. You have to cast the LONG returned to the type that GDKWndProc is, which is WNDPROC, as well. C/C++ do not usually perform implicit casts (coercion, or automatic type conversion) for you in cases like this. 'C-style casting, or function-style casting' is called explicit casting because you are doing it. You are likely to get a warning about it, but you can safely ignore it if you are making a 32-bit program. That goes for other casts of 32-bit addresses, as well. (You will get a warning for casting char* types in that manner, too.)
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 11th Jun 2008 16:40
thanks Jinzai I fixed that error!

How does MyWndProc() work exactly as it tapes some params?

Do I call it from LoopGDK ()?
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 11th Jun 2008 16:42
No, the beauty of it is that you never call it. It is a CALLBACK...Windows calls it with the necessary parameters. They are the same ones that you were trying to get using PeekMessage. (It depends on the message you get.)
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 11th Jun 2008 17:02
Callback are quite noew to me, so pardon my utter ignorance on the matter.

Here is my updated code. Can't get it to work yet


jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 11th Jun 2008 17:23 Edited at: 11th Jun 2008 17:50
Well, CALLBACKs are not the simplest things to understand at first anyway. You need them alot in Windows. (You cannot do many enumerations without a CALLBACK, for example. GDK uses alot of them for the dbPerformCheckList type functions.)

First, I think you might want to consider making the NOTIFYICONDATA structure global, as well so that they exist after your function exits. (Part of writing event driven vs. procedure driven code.)

Next, your WndProc needs to test for your application defined message, otherwise you will be stealing all of the right click messages from GDK. One other thing that you should test in your WndProc...the hWnd you are given needs to be the same one in GlobStruct. Ordinarily, you won't get any messages for other windows, but...you can.

When you use the notify mechanism, you will get your message, and so you don't test the message for WM_RBUTTONDOWN...it is in the lParam parameter. (Whichever mouse event caused the message to be sent...look at the help for the NOTIFYICONDATA structure, the wParam is the ID of the icon, and the lParam is the mouse event that triggered the message.

**************** EDITED TO CORRECT CODE ****************
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 11th Jun 2008 17:36
also this does not work, which might be causing me some problems:

return CallWndProc(GDKWndProc, hWnd, message, wParam, lParam);
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 11th Jun 2008 17:38 Edited at: 11th Jun 2008 17:47
I'm not sure what you mean by it does not work...are you getting compiler errors?

Sorry, my bad...try this:
return CallWindowProc(GDKWndProc, hWnd, message, wParam, lParam);
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 11th Jun 2008 17:50
works fantastic now!

now i need to add some msg filtering to process only whenever the user right clicks on the taskbar icon, as right now everytime the mouse pointer goes over the taskbar icon, I am triggering dbShowWidow()
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 11th Jun 2008 17:52
Yes, you can put that in there, too...in the section that tests for your message....lParam is the place to check it...I just edited the snippet above, there is a note about that.

P.S. Ain't Windows cool when you finally get it working? (Oh, you will have other issues, but...now you have a place to take care of them.)
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 11th Jun 2008 21:09
fantastic. finally got it to work 100% as i wanted.

thanks a million Jinzai your knowledge is incredible.

I am now set to research every line of the above code so I can learn more about Windows and how structures work.

i hope that this will be usefull to others who will come across this thread searching for info about taskbar icons!
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 11th Jun 2008 21:41
Here is the final code, for sake of posterity.

Press the minimize Window icon, to iconify window. LMB on taskbar icon to open window again.

bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 11th Jun 2008 21:45
just a little offtopic consideration.

when the Window is iconified in taskbar, is there some way to make the main loop stop executing, and free cpu processing?

something in the lines of dbSleep or dbSynchOff comes to mind, but I don't know if these are the most adequate commands to work with...
jinzai
18
Years of Service
User Offline
Joined: 19th Aug 2006
Location: USA
Posted: 12th Jun 2008 00:46
dbSleep would only make it hang there. dbSyncOff is probably the best choice, but I'm not positive that it will execute when the window is hidden anyway. You could test it by incrementing a variable every time it loops, and then let it sit in the taskbar for a while, then bring it back up and see if the value changed much.

Its great that you got it working the way you wanted to. There's alot in there to study, that's for certain.

And, you're welcome. jinzai means "capable man", although some take it to mean "talented man". I have no such illusions...I'm capable, and that's the end of it for me.

Cheers.
Lilith
16
Years of Service
User Offline
Joined: 12th Feb 2008
Location: Dallas, TX
Posted: 12th Jun 2008 04:50
You'd almost certainly have to go into some loop that wouldn't be too tight and either test for the application getting focus or react to a gotfocus event. You'd also probably want to drop into the loop on any loss of focus, unless this isn't a game.

Lilith, Night Butterfly
I'm not a programmer but I play one in the office
bjadams
AGK Backer
16
Years of Service
User Offline
Joined: 29th Mar 2008
Location:
Posted: 12th Jun 2008 12:31
I am trying to take this one a step furthur.

I have switched Window style to borderless with dbSetWindowLayout (0, 0, 0)

Now I would like that the user can be able to the main window around the screen whilst pressing RMB and moving mouse.

I need to send a msg to the Window that the Window Caption is being pressed.

I am doing this with PostMessge() in LoopGDK() :

if (dbMouseClick()==2) PostMessage(ptrGlobStruct->hWnd, WM_NCLBUTTONDOWN, HTCAPTION, NULL);

However this is having no effect whatsoever.

Any ideas?

Login to post a reply

Server time is: 2024-09-29 23:19:11
Your offset time is: 2024-09-29 23:19:11