1/* 2 * Copyright 2003-2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Fernando Francisco de Oliveira 7 * Michael Wilber 8 * Michael Pfeiffer 9 * Ryan Leavengood 10 */ 11 12 13#include "ShowImageApp.h" 14 15#include <stdio.h> 16 17#include <Catalog.h> 18#include <Clipboard.h> 19#include <FilePanel.h> 20#include <Locale.h> 21#include <Path.h> 22#include <Screen.h> 23#include <String.h> 24 25#include "ShowImageConstants.h" 26#include "ShowImageWindow.h" 27#include "ToolBarIcons.h" 28 29 30const char* kApplicationSignature = "application/x-vnd.Haiku-ShowImage"; 31const int32 kWindowsToIgnore = 1; 32 // ignore the always open file panel 33 34 35ShowImageApp::ShowImageApp() 36 : 37 BApplication(kApplicationSignature), 38 fOpenPanel(new BFilePanel(B_OPEN_PANEL)), 39 fPulseStarted(false), 40 fLastWindowFrame(BRect(30, 30, 430, 330)) 41{ 42 B_TRANSLATE_MARK_SYSTEM_NAME_VOID("ShowImage"); 43 _UpdateLastWindowFrame(); 44 // BBitmap can be created after there is a BApplication instance. 45 init_tool_bar_icons(); 46} 47 48 49ShowImageApp::~ShowImageApp() 50{ 51 // BBitmap must be deleted while there is still a BApplication instance. 52 uninit_tool_bar_icons(); 53} 54 55 56void 57ShowImageApp::ArgvReceived(int32 argc, char **argv) 58{ 59 BMessage message; 60 bool hasRefs = false; 61 62 // get current working directory 63 const char* cwd; 64 if (CurrentMessage() == NULL 65 || CurrentMessage()->FindString("cwd", &cwd) != B_OK) 66 cwd = ""; 67 68 for (int32 i = 1; i < argc; i++) { 69 BPath path; 70 if (argv[i][0] == '/') { 71 // absolute path 72 path.SetTo(argv[i]); 73 } else { 74 // relative path 75 path.SetTo(cwd); 76 path.Append(argv[i]); 77 } 78 79 entry_ref ref; 80 status_t err = get_ref_for_path(path.Path(), &ref); 81 if (err == B_OK) { 82 message.AddRef("refs", &ref); 83 hasRefs = true; 84 } 85 } 86 87 if (hasRefs) 88 RefsReceived(&message); 89} 90 91 92void 93ShowImageApp::ReadyToRun() 94{ 95 if (CountWindows() == kWindowsToIgnore) 96 fOpenPanel->Show(); 97 else { 98 // If image windows are already open 99 // (paths supplied on the command line) 100 // start checking the number of open windows 101 _StartPulse(); 102 } 103 104 be_clipboard->StartWatching(be_app_messenger); 105 // tell the clipboard to notify this app when its contents change 106} 107 108 109void 110ShowImageApp::MessageReceived(BMessage* message) 111{ 112 switch (message->what) { 113 case MSG_FILE_OPEN: 114 fOpenPanel->Show(); 115 break; 116 117 case B_CANCEL: 118 // File open panel was closed, 119 // start checking count of open windows 120 _StartPulse(); 121 break; 122 123 case B_CLIPBOARD_CHANGED: 124 _CheckClipboard(); 125 break; 126 127 case MSG_WINDOW_HAS_QUIT: 128 // Make sure that new windows open with the location/size of the 129 // last closed window. 130 _UpdateLastWindowFrame(); 131 break; 132 133 default: 134 BApplication::MessageReceived(message); 135 break; 136 } 137} 138 139 140void 141ShowImageApp::Pulse() 142{ 143 // Bug: The BFilePanel is automatically closed if the volume that 144 // is displayed is unmounted. 145 if (!IsLaunching() && CountWindows() <= kWindowsToIgnore) { 146 // If the application is not launching and 147 // all windows are closed except for the file open panel, 148 // quit the application 149 PostMessage(B_QUIT_REQUESTED); 150 } 151} 152 153 154void 155ShowImageApp::RefsReceived(BMessage* message) 156{ 157 // If a tracker window opened me, get a messenger from it. 158 BMessenger trackerMessenger; 159 if (message->HasMessenger("TrackerViewToken")) 160 message->FindMessenger("TrackerViewToken", &trackerMessenger); 161 162 entry_ref ref; 163 for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) 164 _Open(ref, trackerMessenger); 165} 166 167 168bool 169ShowImageApp::QuitRequested() 170{ 171 // Give the windows a chance to prompt the user if there are changes 172 bool result = BApplication::QuitRequested(); 173 if (result) { 174 be_clipboard->StopWatching(be_app_messenger); 175 // tell clipboard we don't want anymore notification 176 } 177 178 return result; 179} 180 181 182void 183ShowImageApp::_StartPulse() 184{ 185 if (!fPulseStarted) { 186 // Tell the app to begin checking 187 // for the number of open windows 188 fPulseStarted = true; 189 SetPulseRate(250000); 190 // Set pulse to every 1/4 second 191 } 192} 193 194 195void 196ShowImageApp::_Open(const entry_ref& ref, const BMessenger& trackerMessenger) 197{ 198 fLastWindowFrame.OffsetBy(20, 20); 199 if (!BScreen(B_MAIN_SCREEN_ID).Frame().Contains(fLastWindowFrame)) 200 fLastWindowFrame.OffsetTo(50, 50); 201 202 new ShowImageWindow(fLastWindowFrame, ref, trackerMessenger); 203} 204 205 206void 207ShowImageApp::_BroadcastToWindows(BMessage* message) 208{ 209 const int32 count = CountWindows(); 210 for (int32 i = 0; i < count; i++) { 211 // BMessenger checks for us if BWindow is still a valid object 212 BMessenger messenger(WindowAt(i)); 213 messenger.SendMessage(message); 214 } 215} 216 217 218void 219ShowImageApp::_CheckClipboard() 220{ 221 // Determines if the contents of the clipboard contain 222 // data that is useful to this application. 223 // After checking the clipboard, a message is sent to 224 // all windows indicating that the clipboard has changed 225 // and whether or not the clipboard contains useful data. 226 bool dataAvailable = false; 227 228 if (be_clipboard->Lock()) { 229 BMessage* clip = be_clipboard->Data(); 230 if (clip != NULL) { 231 dataAvailable = clip->HasMessage("image/bitmap") 232 || clip->HasMessage("image/x-be-bitmap"); 233 } 234 235 be_clipboard->Unlock(); 236 } 237 238 BMessage msg(B_CLIPBOARD_CHANGED); 239 msg.AddBool("data_available", dataAvailable); 240 _BroadcastToWindows(&msg); 241} 242 243 244void 245ShowImageApp::_UpdateLastWindowFrame() 246{ 247 fLastWindowFrame = fSettings.GetRect("WindowFrame", fLastWindowFrame); 248 // Compensate the offset which we always add to new windows. 249 fLastWindowFrame.OffsetBy(-20, -20); 250} 251 252 253// #pragma mark - 254 255 256int 257main(int, char**) 258{ 259 ShowImageApp app; 260 app.Run(); 261 return 0; 262} 263 264