Board index » cppbuilder » Re: Catching the Application->Minimize() ..event from TaskBar Buttons
JD
![]() CBuilder Developer |
JD
![]() CBuilder Developer |
Re: Catching the Application->Minimize() ..event from TaskBar Buttons2005-11-11 12:16:52 AM cppbuilder4 Simon Guertin < XXXX@XXXXX.COM >wrote: Quote
would suggest you look here instead: tinyurl.com/bvoy6 ~ JD |
Simon Guertin
![]() CBuilder Developer |
2005-11-11 12:17:44 AM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
Good morning all!
I am using the TTrayIcon and there is one odd behavior that is happening in my application. When I have a TForm open and I use the TaskBar button to toggle between Minimized and The restore state, it does not behave correctly. If the Window is already open, (In maximized state or normal) and I click on the Taskbar button, it makes the window disapear. But if I click on the Taskbar after I intentionaly minimized the window by using the Minimize Button, it restores the state of the window. I was trying to catch WM_Message that could come from the task bar to fix this behavior but I don't know where to trap it. Or do I need to Extend and Modify TTrayIcon to alterate the behavior when the minize/restore message is received from the OS? thanks Simon |
JD
![]() CBuilder Developer |
2005-11-11 01:43:33 AM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
Simon Guertin < XXXX@XXXXX.COM >wrote:
Quote
applications. ~ JD {smallsort} |
Simon Guertin
![]() CBuilder Developer |
2005-11-11 01:54:03 AM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
JD wrote:
QuoteSimon Guertin < XXXX@XXXXX.COM >wrote: :) have a good day! |
Vladimir Stefanovic
![]() CBuilder Developer |
2005-11-11 03:03:32 AM
Re:Re: Catching the Application->Minimize() ..event from TaskBar ButtonsQuoteThank you, I now have another problem, I need to You have the whole source, so you are the master. No need to worry. -- Best regards, Vladimir Stefanovic |
Simon Guertin
![]() CBuilder Developer |
2005-11-11 04:18:49 AM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
Vladimir Stefanovic wrote:
Quote>Thank you, I now have another problem, I need to |
Simon Guertin
![]() CBuilder Developer |
2005-11-15 02:26:32 AM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
I am using the TrayIcon from your link and I modified it so the
application does not minimize to the tray icon when I push the task bar button. It now works fine but there is one little problem remaining. When I minimize the Window to the task bar, instead of just clicking the task bar button, I right click on the task bar button and then I choose restore. The application restores properly but after this, clicking on the task bar button does not toggle between the Minimized and Restore state. It does not even trigger the minimize and restore events. But if I simply right click again (I don't have to choose Restore or Minimize) on the task bar button, the behavior is normal again. I notice I am still receiving other events but not WM_SYSCOMMAND types event. I also modified the Tray to use a "Fake Main Form" because my main form is special and remains hiddden forever. Thank you Simon |
Simon Guertin
![]() CBuilder Developer |
2005-11-15 05:17:28 AM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
Never mind this, I believe it is a normal Windows Behavior, it seems to
do the same in all the other applications (but it still seems like a bug ) Simon Guertin wrote: QuoteI am using the TrayIcon from your link and I modified it so the |
JD
![]() CBuilder Developer |
2005-11-15 06:21:50 PM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
Simon Guertin < XXXX@XXXXX.COM >wrote:
Quote
Windows using the win32 API SetWindowLong. I did it this way because the application would animate to the taskbar and then disappear from the taskbar. The result is that the application animates to the system tray instead. Exactly how did you modify the Minimize and Restore methods? Quote[...] but after this, clicking on the task bar button does right clicking the program's icon. I've seen it before when one restores a window that is already restored. The Minimize border icon is disabled and clicking the tray icon does nothing unless it's right clicked but then that clears the problem. QuoteI am still receiving other events but not WM_SYSCOMMAND QuoteI also modified the Tray to use a "Fake Main Form" because To do what you are trying to do would require rewritting several blocks of code because Windows doesn't report the window state correctly 100% of the time and you need to know the correct state before you restore. The component deals with this by hooking into the main form's WndProc method and manually tracking the application's state. Since you changed the main form from being the 'main form', you need to hook into the other form instead. Why are you hidding the main form and displaying another? ISTM that if all it is being used for is a class container, that that code could go into a seperate unit and be allocated in the main form's constructor. I also read your other post and to be clear, it is not normal Windows behavior. It's your code that's doing it. ~ JD |
Simon Guertin
![]() CBuilder Developer |
2005-11-16 12:40:40 AM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
Good morning!
QuoteI also read your other post and to be clear, it is not normal their own things wrong. I have just reproduced the behavior and here are the exacts steps. 1. Reboot Windows. (To make sure nothing is left from my TrayIcon code just in case) 2. I opened Internet Explorer (6.0) 3. I maximized IE using the top right Maximize button. 4. I then minimized IE using the Top right minimize button 5. Then I right click on IE's Taskbar button at the bottom of my desktop. 6. I then choose Restore (The window gets restore in the maximized state) 7. I Left click many times on the IE's task bar button (The button get toggled in the push state and unclicked state) but nothing happens anymore. 8. I simply right click on IE's task bar button to make the menu show up but I don't choose anything. 9. I click somewhere else in the screen to make this menu disapear. 10. I left click on IE's Taskbar button and the behavior if finally restored. (It makes the window toggles between minimize and maximize state.) QuoteWhy are you hidding the main form and displaying another? ISTM Let me explain why. Our application is very tricky and we don't create all our forms in the project's main .cpp file. Also, the way Borland assigns the Main form is not the way it is said in the Documentation. It does not assign the Main form to the Main form specified in the Project's Option main form or to the first form that is created in the project's main .cpp file (normally the Main Form is the first one Application->CreateForm(__classid(TForm1), &Form1);) It really allocates the Main form to the first form that has completely return from creation.) Ok so in my case, there are some objects that are getting parse during the creation of a form and indirectly creates Other forms but they remain invisible. In the end, the first form that finish creating becomes the application's main form. We have no way to control this order, so when we would close that form, the application would shutdown. So I created the real MainForm that does not get parse and That I am sure is created first. This form is like our dummy form that is always the Application's Application->MainForm. And so we delegated the Applciation's Main form role to another Window. A Normal window that the user interacts with. Quote
new field FMainForm ... But this object is still instanciated in the Real Application->MainForm. bool __fastcall TAnimatedTrayIcon::Minimize(bool IsSystemMinimize) { FMinimized = true; if( FUseTray && FActive ) { if( !FAnimating || !FLoopSound ) ::PlaySound( (LPCSTR)MinimizeWave, NULL, SND_MEMORY | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT ); BoundsRect = FMainForm->BoundsRect; //if(!IsSystemMinimize)::DrawAnimatedRects(FMainForm->Handle, IDANI_CAPTION, &BoundsRect, &TrayRect ); if( FMainForm->FormStyle != fsMDIForm ) { for( int x = 0; x < Screen->FormCount; ++x ) { if( Screen->Forms[x]->Visible ) vForms.push_back( Screen->Forms[x] ); } HWND hWnd = ::GetTopWindow( FMainForm->Handle ); while( hWnd ) { vZOrder.push_back( hWnd ); hWnd = ::GetNextWindow( hWnd, GW_HWNDNEXT ); } for( unsigned int x = 0; x < vForms.size(); ++x ) vForms[x]->Visible = false; } else FMainForm->Visible = false; Application->ShowMainForm = false; if(IsSystemMinimize) ::ShowWindow( Application->Handle, SW_MINIMIZE ); else ::ShowWindow( Application->Handle, SW_HIDE ); ::SetWindowLong( Application->Handle, GWL_STYLE, ::GetWindowLong(Application->Handle, GWL_STYLE) | WS_MINIMIZE ); return true; } return false; } //-------------------------------------------------------------- bool __fastcall TAnimatedTrayIcon::Restore(bool IsSystemRestore) { bool Result = false; if( FUseTray && FActive && FMinimized ) { if( !FAnimating || !FLoopSound ) ::PlaySound( (LPCSTR)RestoreWave, NULL, SND_MEMORY | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT ); //if(!IsSystemRestore) ::DrawAnimatedRects(FMainForm->Handle, IDANI_CAPTION, &TrayRect, &BoundsRect ); if( FMainForm->FormStyle != fsMDIForm ) { if(FMainForm->Visible == false && !IsSystemRestore) FMainForm->Visible = true; for( int x = vForms.size() - 1; x>-1; --x ) vForms[x]->Visible = true; for( int x = vZOrder.size() - 1; x>-1; --x ) ::ShowWindow( vZOrder[x], SW_SHOW ); vZOrder.clear(); vForms.clear(); } else { FMainForm->Visible = true; FMainForm->ArrangeIcons(); } ::ShowWindow( Application->Handle, SW_SHOW ); // ::ShowWindow( FMainForm->Handle, SW_SHOW ); Application->Restore(); Application->BringToFront(); Result = true; } FMinimized = false; return Result; } |
JD
![]() CBuilder Developer |
2005-11-16 03:32:54 AM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
Simon Guertin < XXXX@XXXXX.COM >wrote:
Quote
Quote2. I opened Internet Explorer (6.0) Quote>Why are you hidding the main form [...] Quote[...] there are some objects that are getting parse during fully created. In fact, my TrayIcon source demonstrates doing this. In it's constructor, it uses the win32 API PostMessage to complete initialization because the final step has to wait until the TApplication::MainForm is valid. The TrayIcon code would need a slight modification because the TForm already has a WndProc method so instead of creating one like the TrayIcon, you need to override it instead. For example: //--- in the header ------------------------------------------- protected: // User declarations virtual void __fastcall WndProc( TMessage &Message ); private: #define UWM_INITIALIZE (WM_USER + 100) typedef TForm inherited; //--- in the unit --------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { // Do all of your initialization except the stuff // related to creating other forms. // As your last command: ::PostMessage( Handle, UWM_INITIALIZE, 0, 0 ); } //------------------------------------------------------------- void __fastcall TForm1::WndProc( TMessage &Message ) { if( Message.Msg == UWM_INITIALIZE ) { // move your problem code from the ctor to here } inherited::WndProc( Message ); } //------------------------------------------------------------- Another way to accomplish the exact same thing is to use a message map instead. For example: //--- in the header ------------------------------------------- private: #define UWM_INITIALIZE (WM_USER + 100) MESSAGE void __fastcall UWMInitialize( TMessage &Message ); public: BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER( UWM_INITIALIZE, TMessage, UWMInitialized ) END_MESSAGE_MAP( TForm ) //--- in the unit --------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { // Do all of your initialization except the stuff // related to creating other forms. // As your last command: ::PostMessage( Handle, UWM_INITIALIZE, 0, 0 ); } //------------------------------------------------------------- MESSAGE void __fastcall TForm1::UWMInitialize(TMessage &Message) { // move your problem code to here } //------------------------------------------------------------- Should take you 5 minutes to cut and paste - tops. Quote>Exactly how did you modify the Minimize and Restore methods? AppHook method to the fake main form's WndProc method that is demonstrated above: if( Message.Msg == WM_SYSCOMMAND ) { switch( Message.WParam ) { case SC_RESTORE: case SC_MAXIMIZE: return Restore(); case SC_MINIMIZE: return Minimize(); } } but it's not as simple as that. The Restore and Minimize methods would no longer return a value so they would be defined as void instead of bool. How you deal with actually minimizing and restoring should be different as well because now Windows will actually minimize and restore the fake main. I don't see any obviouse problems with your Minimize and Restore methods but I'm also not inclined to build a test bed to check it. That said, I would strongly suggest that you reconsider using the fake main form. ISTM that it would clear up several issues for you and most likely prevent several more in the time to come. ~ JD |
Simon Guertin
![]() CBuilder Developer |
2005-11-16 06:04:57 AM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
Thanks , I will look into your suggestions and let you know!
JD wrote: QuoteSimon Guertin < XXXX@XXXXX.COM >wrote: |
Simon Guertin
![]() CBuilder Developer |
2005-11-16 11:00:41 PM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
Hello again! I am encountering a problem when I tried to display a modal
form directly from the tray icon and without having a Fake Main form or Real Main form open. The first time around I would right click on the tray to open a form (Form->ShowModal()) and it would work. I would close the form using Right click ->Close on the task bar button. I would then reopen the same Modal form using the tray. It would then crash, saying cannot display modal form. I fixed this bu calling Application->Restore before showing the Modal form. It seems to work. I suspect that my problem could be at two places. First I am thinking it is the modified right click of the popup. Do you think setting the foreground window to the fake main form if ok or I really need to set the foreground window the the real Application->MainForm. Or secondly, I should check if there is a parent window before calling a showmodal and if not I just need to call Show() on my form? //Modified popup right click if( FPopupMenu ) { ::SetForegroundWindow( FMainForm->Handle ); //or ::SetForegroundWindow( Application->MainForm->Handle ); FPopupMenu->PopupComponent = this; FPopupMenu->Popup( P.x, P.y ); ::PostMessage( Application->MainForm->Handle, WM_NULL, 0, 0 ); //why this post message that does nothing? should it be send to my fake //main form instead? } thanks Simon |
JD
![]() CBuilder Developer |
2005-11-17 12:15:28 AM
Re:Re: Catching the Application->Minimize() ..event from TaskBar Buttons
Simon Guertin < XXXX@XXXXX.COM >wrote:
Quote
Application->Restore fixed the problem, there's also a possibility that the window state is getting mixed up which would be a result of using a fake main. Typically, when a tray icon displays a secondary form, it's non-modal and gets it's own taskbar icon. The seperate taskbar icon is achieved by overriding the form's CreateParams method and applying the WS_EX_APPWINDOW to it's ExStyle. Quote[...] I suspect that my problem could be at two places. tray code so that it's a different animal and it's only going to get more complicated. How close are you? Have you tried getting rid of the fake main? Quote::PostMessage( Application->MainForm->Handle, WM_NULL, 0, 0 ); Quoteshould it be send to my fake ~ JD |