3 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "mainerror.h"
29 #include <sys/types.h>
32 #include <sys/types.h>
39 // 1 = update from client, 2 = client closes, 3 = quit
43 SvgWin::SvgWin(SvgMain *client)
44 : PluginClientWindow(client, xS(420), yS(210), xS(420), yS(210), 1)
46 this->client = client;
54 void SvgWin::create_objects()
56 int xs10 = xS(10), xs15 = xS(15);
57 int ys5 = yS(5), ys10 = yS(10), ys20 = yS(20), ys15 = yS(15);
59 int x0 = xs10, y = ys10;
61 add_tool(title = new BC_Title(x0, y, _("Out X:")));
62 int x1 = x0 + title->get_w() + xs10;
63 out_x = new SvgCoord(this, client, x1, y, &client->config.out_x);
64 out_x->create_objects();
65 int x2 = x1 + out_x->get_w() + xs15;
66 add_tool(title = new BC_Title(x2, y, _("Out W:")));
67 int x3 = x2 + title->get_w() + xs10;
68 out_w = new SvgCoord(this, client, x3, y, &client->config.out_w);
69 out_w->create_objects();
70 y += out_x->get_h() + ys5;
72 add_tool(new BC_Title(x0, y, _("Out Y:")));
73 out_y = new SvgCoord(this, client, x1, y, &client->config.out_y);
74 out_y->create_objects();
75 add_tool(title = new BC_Title(x2, y, _("Out H:")));
76 out_h = new SvgCoord(this, client, x3, y, &client->config.out_h);
77 out_h->create_objects();
78 y += out_y->get_h() + ys20;
80 add_tool(title = new BC_Title(x0, y, _("DPI:")));
81 dpi = new DpiValue(this, client, x1, y, &client->config.dpi);
82 dpi->create_objects();
83 add_tool(dpi_button = new DpiButton(this, client, x2, y));
84 dpi_button->create_objects();
85 y += dpi->get_h() + ys20;
87 add_tool(svg_file_title = new BC_Title(x0, y, client->config.svg_file));
88 y += svg_file_title->get_h() + ys5;
90 int64_t ms_time = stat(client->config.svg_file, &st) ? 0 :
91 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
92 char mtime[BCSTRLEN]; mtime[0] = 0;
94 time_t tm = ms_time/1000;
97 add_tool(svg_file_mstime = new BC_Title(x0, y, mtime));
98 y += svg_file_mstime->get_h() + ys15;
100 y = get_h() - NewSvgButton::calculate_h() - ys5;
101 add_tool(new_svg_button = new NewSvgButton(client, this, x0, y));
102 y = get_h() - EditSvgButton::calculate_h() - ys5;
103 add_tool(edit_svg_button = new EditSvgButton(client, this, x0+xS(300), y));
109 int SvgWin::close_event()
111 new_svg_button->stop();
112 edit_svg_button->stop();
117 int SvgWin::hide_window(int flush)
119 new_svg_button->stop();
120 edit_svg_button->stop();
121 return BC_WindowBase::hide_window(flush);
125 void SvgWin::update_gui(SvgConfig &config)
127 lock_window("SvgWin::update_gui");
128 out_x->update(config.out_x);
129 out_y->update(config.out_y);
130 out_w->update(config.out_w);
131 out_h->update(config.out_h);
132 dpi->update(config.dpi);
133 svg_file_title->update(config.svg_file);
134 char mtime[BCSTRLEN]; mtime[0] = 0;
135 if( config.ms_time > 0 ) {
136 time_t tm = config.ms_time/1000;
139 svg_file_mstime->update(mtime);
143 SvgCoord::SvgCoord(SvgWin *win, SvgMain *client, int x, int y, float *value)
144 : BC_TumbleTextBox(win, *value, (float)0, (float)3000, x, y, xS(100))
146 //printf("SvgWidth::SvgWidth %f\n", client->config.w);
147 this->client = client;
152 SvgCoord::~SvgCoord()
156 int SvgCoord::handle_event()
158 *value = atof(get_text());
159 client->send_configure_change();
163 NewSvgButton::NewSvgButton(SvgMain *client, SvgWin *window, int x, int y)
164 : BC_GenericButton(x, y, _("New/Open SVG..."))
166 this->client = client;
167 this->window = window;
170 NewSvgButton::~NewSvgButton()
176 int NewSvgButton::handle_event()
178 window->editing_lock.lock();
179 if( !window->editing ) {
181 window->editing_lock.unlock();
186 window->editing_lock.unlock();
192 void NewSvgButton::run()
194 // ======================================= get path from user
196 //printf("NewSvgButton::run 1\n");
199 strncpy(filename, client->config.svg_file, sizeof(filename));
200 // Loop until file is chosen
202 char directory[1024];
203 strncpy(directory, client->config.svg_file, sizeof(directory));
204 char *cp = strrchr(directory, '/');
206 if( !directory[0] ) {
207 char *cp = getenv("HOME");
208 if( cp ) strncpy(directory, cp, sizeof(directory));
210 new_window = new NewSvgWindow(client, window, directory);
211 new_window->create_objects();
212 new_window->lock_window("NewSvgButton::run");
213 new_window->update_filter("*.svg");
214 new_window->unlock_window();
215 result = new_window->run_window();
216 const char *filepath = new_window->get_path(0);
217 strcpy(filename, filepath ? filepath : "" );
218 delete new_window; new_window = 0;
219 window->editing_lock.lock();
220 if( result || !filename[0] )
222 window->editing_lock.unlock();
223 if( !window->editing ) return; // cancel or no filename given
225 // Extend the filename with .svg
226 if( strlen(filename) < 4 ||
227 strcasecmp(&filename[strlen(filename) - 4], ".svg") ) {
228 strcat(filename, ".svg");
231 if( !access(filename, R_OK) )
234 FILE *out = fopen(filename,"w");
236 extern unsigned char _binary_new_svg_start[];
237 extern unsigned char _binary_new_svg_end[];
238 unsigned int *ip = (unsigned int *)_binary_new_svg_start;
239 unsigned int hdr_sz = *ip++;
240 unsigned char *dp = (unsigned char *)ip + hdr_sz;
241 unsigned char *ep = _binary_new_svg_end;
242 fwrite(dp, ep - dp, 1, out);
247 } while(result); // file doesn't exist so repeat
249 strcpy(client->config.svg_file, filename);
250 client->config.ms_time = 0;
251 window->update_gui(client->config);
252 client->send_configure_change();
254 window->editing_lock.lock();
256 window->editing_lock.unlock();
261 void NewSvgButton::stop()
264 new_window->set_done(1);
269 EditSvgButton::EditSvgButton(SvgMain *client, SvgWin *window, int x, int y)
270 : BC_GenericButton(x, y, _("Edit")), Thread(1)
272 this->client = client;
273 this->window = window;
277 EditSvgButton::~EditSvgButton()
282 void EditSvgButton::stop()
286 struct fifo_struct fifo_buf;
287 fifo_buf.pid = getpid();
289 write(fh_fifo, &fifo_buf, sizeof(fifo_buf));
295 int EditSvgButton::handle_event()
298 window->editing_lock.lock();
299 if( !window->editing && client->config.svg_file[0] != 0 ) {
301 window->editing_lock.unlock();
306 window->editing_lock.unlock();
311 void EditSvgButton::run()
313 // ======================================= get path from user
314 char filename_png[1024];
315 char filename_fifo[1024];
316 strcpy(filename_png, client->config.svg_file);
317 strcat(filename_png, ".png");
318 remove(filename_png);
319 strcpy(filename_fifo, filename_png);
320 strcat(filename_fifo, ".fifo");
321 remove(filename_fifo);
322 if( !mkfifo(filename_fifo, S_IRWXU) &&
323 (fh_fifo = ::open(filename_fifo, O_RDWR+O_NONBLOCK)) >= 0 ) {
324 SvgInkscapeThread inkscape_thread(this);
325 inkscape_thread.start();
327 while( inkscape_thread.running() && !done ) {
329 int64_t ms_time = stat(client->config.svg_file, &st) ? 0 :
330 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
331 if( client->config.ms_time != ms_time ) {
332 client->config.ms_time = ms_time;
333 client->send_configure_change();
335 // select(fh_fifo+1,rds,0,ers,tmo) does not work here
337 struct fifo_struct fifo_buf; fifo_buf.action = 1;
338 int ret = read(fh_fifo, &fifo_buf, sizeof(fifo_buf));
340 if( errno == EAGAIN ) continue;
344 if( ret != sizeof(fifo_buf) ) continue;
345 switch( fifo_buf.action ) {
347 case 2: // printf(_("Inkscape has exited\n"));
349 case 3: // printf(_("Plugin window has closed\n"));
356 perror(_("Error opening fifo file"));
357 remove(filename_fifo); // fifo destroyed on last close
359 window->editing_lock.lock();
361 window->editing_lock.unlock();
363 client->config.ms_time = stat(client->config.svg_file, &st) ? 0 :
364 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
365 client->send_configure_change();
368 SvgInkscapeThread::SvgInkscapeThread(EditSvgButton *edit)
374 SvgInkscapeThread::~SvgInkscapeThread()
380 static int exec_command(char* const*argv)
383 if( pid < 0 ) return -1;
386 waitpid(pid, &stat, 0);
389 sprintf(msg, "%s: error exit status %d", argv[0], stat);
390 MainError::show_error(msg);
394 execvp(argv[0], &argv[0]);
398 void SvgInkscapeThread::run()
402 snprintf(command, sizeof(command),
403 "inkscape --with-gui %s", edit->client->config.svg_file);
404 printf(_("Running external SVG editor: %s\n"), command);
405 char *const argv[] = {
408 edit->client->config.svg_file,
414 printf(_("External SVG editor finished\n"));
415 struct fifo_struct fifo_buf;
416 fifo_buf.pid = getpid();
418 write(edit->fh_fifo, &fifo_buf, sizeof(fifo_buf));
425 NewSvgWindow::NewSvgWindow(SvgMain *client, SvgWin *window, char *init_directory)
427 BC_WindowBase::get_resources()->filebox_h / 2,
429 _("SVG Plugin: Pick SVG file"),
430 _("Open an existing SVG file or create a new one"))
432 this->window = window;
435 NewSvgWindow::~NewSvgWindow() {}
438 DpiValue::DpiValue(SvgWin *win, SvgMain *client, int x, int y, float *value)
439 : BC_TumbleTextBox(win, *value, 10.f, 1000.f, x, y, xS(100), 2)
441 //printf("SvgWidth::SvgWidth %f\n", client->config.w);
442 this->client = client;
447 DpiValue::~DpiValue()
451 int DpiValue::handle_event()
453 *value = atof(get_text());
458 DpiButton::DpiButton( SvgWin *window, SvgMain *client, int x, int y)
459 : BC_GenericButton(x, y, _("update dpi"))
461 this->client = client;
462 this->window = window;
465 DpiButton::~DpiButton()
469 int DpiButton::handle_event()
471 client->send_configure_change();