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
ShowImageApp()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_VOID("ShowImage");
43 _UpdateLastWindowFrame();
44 // BBitmap can be created after there is a BApplication instance.
45 init_tool_bar_icons();
46 }
47
48
~ShowImageApp()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
ArgvReceived(int32 argc,char ** argv)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
ReadyToRun()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
MessageReceived(BMessage * message)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
Pulse()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
RefsReceived(BMessage * message)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
QuitRequested()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 DefaultCache().Stop();
178
179 return result;
180 }
181
182
183 void
_StartPulse()184 ShowImageApp::_StartPulse()
185 {
186 if (!fPulseStarted) {
187 // Tell the app to begin checking
188 // for the number of open windows
189 fPulseStarted = true;
190 SetPulseRate(250000);
191 // Set pulse to every 1/4 second
192 }
193 }
194
195
196 void
_Open(const entry_ref & ref,const BMessenger & trackerMessenger)197 ShowImageApp::_Open(const entry_ref& ref, const BMessenger& trackerMessenger)
198 {
199 fLastWindowFrame.OffsetBy(20, 20);
200 if (!BScreen(B_MAIN_SCREEN_ID).Frame().Contains(fLastWindowFrame))
201 fLastWindowFrame.OffsetTo(50, 50);
202
203 new ShowImageWindow(fLastWindowFrame, ref, trackerMessenger);
204 }
205
206
207 void
_BroadcastToWindows(BMessage * message)208 ShowImageApp::_BroadcastToWindows(BMessage* message)
209 {
210 const int32 count = CountWindows();
211 for (int32 i = 0; i < count; i++) {
212 // BMessenger checks for us if BWindow is still a valid object
213 BMessenger messenger(WindowAt(i));
214 messenger.SendMessage(message);
215 }
216 }
217
218
219 void
_CheckClipboard()220 ShowImageApp::_CheckClipboard()
221 {
222 // Determines if the contents of the clipboard contain
223 // data that is useful to this application.
224 // After checking the clipboard, a message is sent to
225 // all windows indicating that the clipboard has changed
226 // and whether or not the clipboard contains useful data.
227 bool dataAvailable = false;
228
229 if (be_clipboard->Lock()) {
230 BMessage* clip = be_clipboard->Data();
231 if (clip != NULL) {
232 dataAvailable = clip->HasMessage("image/bitmap")
233 || clip->HasMessage("image/x-be-bitmap");
234 }
235
236 be_clipboard->Unlock();
237 }
238
239 BMessage msg(B_CLIPBOARD_CHANGED);
240 msg.AddBool("data_available", dataAvailable);
241 _BroadcastToWindows(&msg);
242 }
243
244
245 void
_UpdateLastWindowFrame()246 ShowImageApp::_UpdateLastWindowFrame()
247 {
248 fLastWindowFrame = fSettings.GetRect("WindowFrame", fLastWindowFrame);
249 // Compensate the offset which we always add to new windows.
250 fLastWindowFrame.OffsetBy(-20, -20);
251 }
252
253
254 // #pragma mark -
255
256
257 int
main(int,char **)258 main(int, char**)
259 {
260 ShowImageApp app;
261 app.Run();
262 return 0;
263 }
264
265