4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "mainerror.h"
30 #include <sys/types.h>
33 #include <sys/types.h>
38 #include "empty_svg.h"
42 // 1 = update from client, 2 = client closes, 3 = quit
46 SvgWin::SvgWin(SvgMain *client)
47 : PluginClientWindow(client, xS(420), yS(210), xS(420), yS(210), 1)
49 this->client = client;
57 void SvgWin::create_objects()
59 int xs10 = xS(10), xs15 = xS(15);
60 int ys5 = yS(5), ys10 = yS(10), ys20 = yS(20), ys15 = yS(15);
62 int x0 = xs10, y = ys10;
64 add_tool(title = new BC_Title(x0, y, _("Out X:")));
65 int x1 = x0 + title->get_w() + xs10;
66 out_x = new SvgCoord(this, client, x1, y, &client->config.out_x);
67 out_x->create_objects();
68 int x2 = x1 + out_x->get_w() + xs15;
69 add_tool(title = new BC_Title(x2, y, _("Out W:")));
70 int x3 = x2 + title->get_w() + xs10;
71 out_w = new SvgCoord(this, client, x3, y, &client->config.out_w);
72 out_w->create_objects();
73 y += out_x->get_h() + ys5;
75 add_tool(new BC_Title(x0, y, _("Out Y:")));
76 out_y = new SvgCoord(this, client, x1, y, &client->config.out_y);
77 out_y->create_objects();
78 add_tool(title = new BC_Title(x2, y, _("Out H:")));
79 out_h = new SvgCoord(this, client, x3, y, &client->config.out_h);
80 out_h->create_objects();
81 y += out_y->get_h() + ys20;
83 add_tool(title = new BC_Title(x0, y, _("DPI:")));
84 dpi = new DpiValue(this, client, x1, y, &client->config.dpi);
85 dpi->create_objects();
86 add_tool(dpi_button = new DpiButton(this, client, x2, y));
87 dpi_button->create_objects();
88 y += dpi->get_h() + ys20;
90 add_tool(svg_file_title = new BC_Title(x0, y, client->config.svg_file));
91 y += svg_file_title->get_h() + ys5;
93 int64_t ms_time = stat(client->config.svg_file, &st) ? 0 :
94 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
95 char mtime[BCSTRLEN]; mtime[0] = 0;
97 time_t tm = ms_time/1000;
100 add_tool(svg_file_mstime = new BC_Title(x0, y, mtime));
101 y += svg_file_mstime->get_h() + ys15;
103 y = get_h() - NewSvgButton::calculate_h() - ys5;
104 add_tool(new_svg_button = new NewSvgButton(client, this, x0, y));
105 y = get_h() - EditSvgButton::calculate_h() - ys5;
106 add_tool(edit_svg_button = new EditSvgButton(client, this, x0+xS(300), y));
112 int SvgWin::close_event()
114 new_svg_button->stop();
115 edit_svg_button->stop();
120 int SvgWin::hide_window(int flush)
122 new_svg_button->stop();
123 edit_svg_button->stop();
124 return BC_WindowBase::hide_window(flush);
128 void SvgWin::update_gui(SvgConfig &config)
130 lock_window("SvgWin::update_gui");
131 out_x->update(config.out_x);
132 out_y->update(config.out_y);
133 out_w->update(config.out_w);
134 out_h->update(config.out_h);
135 dpi->update(config.dpi);
136 svg_file_title->update(config.svg_file);
137 char mtime[BCSTRLEN]; mtime[0] = 0;
138 if( config.ms_time > 0 ) {
139 time_t tm = config.ms_time/1000;
142 svg_file_mstime->update(mtime);
146 SvgCoord::SvgCoord(SvgWin *win, SvgMain *client, int x, int y, float *value)
147 : BC_TumbleTextBox(win, *value, (float)0, (float)3000, x, y, xS(100))
149 //printf("SvgWidth::SvgWidth %f\n", client->config.w);
150 this->client = client;
155 SvgCoord::~SvgCoord()
159 int SvgCoord::handle_event()
161 *value = atof(get_text());
162 client->send_configure_change();
166 NewSvgButton::NewSvgButton(SvgMain *client, SvgWin *window, int x, int y)
167 : BC_GenericButton(x, y, _("New/Open SVG..."))
169 this->client = client;
170 this->window = window;
173 NewSvgButton::~NewSvgButton()
179 int NewSvgButton::handle_event()
181 window->editing_lock.lock();
182 if( !window->editing ) {
184 window->editing_lock.unlock();
189 window->editing_lock.unlock();
195 void NewSvgButton::run()
197 // ======================================= get path from user
199 //printf("NewSvgButton::run 1\n");
202 strncpy(filename, client->config.svg_file, sizeof(filename));
203 // Loop until file is chosen
205 char directory[1024];
206 strncpy(directory, client->config.svg_file, sizeof(directory));
207 char *cp = strrchr(directory, '/');
209 if( !directory[0] ) {
210 char *cp = getenv("HOME");
211 if( cp ) strncpy(directory, cp, sizeof(directory));
213 new_window = new NewSvgWindow(client, window, directory);
214 new_window->create_objects();
215 new_window->update_filter("*.svg");
216 result = new_window->run_window();
217 const char *filepath = new_window->get_path(0);
218 strcpy(filename, filepath ? filepath : "" );
219 delete new_window; new_window = 0;
220 window->editing_lock.lock();
221 if( result || !filename[0] )
223 window->editing_lock.unlock();
224 if( !window->editing ) return; // cancel or no filename given
226 // Extend the filename with .svg
227 if( strlen(filename) < 4 ||
228 strcasecmp(&filename[strlen(filename) - 4], ".svg") ) {
229 strcat(filename, ".svg");
232 if( !access(filename, R_OK) )
235 FILE *out = fopen(filename,"w");
237 unsigned long size = sizeof(empty_svg) - 4;
238 fwrite(empty_svg+4, size, 1, out);
243 } while(result); // file doesn't exist so repeat
245 strcpy(client->config.svg_file, filename);
246 client->config.ms_time = 0;
247 window->update_gui(client->config);
248 client->send_configure_change();
250 window->editing_lock.lock();
252 window->editing_lock.unlock();
257 void NewSvgButton::stop()
260 new_window->set_done(1);
265 EditSvgButton::EditSvgButton(SvgMain *client, SvgWin *window, int x, int y)
266 : BC_GenericButton(x, y, _("Edit")), Thread(1)
268 this->client = client;
269 this->window = window;
273 EditSvgButton::~EditSvgButton()
278 void EditSvgButton::stop()
282 struct fifo_struct fifo_buf;
283 fifo_buf.pid = getpid();
285 write(fh_fifo, &fifo_buf, sizeof(fifo_buf));
291 int EditSvgButton::handle_event()
294 window->editing_lock.lock();
295 if( !window->editing && client->config.svg_file[0] != 0 ) {
297 window->editing_lock.unlock();
302 window->editing_lock.unlock();
307 void EditSvgButton::run()
309 // ======================================= get path from user
310 char filename_png[1024];
311 char filename_fifo[1024];
312 strcpy(filename_png, client->config.svg_file);
313 strcat(filename_png, ".png");
314 remove(filename_png);
315 strcpy(filename_fifo, filename_png);
316 strcat(filename_fifo, ".fifo");
317 remove(filename_fifo);
318 if( !mkfifo(filename_fifo, S_IRWXU) &&
319 (fh_fifo = ::open(filename_fifo, O_RDWR+O_NONBLOCK)) >= 0 ) {
320 SvgInkscapeThread inkscape_thread(this);
321 inkscape_thread.start();
323 while( inkscape_thread.running() && !done ) {
325 int64_t ms_time = stat(client->config.svg_file, &st) ? 0 :
326 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
327 if( client->config.ms_time != ms_time ) {
328 client->config.ms_time = ms_time;
329 client->send_configure_change();
331 // select(fh_fifo+1,rds,0,ers,tmo) does not work here
333 struct fifo_struct fifo_buf; fifo_buf.action = 1;
334 int ret = read(fh_fifo, &fifo_buf, sizeof(fifo_buf));
336 if( errno == EAGAIN ) continue;
340 if( ret != sizeof(fifo_buf) ) continue;
341 switch( fifo_buf.action ) {
343 case 2: printf(_("Inkscape has exited\n"));
345 case 3: printf(_("Plugin window has closed\n"));
352 perror(_("Error opening fifo file"));
353 remove(filename_fifo); // fifo destroyed on last close
355 window->editing_lock.lock();
357 window->editing_lock.unlock();
359 client->config.ms_time = stat(client->config.svg_file, &st) ? 0 :
360 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
361 client->send_configure_change();
364 SvgInkscapeThread::SvgInkscapeThread(EditSvgButton *edit)
370 SvgInkscapeThread::~SvgInkscapeThread()
376 static int exec_command(char* const*argv)
379 if( pid < 0 ) return -1;
382 waitpid(pid, &stat, 0);
385 sprintf(msg, "%s: error exit status %d", argv[0], stat);
386 MainError::show_error(msg);
390 execvp(argv[0], &argv[0]);
394 void SvgInkscapeThread::run()
398 snprintf(command, sizeof(command),
399 "inkscape --with-gui %s", edit->client->config.svg_file);
400 printf(_("Running external SVG editor: %s\n"), command);
401 char *const argv[] = {
404 edit->client->config.svg_file,
410 printf(_("External SVG editor finished\n"));
411 struct fifo_struct fifo_buf;
412 fifo_buf.pid = getpid();
414 write(edit->fh_fifo, &fifo_buf, sizeof(fifo_buf));
421 NewSvgWindow::NewSvgWindow(SvgMain *client, SvgWin *window, char *init_directory)
423 BC_WindowBase::get_resources()->filebox_h / 2,
425 _("SVG Plugin: Pick SVG file"),
426 _("Open an existing SVG file or create a new one"))
428 this->window = window;
431 NewSvgWindow::~NewSvgWindow() {}
434 DpiValue::DpiValue(SvgWin *win, SvgMain *client, int x, int y, float *value)
435 : BC_TumbleTextBox(win, *value, (float)10, (float)1000, x, y, 100)
437 //printf("SvgWidth::SvgWidth %f\n", client->config.w);
438 this->client = client;
443 DpiValue::~DpiValue()
447 int DpiValue::handle_event()
449 *value = atof(get_text());
454 DpiButton::DpiButton( SvgWin *window, SvgMain *client, int x, int y)
455 : BC_GenericButton(x, y, _("update dpi"))
457 this->client = client;
458 this->window = window;
461 DpiButton::~DpiButton()
465 int DpiButton::handle_event()
467 client->send_configure_change();