[xiph-commits] r14007 - trunk/sushivision
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Wed Oct 17 17:58:25 PDT 2007
Author: xiphmont
Date: 2007-10-17 17:58:24 -0700 (Wed, 17 Oct 2007)
New Revision: 14007
Added:
trunk/sushivision/toplevel.c
Removed:
trunk/sushivision/main.c
Modified:
trunk/sushivision/Makefile
trunk/sushivision/dimension.c
trunk/sushivision/objective.c
trunk/sushivision/panel.c
trunk/sushivision/sushi-gtkrc.in
trunk/sushivision/sushivision.h
trunk/sushivision/undo.c
Log:
Moving work to another machine
Modified: trunk/sushivision/Makefile
===================================================================
--- trunk/sushivision/Makefile 2007-10-17 23:49:14 UTC (rev 14006)
+++ trunk/sushivision/Makefile 2007-10-18 00:58:24 UTC (rev 14007)
@@ -24,14 +24,14 @@
SOCFLAGS = -fPIC
SOLDFLAGS = -shared -nostdlib -Wl,-soname="lib$(NAME).so.$(MAJOR)"
-SRC = main.c mapping.c scale.c plot.c slider.c slice.c spinner.c objective.c panel.c \
+SRC = toplevel.c mapping.c scale.c plot.c slider.c slice.c spinner.c objective.c panel.c \
plane-2d.c dimension.c function.c undo.c gtksucks.c xml.c \
tokens.c example_fractal.c example_discrete.c example_chirp.c example_spirograph.c
INC = sushivision.h sushimacro.h
MAN =
EXAMPLES = sushivision_fractal #sushivision_discrete sushivision_chirp
EX_OBJ = example_fractal.o #example_discrete.o example_chirp.o example_spirograph.o
-OBJ = main.o mapping.o scale.o plot.o slider.o slice.o spinner.c objective.o panel.o \
+OBJ = toplevel.o mapping.o scale.o plot.o slider.o slice.o spinner.c objective.o panel.o \
plane-2d.o dimension.o function.o undo.o gtksucks.o xml.o tokens.c
LIBS = -lpthread -ldl
CAIROVER = >= 1.4.1
Modified: trunk/sushivision/dimension.c
===================================================================
--- trunk/sushivision/dimension.c 2007-10-17 23:49:14 UTC (rev 14006)
+++ trunk/sushivision/dimension.c 2007-10-18 00:58:24 UTC (rev 14007)
@@ -26,6 +26,10 @@
#include <math.h>
#include "internal.h"
+int _sv_dimensions=0;
+sv_dim_t **_sv_dimension_list=NULL;
+pthread_key_t _sv_dim_key;
+
void _sv_dim_data_copy(sv_dim_data_t *dd,sv_dim_data_t *copy){
Deleted: trunk/sushivision/main.c
===================================================================
--- trunk/sushivision/main.c 2007-10-17 23:49:14 UTC (rev 14006)
+++ trunk/sushivision/main.c 2007-10-18 00:58:24 UTC (rev 14007)
@@ -1,469 +0,0 @@
-/*
- *
- * sushivision copyright (C) 2006-2007 Monty <monty at xiph.org>
- *
- * sushivision is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * sushivision is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with sushivision; see the file COPYING. If not, write to the
- * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- */
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <math.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <gtk/gtk.h>
-#include <cairo-ft.h>
-#include <pthread.h>
-#include <dlfcn.h>
-#include "internal.h"
-#include "sushi-gtkrc.h"
-
-// All API and GTK/GDK access is locked by a single recursive mutex
-// installed into GDK.
-
-// Worker threads exist to handle high latency tasks asynchronously.
-// The worker threads (with one exception) never touch the main GDK
-// mutex; any data protected by the main mutex needed for a worker
-// task is pulled out and encapsulated when that task is set up from a
-// GTK or API call. The one exception to worker threads and the GDK
-// lock is expose requests after rendering; in this case, the worker
-// waits until it can drop all locks, does so, and then issues an
-// expose request locked by GDK.
-
-// All data object memory strutures that are used by the worker
-// threads and can be manipulated by API/GTK/GDK and the worker
-// threads re locked by r/w locks; any thread 'inside' the abstraction
-// read-locks the memory while it is in use. GDK/API access
-// write-locks this memory to manipulate it (allocation, deallocation,
-// structural mutation).
-
-// lock acquisition order must move to the right:
-// GDK -> panel_list -> panel locks -> plot_main -> plot_data
-
-// mutex condm is only for protecting the worker condvar
-static pthread_mutex_t worker_condm = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t worker_cond = PTHREAD_COND_INITIALIZER;
-sig_atomic_t _sv_exiting=0;
-static int wake_pending = 0;
-static int num_threads;
-
-int _sv_dimensions=0;
-sv_dim_t **_sv_dimension_list=NULL;
-int _sv_panels=0;
-sv_panel_t **_sv_panel_list=NULL;
-int _sv_undo_level=0;
-int _sv_undo_suspended=0;
-_sv_undo_t **_sv_undo_stack=NULL;
-
-pthread_key_t _sv_dim_key;
-pthread_key_t _sv_obj_key;
-
-void _sv_wake_workers(){
- pthread_mutex_lock(&worker_condm);
- wake_pending = num_threads;
- pthread_cond_broadcast(&worker_cond);
- pthread_mutex_unlock(&worker_condm);
-}
-
-void _sv_clean_exit(){
- _sv_exiting = 1;
- _sv_wake_workers();
-
- _gdk_lock();
- if(!gtk_main_iteration_do(FALSE)) // side effect: returns true if
- // there are no main loops active
- gtk_main_quit();
-
- _gdk_unlock();
-}
-
-static int num_proccies(){
- FILE *f = fopen("/proc/cpuinfo","r");
- char * line = NULL;
- size_t len = 0;
- ssize_t read;
- int num=1,arg;
-
- if (f == NULL) return 1;
- while ((read = getline(&line, &len, f)) != -1) {
- if(sscanf(line,"processor : %d",&arg)==1)
- if(arg+1>num)num=arg+1;
- }
- if (line)
- free(line);
-
- fprintf(stderr,"Number of processors: %d\n",num);
- fclose(f);
- return num;
-}
-
-/// XXXXXX call wake_workers after any panel_call that returns STATUS_WORKING
-static void *worker_thread(void *dummy){
- /* set up temporary working space for function rendering; this saves
- continuously recreating it in the loop below */
- _sv_bythread_cache_t *c=calloc(_sv_panels,sizeof(*c));
- int i;
-
- while(1){
- if(_sv_exiting)break;
-
- // look for work
- {
- int flag=0;
- for(i=0;i<_sv_panels;i++){
- sv_panel_t *p = _sv_panel_list[i];
-
- if(_sv_exiting)break;
-
- // pending remap work?
- gdk_lock();
- if(p && p->private && p->private->realized && p->private->graph){
-
- // pending computation work?
- if(p->private->plot_active){
- _sv_spinner_set_busy(p->private->spinner);
-
- if(p->private->plot_progress_count==0){
- if(p->private->callback_precompute)
- p->private->callback_precompute(p,p->private->callback_precompute_data);
- }
-
- flag |= p->private->compute_action(p,&c[i]); // may drop lock internally
- }
-
- if(p->private->map_active){
- int ret = 1;
- while(ret){ // favor completing remaps over other ops
- _sv_spinner_set_busy(p->private->spinner);
- flag |= ret = p->private->map_action(p,&c[i]); // may drop lock internally
- if(!p->private->map_active)
- _sv_map_set_throttle_time(p);
- }
- }
-
- // pending legend work?
- if(p->private->legend_active){
- _sv_spinner_set_busy(p->private->spinner);
- flag |= p->private->legend_action(p); // may drop lock internally
- }
-
- if(!p->private->plot_active &&
- !p->private->legend_active &&
- !p->private->map_active)
- _sv_spinner_set_idle(p->private->spinner);
- }
- gdk_unlock ();
- }
- if(flag==1)continue;
- }
-
- // nothing to do, wait
- pthread_mutex_lock(&worker_condm);
- while(!wake_pending)
- pthread_cond_wait(&worker_cond,&worker_condm);
-
- wake_pending--;
- pthread_mutex_unlock(&worker_condm);
- }
-
- pthread_mutex_unlock(&worker_condm);
- return 0;
-}
-
-static char * gtkrc_string(){
- return _SUSHI_GTKRC_STRING;
-}
-
-static void _sv_realize_all(void){
- int i;
- for(i=0;i<_sv_panels;i++)
- _sv_panel_realize(_sv_panel_list[i]);
- for(i=0;i<_sv_panels;i++)
- if(_sv_panel_list[i])
- _sv_panel_list[i]->private->request_compute(_sv_panel_list[i]);
-}
-
-char *_sv_appname = NULL;
-char *_sv_filename = NULL;
-char *_sv_filebase = NULL;
-char *_sv_dirname = NULL;
-char *_sv_cwdname = NULL;
-
-static void *event_thread(void *dummy){
-
- gdk_lock();
- gtk_main ();
- gdk_unlock();
-
-// in case there's another mainloop in the main app
- gdk_lock();
- if(!gtk_main_iteration_do(FALSE)) // side effect: returns true if
- // there are no main loops active
- gtk_main_quit();
- gdk_unlock();
-
- return 0;
-}
-
-/* externally visible interface */
-int sv_init(){
- int ret=0;
- if((ret=pthread_key_create(&_sv_mutexcheck_key,NULL)))
- return ret;
- if((ret=pthread_key_create(&_sv_dim_key,NULL)))
- return ret;
- if((ret=pthread_key_create(&_sv_obj_key,NULL)))
- return ret;
-
- num_threads = ((num_proccies()*3)>>2);
-
- _gtk_mutex_fixup();
- gtk_init (NULL,NULL);
-
- return 0;
-}
-
-int sv_join(){
- while(!_sv_exiting){
- pthread_mutex_lock(&worker_condm);
- pthread_cond_wait(&worker_cond,&worker_condm);
- pthread_mutex_unlock(&worker_condm);
- }
- return 0;
-}
-
-int sv_go(){
-
- if (!g_thread_supported ()) g_thread_init (NULL);
- gdk_threads_init ();
- gtk_rc_parse_string(gtkrc_string());
- gtk_rc_add_default_file("sushi-gtkrc");
-
- gdk_lock();
- _sv_realize_all();
- _gtk_button3_fixup();
-
- _sv_appname = g_get_prgname ();
- _sv_cwdname = getcwd(NULL,0);
- _sv_dirname = strdup(_sv_cwdname);
- /*if(argc>1){
- // file to load specified on commandline
- if(argv[argc-1][0] != '-'){
- _sv_filebase = strdup(argv[argc-1]);
- char *base = strrchr(_sv_filebase,'/');
-
- // filebase may include a path; pull it off and apply it toward dirname
- if(base){
- base[0] = '\0';
- char *dirbit = strdup(_sv_filebase);
- _sv_filebase = base+1;
- if(g_path_is_absolute(dirbit)){
- // replace dirname
- free(_sv_dirname);
- _sv_dirname = dirbit;
- }else{
- // append to dirname
- char *buf;
- asprintf(&buf,"%s/%s",_sv_dirname,dirbit);
- free(_sv_dirname);
- _sv_dirname = buf;
- }
- }
- asprintf(&_sv_filename,"%s/%s",_sv_dirname,_sv_filebase);
- }
- }
-
- if(!_sv_filename || _sv_main_load()){
- if(_sv_appname){
- char *base = strrchr(_sv_appname,'/');
- if(!base)
- base = _sv_appname;
- else
- base++;
-
- asprintf(&_sv_filebase, "%s.sushi",base);
- }else
- _sv_filebase = strdup("default.sushi");
- asprintf(&_sv_filename,"%s/%s",_sv_dirname,_sv_filebase);
- }*/
-
- {
- pthread_t dummy;
- int threads = num_threads;
- while(threads--)
- pthread_create(&dummy, NULL, &worker_thread,NULL);
- }
-
- //signal(SIGINT,_sv_clean_exit);
- //signal(SIGSEGV,_sv_clean_exit);
-
- gdk_unlock();
-
- {
- pthread_t dummy;
- return pthread_create(&dummy, NULL, &event_thread,NULL);
- }
-}
-
-void _sv_first_load_warning(int *warn){
- if(!*warn)
- fprintf(stderr,"\nWARNING: The data file to be opened is not a perfect match to\n"
- "%s.\n\nThis may be because the file is for a different version of\n"
- "the executable, or because it is is not a save file for \n%s at all.\n\n"
- "Specific warnings follow:\n\n",_sv_appname,_sv_appname);
- *warn = 1;
-}
-
-int _sv_main_save(){
- xmlDocPtr doc = NULL;
- xmlNodePtr root_node = NULL;
- int i, ret=0;
-
- LIBXML_TEST_VERSION;
-
- doc = xmlNewDoc((xmlChar *)"1.0");
- root_node = xmlNewNode(NULL, (xmlChar *)_sv_appname);
- xmlDocSetRootElement(doc, root_node);
-
- // dimension values are independent of panel
- for(i=0;i<_sv_dimensions;i++)
- ret|=_sv_dim_save(_sv_dimension_list[i], root_node);
-
- // objectives have no independent settings
-
- // panel settings (by panel)
- for(i=0;i<_sv_panels;i++)
- ret|=_sv_panel_save(_sv_panel_list[i], root_node);
-
- xmlSaveFormatFileEnc(_sv_filename, doc, "UTF-8", 1);
-
- xmlFreeDoc(doc);
- xmlCleanupParser();
-
- return ret;
-}
-
-int _sv_main_load(){
- xmlDoc *doc = NULL;
- xmlNode *root = NULL;
- int fd,warn=0;
- int i;
-
- LIBXML_TEST_VERSION;
-
- fd = open(_sv_filename, O_RDONLY);
- if(fd<0){
- GtkWidget *dialog = gtk_message_dialog_new (NULL,0,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- "Error opening file '%s': %s",
- _sv_filename, strerror (errno));
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
- return 1;
- }
-
- doc = xmlReadFd(fd, NULL, NULL, 0);
- close(fd);
-
- if (doc == NULL) {
- GtkWidget *dialog = gtk_message_dialog_new (NULL,0,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- "Error parsing file '%s'",
- _sv_filename);
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
- return 1;
- }
-
- root = xmlDocGetRootElement(doc);
-
- // piggyback off undo (as it already goes through the trouble of
- // doing correct unrolling, which can be tricky)
-
- // if this instance has an undo stack, pop it all, then log current state into it
- _sv_undo_level=0;
- _sv_undo_log();
-
- _sv_undo_t *u = _sv_undo_stack[_sv_undo_level];
-
- // load dimensions
- for(i=0;i<_sv_dimensions;i++){
- sv_dim_t *d = _sv_dimension_list[i];
- if(d){
- xmlNodePtr dn = _xmlGetChildI(root,"dimension","number",d->number);
- if(!dn){
- _sv_first_load_warning(&warn);
- fprintf(stderr,"Could not find data for dimension \"%s\" in save file.\n",
- d->name);
- }else{
- warn |= _sv_dim_load(d,u,dn,warn);
- xmlFreeNode(dn);
- }
- }
- }
-
- // load panels
- for(i=0;i<_sv_panels;i++){
- sv_panel_t *p = _sv_panel_list[i];
- if(p){
- xmlNodePtr pn = _xmlGetChildI(root,"panel","number",p->number);
- if(!pn){
- _sv_first_load_warning(&warn);
- fprintf(stderr,"Could not find data for panel \"%s\" in save file.\n",
- p->name);
- }else{
- warn |= _sv_panel_load(p,u->panels+i,pn,warn);
- xmlFreeNode(pn);
- }
- }
- }
-
- // if any elements are unclaimed, warn
- xmlNodePtr node = root->xmlChildrenNode;
- while(node){
- if (node->type == XML_ELEMENT_NODE) {
- xmlChar *name = xmlGetProp(node, (xmlChar *)"name");
- _sv_first_load_warning(&warn);
- if(name){
- fprintf(stderr,"Save file contains data for nonexistant object \"%s\".\n",
- name);
- xmlFree(name);
- }else
- fprintf(stderr,"Save file root node contains an extra unknown elements.\n");
- }
- node = node->next;
- }
-
- // effect the loaded values
- _sv_undo_suspend();
- _sv_undo_restore();
- _sv_undo_resume();
-
- xmlFreeDoc(doc);
- xmlCleanupParser();
-
- return 0;
-}
Modified: trunk/sushivision/objective.c
===================================================================
--- trunk/sushivision/objective.c 2007-10-17 23:49:14 UTC (rev 14006)
+++ trunk/sushivision/objective.c 2007-10-18 00:58:24 UTC (rev 14007)
@@ -27,6 +27,7 @@
int _sv_objectives=0;
sv_obj_t **_sv_objective_list=NULL;
+pthread_key_t _sv_obj_key;
static char *objective_axismap[]={
"X","Y","Z"
Modified: trunk/sushivision/panel.c
===================================================================
--- trunk/sushivision/panel.c 2007-10-17 23:49:14 UTC (rev 14006)
+++ trunk/sushivision/panel.c 2007-10-18 00:58:24 UTC (rev 14007)
@@ -33,6 +33,9 @@
#include <cairo-ft.h>
#include "internal.h"
+int _sv_panels=0;
+sv_panel_t **_sv_panel_list=NULL;
+pthread_rwlock_t panellist_m;
// panel.panel_m: rwlock, protects all panel and plane heaps
// panel.status_m: mutex, protects status variables
Modified: trunk/sushivision/sushi-gtkrc.in
===================================================================
--- trunk/sushivision/sushi-gtkrc.in 2007-10-17 23:49:14 UTC (rev 14006)
+++ trunk/sushivision/sushi-gtkrc.in 2007-10-18 00:58:24 UTC (rev 14007)
@@ -114,13 +114,14 @@
font_name = "sans"
}
-widget "*" style "panel"
-widget "*.GtkScrolledWindow*" style "scale-poppy"
-widget "*.GtkLabel" style "panel-text"
-widget "*.GtkMenu*" style "button-poppy"
-widget "*.GtkComboBox*" style "button-poppy"
-widget "*.GtkToggleButton*" style "button-poppy"
-widget "*.GtkButton*" style "button-poppy"
-widget "*.GtkExpander" style "exp-poppy"
-widget "*.GtkEntry" style "entry-poppy"
-widget "*.Slider" style "slider-poppy"
+widget "sushivision" style "panel"
+widget "sushivision.*" style "panel"
+widget "sushivision.*.GtkScrolledWindow*" style "scale-poppy"
+widget "sushivision.*.GtkLabel" style "panel-text"
+widget "sushivision.*.GtkMenu*" style "button-poppy"
+widget "sushivision.*.GtkComboBox*" style "button-poppy"
+widget "sushivision.*.GtkToggleButton*" style "button-poppy"
+widget "sushivision.*.GtkButton*" style "button-poppy"
+widget "sushivision.*.GtkExpander" style "exp-poppy"
+widget "sushivision.*.GtkEntry" style "entry-poppy"
+widget "sushivision.*.Slider" style "slider-poppy"
Modified: trunk/sushivision/sushivision.h
===================================================================
--- trunk/sushivision/sushivision.h 2007-10-17 23:49:14 UTC (rev 14006)
+++ trunk/sushivision/sushivision.h 2007-10-18 00:58:24 UTC (rev 14007)
@@ -29,8 +29,11 @@
/* toplevel ******************************************************/
extern int sv_init(void);
-extern int sv_go(void);
+extern int sv_exit(void);
+extern int sv_wake(void);
extern int sv_join(void);
+extern int sv_suspend(int);
+extern int sv_unsuspend(void);
extern int sv_save(char *filename);
extern int sv_load(char *filename);
Added: trunk/sushivision/toplevel.c
===================================================================
--- trunk/sushivision/toplevel.c (rev 0)
+++ trunk/sushivision/toplevel.c 2007-10-18 00:58:24 UTC (rev 14007)
@@ -0,0 +1,417 @@
+/*
+ *
+ * sushivision copyright (C) 2006-2007 Monty <monty at xiph.org>
+ *
+ * sushivision is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * sushivision is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with sushivision; see the file COPYING. If not, write to the
+ * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <gtk/gtk.h>
+#include <cairo-ft.h>
+#include <pthread.h>
+#include <dlfcn.h>
+#include "internal.h"
+#include "sushi-gtkrc.h"
+
+// All API and GTK/GDK access is locked by a single recursive mutex
+// installed into GDK.
+
+// Worker threads exist to handle high latency tasks asynchronously.
+// The worker threads (with one exception) never touch the main GDK
+// mutex; any data protected by the main mutex needed for a worker
+// task is pulled out and encapsulated when that task is set up from a
+// GTK or API call. The one exception to worker threads and the GDK
+// lock is expose requests after rendering; in this case, the worker
+// waits until it can drop all locks, does so, and then issues an
+// expose request locked by GDK.
+
+// All data object memory strutures that are used by the worker
+// threads and can be manipulated by API/GTK/GDK and the worker
+// threads re locked by r/w locks; any thread 'inside' the abstraction
+// read-locks the memory while it is in use. GDK/API access
+// write-locks this memory to manipulate it (allocation, deallocation,
+// structural mutation).
+
+// lock acquisition order must move to the right:
+// GDK -> panel_m -> status_m -> plot_m
+
+// mutex condm is only for protecting the worker condvar
+static pthread_mutex_t worker_condm = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t worker_cond = PTHREAD_COND_INITIALIZER;
+static sig_atomic_t sv_exiting=0;
+static int wake_pending = 0;
+static int num_threads;
+
+static int num_proccies(){
+ FILE *f = fopen("/proc/cpuinfo","r");
+ char * line = NULL;
+ size_t len = 0;
+ ssize_t read;
+ int num=1,arg;
+
+ if (f == NULL) return 1;
+ while ((read = getline(&line, &len, f)) != -1) {
+ if(sscanf(line,"processor : %d",&arg)==1)
+ if(arg+1>num)num=arg+1;
+ }
+ if (line)
+ free(line);
+
+ fprintf(stderr,"Number of processors: %d\n",num);
+ fclose(f);
+ return num;
+}
+
+static void *worker_thread(void *dummy){
+ while(1){
+ int i,flag=0;
+ if(sv_exiting)break;
+
+ pthread_rwlock_rdlock(panellist_m);
+ for(i=0;i<_sv_panels;i++){
+ sv_panel_t *p = _sv_panel_list[i];
+
+ if(sv_exiting)break;
+
+ if(p){
+ int ret = _sv_panel_work(p);
+ if(ret == STATUS_WORKING){
+ flag = 1;
+ sv_wake(); // result of this completion might have
+ // generated more work
+ }
+ }
+ }
+ if(flag==1)continue;
+
+ // nothing to do, wait
+ pthread_mutex_lock(&worker_condm);
+ while(!wake_pending)
+ pthread_cond_wait(&worker_cond,&worker_condm);
+
+ wake_pending--;
+ pthread_mutex_unlock(&worker_condm);
+ }
+
+ pthread_mutex_unlock(&worker_condm);
+ return 0;
+}
+
+static char *gtkrc_string(){
+ return _SUSHI_GTKRC_STRING;
+}
+
+static void _sv_realize_all(void){
+ int i;
+ for(i=0;i<_sv_panels;i++)
+ _sv_panel_realize(_sv_panel_list[i]);
+ for(i=0;i<_sv_panels;i++)
+ if(_sv_panel_list[i])
+ _sv_panel_list[i]->private->request_compute(_sv_panel_list[i]);
+}
+
+char *_sv_appname = NULL;
+char *_sv_filename = NULL;
+char *_sv_filebase = NULL;
+char *_sv_dirname = NULL;
+char *_sv_cwdname = NULL;
+
+static void *eventloop(void *dummy){
+
+ gdk_lock();
+ gtk_main ();
+ gdk_unlock();
+
+ // in case there's another mainloop in the main app
+ gdk_lock();
+ if(!gtk_main_iteration_do(FALSE)) // side effect: returns true if
+ // there are no main loops active
+ gtk_main_quit();
+ gdk_unlock();
+
+ return 0;
+}
+
+/* externally visible interface */
+int sv_init(void){
+ int ret=0;
+ if((ret=pthread_key_create(&_sv_dim_key,NULL)))
+ return ret;
+ if((ret=pthread_key_create(&_sv_obj_key,NULL)))
+ return ret;
+ if((ret=pthread_key_create(&_sv_panel_key,NULL)))
+ return ret;
+
+ num_threads = ((num_proccies()*3)>>2);
+
+ _gtk_mutex_fixup();
+ gtk_init (NULL,NULL);
+
+ _sv_appname = g_get_prgname ();
+ _sv_cwdname = getcwd(NULL,0);
+ _sv_dirname = strdup(_sv_cwdname);
+
+ if(_sv_appname){
+ char *base = strrchr(_sv_appname,'/');
+ if(!base)
+ base = _sv_appname;
+ else
+ base++;
+
+ asprintf(&_sv_filebase, "%s.sushi",base);
+ }else
+ _sv_filebase = strdup("unnamed.sushi");
+ asprintf(&_sv_filename,"%s/%s",_sv_dirname,_sv_filebase);
+
+ if (!g_thread_supported ()) g_thread_init (NULL);
+ gdk_threads_init ();
+
+ gtk_rc_parse_string(gtkrc_string());
+ gtk_rc_add_default_file("sushi-gtkrc");
+
+ _gtk_button3_fixup();
+
+ // worker threads
+ {
+ pthread_t dummy;
+ int threads = num_threads;
+ while(threads--)
+ pthread_create(&dummy, NULL, &worker_thread,NULL);
+ }
+
+ // event thread for panels in the event the app we're injected into
+ // has no gtk main loop
+ {
+ pthread_t dummy;
+ return pthread_create(&dummy, NULL, &event_thread,NULL);
+ }
+
+ return 0;
+}
+
+int sv_join(void){
+ while(!sv_exiting){
+ pthread_mutex_lock(&worker_condm);
+ pthread_cond_wait(&worker_cond,&worker_condm);
+ pthread_mutex_unlock(&worker_condm);
+ }
+ return 0;
+}
+
+int sv_wake(void){
+ pthread_mutex_lock(&worker_condm);
+ wake_pending = num_threads;
+ pthread_cond_broadcast(&worker_cond);
+ pthread_mutex_unlock(&worker_condm);
+ return 0;
+}
+
+int sv_exit(void){
+ sv_exiting = 1;
+ sv_wake();
+
+ gdk_threads_enter();
+ if(!gtk_main_iteration_do(FALSE)) // side effect: returns true if
+ // there are no main loops active
+ gtk_main_quit();
+
+ gdk_threads_leave();
+ return 0;
+}
+
+void _sv_first_load_warning(int *warn){
+ if(!*warn)
+ fprintf(stderr,"\nWARNING: The data file to be opened is not a perfect match to\n"
+ "%s.\n\nThis may be because the file is for a different version of\n"
+ "the executable, or because it is is not a save file for \n%s at all.\n\n"
+ "Specific warnings follow:\n\n",_sv_appname,_sv_appname);
+ *warn = 1;
+}
+
+static void set_internal_filename(char *filename){
+ // save the filename for internal menu seeding purposes
+ char *base = strrchr(filename,'/');
+
+ // filename may include a path; pull it off and apply it toward dirname
+ if(base){
+ base[0] = '\0';
+ char *dirbit = strdup(_sv_filebase);
+ _sv_filebase = base+1;
+ if(g_path_is_absolute(dirbit)){
+ // replace dirname
+ free(_sv_dirname);
+ _sv_dirname = dirbit;
+ }else{
+ // append to dirname
+ char *buf;
+ asprintf(&buf,"%s/%s",_sv_dirname,dirbit);
+ free(_sv_dirname);
+ _sv_dirname = buf;
+ }
+ }
+ asprintf(&_sv_filename,"%s/%s",_sv_dirname,_sv_filebase);
+}
+
+int sv_save(char *filename){
+ xmlDocPtr doc = NULL;
+ xmlNodePtr root_node = NULL;
+ int i, ret=0;
+
+ LIBXML_TEST_VERSION;
+
+ doc = xmlNewDoc((xmlChar *)"1.0");
+ root_node = xmlNewNode(NULL, (xmlChar *)_sv_appname);
+ xmlDocSetRootElement(doc, root_node);
+
+ // dimension values are independent of panel
+ for(i=0;i<_sv_dimensions;i++)
+ ret|=_sv_dim_save(_sv_dimension_list[i], root_node);
+
+ // objectives have no independent settings
+
+ // panel settings (by panel)
+ for(i=0;i<_sv_panels;i++)
+ ret|=_sv_panel_save(_sv_panel_list[i], root_node);
+
+ ret|=xmlSaveFormatFileEnc(filename, doc, "UTF-8", 1);
+
+ if(ret==0) set_internal_filename(filename);
+
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+
+ return ret;
+}
+
+int sv_load(filename){
+ xmlDoc *doc = NULL;
+ xmlNode *root = NULL;
+ int fd,warn=0;
+ int i;
+
+ LIBXML_TEST_VERSION;
+
+ fd = open(_sv_filename, O_RDONLY);
+ if(fd<0){
+ GtkWidget *dialog = gtk_message_dialog_new (NULL,0,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Error opening file '%s': %s",
+ _sv_filename, strerror (errno));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ return 1;
+ }
+
+ doc = xmlReadFd(fd, NULL, NULL, 0);
+ close(fd);
+
+ if (doc == NULL) {
+ GtkWidget *dialog = gtk_message_dialog_new (NULL,0,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Error parsing file '%s'",
+ _sv_filename);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ errno = -EINVAL;
+ return 1;
+ }
+
+ root = xmlDocGetRootElement(doc);
+
+ // piggyback off undo (as it already goes through the trouble of
+ // doing correct unrolling, which can be tricky)
+
+ // if this instance has an undo stack, pop it all, then log current state into it
+ _sv_undo_level=0;
+ _sv_undo_log();
+
+ _sv_undo_t *u = _sv_undo_stack[_sv_undo_level];
+
+ // load dimensions
+ for(i=0;i<_sv_dimensions;i++){
+ sv_dim_t *d = _sv_dimension_list[i];
+ if(d){
+ xmlNodePtr dn = _xmlGetChildI(root,"dimension","number",d->number);
+ if(!dn){
+ _sv_first_load_warning(&warn);
+ fprintf(stderr,"Could not find data for dimension \"%s\" in save file.\n",
+ d->name);
+ }else{
+ warn |= _sv_dim_load(d,u,dn,warn);
+ xmlFreeNode(dn);
+ }
+ }
+ }
+
+ // load panels
+ for(i=0;i<_sv_panels;i++){
+ sv_panel_t *p = _sv_panel_list[i];
+ if(p){
+ xmlNodePtr pn = _xmlGetChildI(root,"panel","number",p->number);
+ if(!pn){
+ _sv_first_load_warning(&warn);
+ fprintf(stderr,"Could not find data for panel \"%s\" in save file.\n",
+ p->name);
+ }else{
+ warn |= _sv_panel_load(p,u->panels+i,pn,warn);
+ xmlFreeNode(pn);
+ }
+ }
+ }
+
+ // if any elements are unclaimed, warn
+ xmlNodePtr node = root->xmlChildrenNode;
+ while(node){
+ if (node->type == XML_ELEMENT_NODE) {
+ xmlChar *name = xmlGetProp(node, (xmlChar *)"name");
+ _sv_first_load_warning(&warn);
+ if(name){
+ fprintf(stderr,"Save file contains data for nonexistant object \"%s\".\n",
+ name);
+ xmlFree(name);
+ }else
+ fprintf(stderr,"Save file root node contains an extra unknown elements.\n");
+ }
+ node = node->next;
+ }
+
+ // effect the loaded values
+ _sv_undo_suspend();
+ _sv_undo_restore();
+ _sv_undo_resume();
+
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+
+ if(ret==0) set_internal_filename(filename);
+
+ return 0;
+}
Modified: trunk/sushivision/undo.c
===================================================================
--- trunk/sushivision/undo.c 2007-10-17 23:49:14 UTC (rev 14006)
+++ trunk/sushivision/undo.c 2007-10-18 00:58:24 UTC (rev 14007)
@@ -26,6 +26,10 @@
#include <errno.h>
#include "internal.h"
+int _sv_undo_level=0;
+int _sv_undo_suspended=0;
+sv_undo_t **_sv_undo_stack=NULL;
+
/* encapsulates some amount of common undo/redo infrastructure */
static void update_all_menus(){
More information about the commits
mailing list