[haiku] Deskbar won't "Close All"; who to blame :)

  • From: Caitlin Shaw <rogueeve@xxxxxxxxxxxxx>
  • To: haiku@xxxxxxxxxxxxx
  • Date: Sat, 24 Oct 2009 19:36:40 -0700


I've been investigating an issue I discovered yesterday; which is that on several of my programs the Deskbar "Close All" option (under the window list menu) results in... nothing happening.

Tracking it down, I discovered at the bottom of ShowHideMenuItem.cpp in the Deskbar app the code for "Close All". The Deskbar constructs a BMessenger off of the team ID of the application, and then attempts to send the app a B_QUIT_REQUESTED message through that messenger. The problem is that the BMessenger instantiation is failing with B_BAD_TYPE. And the reason for that, is that that is what a BMesssenger does if the application has B_ARGV_ONLY set in the application flags resource. The applications in question don't make use of any of the special application flags, so I didn't provide a flags resource. And it seems that if you don't provide the flags, the system returns some default ones when asked for them, and those defaults include B_ARGV_ONLY.

So, know that I now how to fix it, I'm wondering whether this is a series of sensible behaviors that together culminate in an unfortunate error, or is it by design and I was very very bad not to include an application flags resource in my program. I know you are supposed to specify a signature, but I had always assumed that the other resources such as icons and flags were optional, especially since the FileTypes applet includes a checkbox for turning the use of app flags on and off.

It seems that perhaps the system could include the B_ARGV_ONLY flag based on the app signature being missing instead of the flags being missing; if the signature is missing it is obviously a unix or terminal app like "ls", etc so the flag is appropriate. Alternatively, the Deskbar could check for that condition and in that case try to quit the app some other way, such as sending messages to all of it's open windows, or sending a posix SIGTERM.

Of course, if neglecting to provide a flags resource is Absolutely Wrong, then it's all my "fault" and that fact just needs to be documented somewhere in the Hello World type guides, which I sure it will be once the OS gets a little more popular, or may even already be.


FYI, here's the test program. The window it produces fails to close via "Close All". Clicking the big "Quit" button is supposed to quit the app by constructing a BMessenger off of the team id in the same way as the Deskbar does, but it doesn't work because the BMessenger fails to instantiate. If you open the binary in FileTypes and manually check the "Application Flags" box, then it starts working.


#include <Application.h>
#include <Window.h>
#include <Button.h>
#include <Roster.h>
#include <stdio.h>
#include <string.h>

#define SIGNATURE        "application/xvnd-Kt.NoClose"
#define M_QUIT_PRESSED    'MQPR'

class QuitButton : public BButton
{
public:
   QuitButton(BRect frame, const char *label)
: BButton(frame, NULL, label, new BMessage(M_QUIT_PRESSED), B_FOLLOW_ALL) { } };

class MyWindow : public BWindow
{
public:
   MyWindow(BRect frame)
       : BWindow(frame, "Can't Close", B_TITLED_WINDOW, 0)
   {
       BRect rc(Bounds());
       rc.InsetBy(20, 20);
       AddChild(new QuitButton(rc, "QUIT APP"));
       Show();
   }
void MessageReceived(BMessage *msg)
   {
       char what_code[5];
       what_code[0] = (msg->what >> 24) & 255;
       what_code[1] = (msg->what >> 16) & 255;
       what_code[2] = (msg->what >> 8) & 255;
       what_code[3] = msg->what & 255;
       what_code[4] = 0;
printf("window: got message '%s'\n", what_code);
       fflush(stdout);
if (msg->what == M_QUIT_PRESSED)
       {
           team_id team = be_app->Team();
           status_t error = -1;
           uint32 command = B_QUIT_REQUESTED;
printf("\n------------\n");
           app_info info;
           info.flags = 0;
           if (be_roster->GetRunningAppInfo(team, &info) == B_OK)
           {
               printf("app flags = %08x\n", info.flags);
               if (info.flags & B_ARGV_ONLY)
                   printf("Warning: info.flags has B_ARGV_ONLY set\n");
           }
printf("Creating messenger with NULL sig and team_id=%d...\n", team); BMessenger messenger((char*)NULL, team, &error); switch(error)
           {
               case B_OK: printf("OK!\n"); break;
               case B_BAD_VALUE: printf("B_BAD_VALUE!\n"); break;
               case B_BAD_TYPE: printf("B_BAD_TYPE!\n"); break;
               case B_BAD_TEAM_ID: printf("B_BAD_TEAM_ID!\n"); break;
case B_MISMATCHED_VALUES: printf("B_MISMATCHED_VALUES!\n"); break;
               case B_BAD_HANDLER: printf("B_BAD_HANDLER!\n"); break;
           }
printf("error = %08x : %s\n", error, strerror(error));
           printf("attempting to send B_QUIT_REQUESTED...\n");
           fflush(stdout);
messenger.SendMessage(command);
       }
BWindow::MessageReceived(msg);
   }
bool QuitRequested()
   {
       printf("Window: Quit Requested!\n");
       fflush(stdout);
be_app->PostMessage(B_QUIT_REQUESTED);
       return BWindow::QuitRequested();
   }
};

class MyApp : public BApplication
{
public:
   MyApp(const char *sig)
       : BApplication(sig)
   {
       printf("MyApp() constructor\n");
       fflush(stdout);
   }
void ReadyToRun()
   {
       printf("ReadyToRun!\n");
       fflush(stdout);
MyWindow *win = new MyWindow(BRect(200, 200, 500, 500));
   }
bool QuitRequested()
   {
       printf("App: Quit Requested!\n");
       fflush(stdout);
return BApplication::QuitRequested();
   }
};


int main(int argc, char *argv[])
{
   new MyApp(SIGNATURE);
   be_app->Run();
   delete be_app;
return 0;
}




Other related posts: