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 30 const char* kApplicationSignature = "application/x-vnd.Haiku-ShowImage"; 31 const int32 kWindowsToIgnore = 1; 32 // ignore the always open file panel 33 34 35 ShowImageApp::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("ShowImage"); 43 _UpdateLastWindowFrame(); 44 // BBitmap can be created after there is a BApplication instance. 45 init_tool_bar_icons(); 46 } 47 48 49 ShowImageApp::~ShowImageApp() 50 { 51 // BBitmap must be deleted while there is still a BApplication instance. 52 uninit_tool_bar_icons(); 53 } 54 55 56 void 57 ShowImageApp::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 92 void 93 ShowImageApp::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 109 void 110 ShowImageApp::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 140 void 141 ShowImageApp::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 154 void 155 ShowImageApp::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 168 bool 169 ShowImageApp::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 182 void 183 ShowImageApp::_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 195 void 196 ShowImageApp::_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 206 void 207 ShowImageApp::_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 218 void 219 ShowImageApp::_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 244 void 245 ShowImageApp::_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 256 int 257 main(int, char**) 258 { 259 ShowImageApp app; 260 app.Run(); 261 return 0; 262 } 263 264