mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
patches from rob browning
1999-08-25 Rob Browning <rlb@cs.utexas.edu> * Add this file (./ChangeLog). I'm planning to add change information here, and I invite others to do the same. For those that use emacs, 'C-x 4 a' adds a new entry. If people don't like this idea, we can drop it. * Add new scheme function gnc:choose-item-from-list-dialog. There is C side code, but it's only meant to be called from scheme. This function is quite flexible in handles selections. Eventually we might want to generalize this even more, but there are some GC issues to consider. See src/gnome/query-user.c and gnc.gwp for details, and see src/scm/extensions.scm for an example usage. * IMPORTANT: queryBox signature has changed. See the docs in src/gnome/query-user.c and in gnc.gwp for details. * Remove queryBox stubs from Motif side. Motif doesn't support it (yet), and with gnc.gwp conditional inclusion we can just ignore it on the motif side. * Add function (current-gnc-compile-flavor) to gnc.gwp so that we can have conditional blocks. Possible return values are 'gnome and 'motif. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@1930 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
fa0eed02ef
commit
c60fa5190a
28
ChangeLog
Normal file
28
ChangeLog
Normal file
@ -0,0 +1,28 @@
|
||||
1999-08-25 Rob Browning <rlb@cs.utexas.edu>
|
||||
|
||||
* Add ./README.gnome-hackers.
|
||||
|
||||
* Add ./README.guile-hackers.
|
||||
|
||||
* Add this file (./ChangeLog). I'm planning to add change
|
||||
information here, and I invite others to do the same. For those
|
||||
that use emacs, 'C-x 4 a' adds a new entry. If people don't like
|
||||
this idea, we can drop it.
|
||||
|
||||
* Add new scheme function gnc:choose-item-from-list-dialog. There
|
||||
is C side code, but it's only meant to be called from scheme.
|
||||
This function is quite flexible in handles selections. Eventually
|
||||
we might want to generalize this even more, but there are some GC
|
||||
issues to consider. See src/gnome/query-user.c and gnc.gwp for
|
||||
details, and see src/scm/extensions.scm for an example usage.
|
||||
|
||||
* IMPORTANT: queryBox signature has changed. See the docs in
|
||||
src/gnome/query-user.c and in gnc.gwp for details.
|
||||
|
||||
* Remove queryBox stubs from Motif side. Motif doesn't support it
|
||||
(yet), and with gnc.gwp conditional inclusion we can just ignore
|
||||
it on the motif side.
|
||||
|
||||
* Add function (current-gnc-compile-flavor) to gnc.gwp so that we
|
||||
can have conditional blocks. Possible return values are 'gnome
|
||||
and 'motif.
|
34
README.gnome-hackers
Normal file
34
README.gnome-hackers
Normal file
@ -0,0 +1,34 @@
|
||||
-*-text-*-
|
||||
|
||||
This file is intended to contain information for those interested in
|
||||
working on the GNOME bits of GnuCash.
|
||||
|
||||
Memory Management (care with reference counting):
|
||||
-------------------------------------------------
|
||||
|
||||
I was unsure about when you're supposed to _unref widgets, etc., and
|
||||
getting this right is critical to avoiding memory leaks on the one
|
||||
hand and dangling pointers on the other. So I asked on the gtk list,
|
||||
and here was the result:
|
||||
|
||||
On 16 Aug 1999, Rob Browning wrote:
|
||||
>
|
||||
> I've been poking around the gtk web site and in the docs for
|
||||
> information on when you're supposed to call gtk_widget_unref. I want
|
||||
> to make sure I'm handling this right so I don't introduce memory
|
||||
> leaks, but so far I haven't found anything describing the rules.
|
||||
> Actually I'd like to know what the guidelines are for all the *_unref
|
||||
> functions...
|
||||
>
|
||||
|
||||
Read gtk+/docs/refcounting.txt (or something like that).
|
||||
|
||||
Also I think some babble about object finalization at
|
||||
http://pobox.com/~hp/gnome-app-devel.html (follow link to sample
|
||||
chapters) might be helpful.
|
||||
|
||||
Basically you have to unref a widget you never use, but if you put it
|
||||
in a container the container "assumes" the initial refcount of 1 and
|
||||
the widget will be deleted along with the container.
|
||||
|
||||
Havoc
|
69
README.guile-hackers
Normal file
69
README.guile-hackers
Normal file
@ -0,0 +1,69 @@
|
||||
-*-text-*-
|
||||
|
||||
This file is intended to contain information for those interested in
|
||||
working on the guile bits of GnuCash.
|
||||
|
||||
I've recently added some GUI functions callable from scheme. This is
|
||||
generally pretty straightforward, and you can look in the code to see
|
||||
how I did it, but there are a few bits you have to be careful about.
|
||||
|
||||
One of the main sources of useful information is "info guile-ref".
|
||||
This contains the documentation for all the guile C-side functions
|
||||
like gh_car(), gh_append(), etc. that manipulate opaque SCM objects
|
||||
from the guile side.
|
||||
|
||||
Given that and a reasonable understanding of GTK/GNOME, you should be
|
||||
able to follow what I've done.
|
||||
|
||||
Garbage collection:
|
||||
-------------------
|
||||
|
||||
One issue to keep in mind is that of garbage collection. You cannot
|
||||
pass a scheme side item to the C side (through a SCM) and then store
|
||||
that object off somewhere on the C side such that it lives longer than
|
||||
all of it's guile side references. If you do, you're likely to get a
|
||||
crash. The problem is that guile's garbage collector only knows to
|
||||
save guile items that still have guile side pointers, or that are
|
||||
found somewhere on the current C side stack. If you store a SCM item
|
||||
off in a C data structure (say a callback pointer), and then return to
|
||||
the guile side and drop the guile-side reference to the item, guile
|
||||
may garbage collect it before it's used by the C side.
|
||||
|
||||
For example, this psudeo-code is a problem:
|
||||
|
||||
void gnc_some_function(SCM scm_thunk) {
|
||||
gnc_set_push_button_callback(some_button, scm_thunk);
|
||||
}
|
||||
|
||||
(define (unsafe-guile-function)
|
||||
(let ((my-callback (lambda () (display "Hello\n"))))
|
||||
(gnc:some-function my-callback)))
|
||||
|
||||
The problem here is that if you call unsafe-guile-function, it
|
||||
registers the pointer to the anonymous lambda created in the let
|
||||
construct with the button on the C-side and then returns. As soon as
|
||||
it returns, guile has no more references to the anonymous lambda, and
|
||||
it's not on the C stack, so guile thinks it's OK to garbage collect
|
||||
the function even though the C side has a pointer to it and may still
|
||||
use it.
|
||||
|
||||
The moral of this story is that if you need to have the C side ferret
|
||||
away a scheme item for later, you must also keep at least one
|
||||
reference to that item on the guile side until the C side is finished
|
||||
with it. I believe that the guile people have recently come up with a
|
||||
nice general solution to this problem, but until that's generally
|
||||
available, there are a number of ways you can solve this.
|
||||
|
||||
If nothing else, you can just create a global hash on the guile side,
|
||||
place the object in question in the hash table, and then have the
|
||||
C-side delete that item from the hash when it's finished with it.
|
||||
|
||||
|
||||
Guile Interrupts:
|
||||
-----------------
|
||||
|
||||
Another issue that I'm not quite sure of myself yet is that of
|
||||
interrupts. Guile has the ability to protect certain segments of code
|
||||
with SCM_DEFER_INTS/SCM_ALLOW_INTS, but at the moment I'm not sure
|
||||
when this is required. If anyone gets the chance to check this out
|
||||
before I do, then please edit this file and put your findings here.
|
@ -71,7 +71,7 @@ GNOME_SRCS := top-level.c window-main.c window-register.c window-adjust.c \
|
||||
ui-callbacks.c window-reconcile.c \
|
||||
dialog-options.c dialog-filebox.c \
|
||||
dialog-add.c dialog-edit.c \
|
||||
scripts_menu.c
|
||||
scripts_menu.c query-user.c
|
||||
######################################################################
|
||||
|
||||
all: gnome
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "messages.h"
|
||||
#include "top-level.h"
|
||||
#include "cursors.h"
|
||||
#include "query-user.h"
|
||||
#include "ui-callbacks.h"
|
||||
#include "util.h"
|
||||
|
||||
@ -241,141 +242,9 @@ unsetBusyCursor(GtkWidget *w)
|
||||
**************** VERIFYBOX STUFF ***********************************
|
||||
\********************************************************************/
|
||||
|
||||
struct verify_callback_data {
|
||||
gboolean finished;
|
||||
int value;
|
||||
};
|
||||
|
||||
static void
|
||||
verify_cb_yes(GtkWidget *w, gpointer data) {
|
||||
struct verify_callback_data *result = (struct verify_callback_data *) data;
|
||||
result->value = 1;
|
||||
result->finished = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
verify_cb_no(GtkWidget *w, gpointer data) {
|
||||
struct verify_callback_data *result = (struct verify_callback_data *) data;
|
||||
result->value = 0;
|
||||
result->finished = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
verify_cb_cancel(GtkWidget *w, gpointer data) {
|
||||
struct verify_callback_data *result = (struct verify_callback_data *) data;
|
||||
result->value = -1;
|
||||
result->finished = TRUE;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
queryBox
|
||||
|
||||
display text, and wait for yes, no, or cancel, depending on the
|
||||
arguments. Each of the *_allowed arguments indicates whether or not
|
||||
the dialog should contain a button of that type. default_answer may
|
||||
be set to 1 for "yes" (or OK), 2 for "no", and -1 for "cancel". If
|
||||
you allow both yes and OK buttons, and set 1 as the default answer,
|
||||
which button is the default is undefined, but the result is the same
|
||||
either way, and why would be doing that anyhow?
|
||||
|
||||
This function returns 1 for yes (or OK), 0 for no, and -1 for cancel.
|
||||
|
||||
NOTE: This function does not return until the dialog is closed.
|
||||
|
||||
*/
|
||||
|
||||
int
|
||||
queryBox(const char *text,
|
||||
int default_answer,
|
||||
gncBoolean yes_allowed,
|
||||
gncBoolean ok_allowed,
|
||||
gncBoolean no_allowed,
|
||||
gncBoolean cancel_allowed) {
|
||||
|
||||
GtkWidget *parent = gnc_get_ui_data();
|
||||
GtkWidget *verify_box = NULL;
|
||||
GtkWidget *verify_text = NULL;
|
||||
struct verify_callback_data result;
|
||||
|
||||
gchar *button_names[5] = {NULL, NULL, NULL, NULL, NULL};
|
||||
int button_count = 0;
|
||||
GtkSignalFunc button_func[5] = {NULL, NULL, NULL, NULL, NULL};
|
||||
int default_button = 0;
|
||||
|
||||
/* FIXME: These should be nana checks, but nana seems broken right now... */
|
||||
#if 0
|
||||
I(yes_allowed || ok_allowed || no_allowed || cancel_allowed);
|
||||
I((default_answer == 1) && (yes_allowed || ok_allowed));
|
||||
I((default_answer == 0) && no_allowed);
|
||||
I((default_answer == -1) && cancel_allowed);
|
||||
#endif
|
||||
|
||||
if(yes_allowed) {
|
||||
button_names[button_count] = GNOME_STOCK_BUTTON_YES;
|
||||
button_func[button_count] = GTK_SIGNAL_FUNC(verify_cb_yes);
|
||||
if(1 == default_answer) default_button = button_count;
|
||||
button_count++;
|
||||
}
|
||||
if(ok_allowed) {
|
||||
button_names[button_count] = GNOME_STOCK_BUTTON_OK;
|
||||
button_func[button_count] = GTK_SIGNAL_FUNC(verify_cb_yes);
|
||||
if(1 == default_answer) default_button = button_count;
|
||||
button_count++;
|
||||
}
|
||||
if(no_allowed) {
|
||||
button_names[button_count] = GNOME_STOCK_BUTTON_NO;
|
||||
button_func[button_count] = GTK_SIGNAL_FUNC(verify_cb_no);
|
||||
if(0 == default_answer) default_button = button_count;
|
||||
button_count++;
|
||||
}
|
||||
if(cancel_allowed) {
|
||||
button_names[button_count] = GNOME_STOCK_BUTTON_CANCEL;
|
||||
button_func[button_count] = GTK_SIGNAL_FUNC(verify_cb_cancel);
|
||||
if(-1 == default_answer) default_button = button_count;
|
||||
button_count++;
|
||||
}
|
||||
|
||||
/* FIXME: I have no idea why gcc needs this coercion right now... */
|
||||
verify_box = gnome_dialog_newv(text, (const gchar **) button_names);
|
||||
|
||||
// gnome_dialog_set_modal(GNOME_DIALOG(verify_box));
|
||||
|
||||
gnome_dialog_set_default(GNOME_DIALOG(verify_box), default_button);
|
||||
gnome_dialog_set_close(GNOME_DIALOG(verify_box), TRUE);
|
||||
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < button_count; i++) {
|
||||
gnome_dialog_button_connect(GNOME_DIALOG(verify_box), i,
|
||||
GTK_SIGNAL_FUNC(button_func[i]),
|
||||
(gpointer) &result);
|
||||
}
|
||||
}
|
||||
|
||||
verify_text = gtk_label_new(text);
|
||||
gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(verify_box)->vbox),
|
||||
verify_text, FALSE, FALSE, 0);
|
||||
gtk_widget_show(verify_text);
|
||||
|
||||
result.finished = FALSE;
|
||||
gtk_widget_show(verify_box);
|
||||
|
||||
setBusyCursor(parent);
|
||||
|
||||
while(!result.finished) {
|
||||
gtk_main_iteration();
|
||||
}
|
||||
|
||||
unsetBusyCursor(parent);
|
||||
|
||||
//gnome_dialog_close(GNOME_DIALOG(verify_box));
|
||||
|
||||
return result.value;
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
* verifyBox *
|
||||
* display a message, and asks the user to press "Ok" or "Cancel" *
|
||||
* display a message, and asks the user to press "Yes" or "No" *
|
||||
* *
|
||||
* NOTE: This function does not return until the dialog is closed *
|
||||
* *
|
||||
@ -386,7 +255,7 @@ queryBox(const char *text,
|
||||
\********************************************************************/
|
||||
gncBoolean
|
||||
verifyBox( const char *text ) {
|
||||
return(queryBox(text, -1, FALSE, TRUE, FALSE, TRUE) == 1);
|
||||
return(queryBox(text, 3, TRUE, FALSE, TRUE, FALSE) == 1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -12,22 +12,26 @@
|
||||
;; answer, which button is the default is undefined, but the result
|
||||
;; is the same either way, and why would be doing that anyhow?
|
||||
;;
|
||||
;; This function returns #t for yes (or OK), #f for no, or 'cancel.
|
||||
;; This function returns 'yes for yes (or OK), 'no for no, or 'cancel.
|
||||
;; If there was an unrecoverable error, this function returns #f.
|
||||
;;
|
||||
;; NOTE: This function does not return until the dialog is closed.")
|
||||
|
||||
(let* ((default (case default-answer
|
||||
((yes) 1)
|
||||
((ok) 1)
|
||||
((no) 0)
|
||||
((cancel) -1)))
|
||||
((no) 2)
|
||||
((cancel) 3)))
|
||||
(result
|
||||
(gnc:_query-dialog-lowlev_
|
||||
message default yes-button? ok-button? no-button? cancel-button?)))
|
||||
(case result
|
||||
((1) #t)
|
||||
((0) #f)
|
||||
((-1) 'cancel))))
|
||||
(cond
|
||||
((< result 0) #f)
|
||||
(else
|
||||
(case result
|
||||
((1) 'yes)
|
||||
((2) 'no)
|
||||
((3) 'cancel))))))
|
||||
|
||||
(define (gnc:message-dialog message)
|
||||
(let ((result (gnc:query-dialog message 'ok #f #t #f #f)))
|
||||
|
@ -23,6 +23,38 @@
|
||||
(lambda ()
|
||||
(gnc:extensions-qif-import win)))
|
||||
|
||||
(gnc:extensions-menu-add-item
|
||||
"Test choose item from list dialog"
|
||||
"Test choose item from list dialog"
|
||||
(lambda ()
|
||||
(let ((result (gnc:choose-item-from-list-dialog
|
||||
"Choose item from list test dialog"
|
||||
(list
|
||||
(cons "Item 1"
|
||||
(lambda ()
|
||||
(display "Item 1 selected") (newline)
|
||||
#f))
|
||||
(cons "Item 2"
|
||||
(lambda ()
|
||||
(display "Item 2 selected") (newline)
|
||||
#f))
|
||||
(cons "Item 3 (and close dialog)"
|
||||
(lambda ()
|
||||
(display "Item 3 selected -- close") (newline)
|
||||
'some-interesting-result))))))
|
||||
|
||||
(cond
|
||||
((eq? result #f)
|
||||
(gnc:error-message-dialog
|
||||
"Fatal error in choose item from list dialog."))
|
||||
((eq? result 'cancel)
|
||||
(gnc:error-message-dialog "Choose item from list dialog canceled."))
|
||||
(else
|
||||
(gnc:error-message-dialog
|
||||
(call-with-output-string (lambda (string-port)
|
||||
(display "Choose item result: " string-port)
|
||||
(write result string-port)))))))))
|
||||
|
||||
(gnc:extensions-menu-add-item
|
||||
"Test verify dialog"
|
||||
"Test verify dialog hint"
|
||||
@ -41,10 +73,13 @@
|
||||
'yes
|
||||
#t #f #t #t)))
|
||||
(case result
|
||||
((#t) (gnc:message-dialog "You said yes."))
|
||||
((#f) (gnc:message-dialog "You said no."))
|
||||
((cancel) (gnc:message-dialog "You said cancel."))))))
|
||||
|
||||
((yes) (gnc:message-dialog "You said yes."))
|
||||
((no) (gnc:message-dialog "You said no."))
|
||||
((cancel) (gnc:message-dialog "You said cancel."))
|
||||
(else
|
||||
(gnc:message-dialog "Something awful happened."))))))
|
||||
|
||||
|
||||
(gnc:extensions-menu-add-item "Simple extension test"
|
||||
"Simple extension test hint"
|
||||
gnc:extensions-menu-test-func))
|
||||
|
@ -30,18 +30,8 @@
|
||||
|
||||
void refreshMainWindow( void );
|
||||
|
||||
|
||||
/* Only implemented in GNOME version right now. */
|
||||
int queryBox(const char *text,
|
||||
int default_answer,
|
||||
gncBoolean yes_allowed,
|
||||
gncBoolean ok_allowed,
|
||||
gncBoolean no_allowed,
|
||||
gncBoolean cancel_allowed);
|
||||
|
||||
/* deprecated... replaced by queryBox in GNOME version */
|
||||
gncBoolean verifyBox(const char *text);
|
||||
|
||||
void errorBox( const char *message );
|
||||
void setBusyCursor( gncUIWidget w );
|
||||
void unsetBusyCursor( gncUIWidget w );
|
||||
|
Loading…
Reference in New Issue
Block a user