gtk: command line and single-instance support
This commit is contained in:
parent
cd1fb5bea9
commit
045da06ace
|
@ -50,7 +50,9 @@
|
||||||
|
|
||||||
begin-busy-cursor
|
begin-busy-cursor
|
||||||
end-busy-cursor
|
end-busy-cursor
|
||||||
is-busy?)
|
is-busy?
|
||||||
|
|
||||||
|
scheme_register_process_global)
|
||||||
|
|
||||||
;; ------------------------------------------------------------
|
;; ------------------------------------------------------------
|
||||||
;; This module must be instantiated only once:
|
;; This module must be instantiated only once:
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
"queue.rkt")
|
"queue.rkt")
|
||||||
(unsafe!)
|
(unsafe!)
|
||||||
|
|
||||||
(define-gtk gtk_init (_fun (_ptr io _int) (_ptr io _pointer) -> _void))
|
|
||||||
|
|
||||||
(define-gtk gtk_rc_parse_string (_fun _string -> _void))
|
(define-gtk gtk_rc_parse_string (_fun _string -> _void))
|
||||||
(define-gtk gtk_rc_add_default_file (_fun _path -> _void))
|
(define-gtk gtk_rc_add_default_file (_fun _path -> _void))
|
||||||
(define-gtk gtk_rc_find_module_in_path (_fun _path -> _path))
|
(define-gtk gtk_rc_find_module_in_path (_fun _path -> _path))
|
||||||
|
@ -17,6 +15,5 @@
|
||||||
(gtk_rc_parse_string (format "module_path \"~a\"\n" dir))
|
(gtk_rc_parse_string (format "module_path \"~a\"\n" dir))
|
||||||
(gtk_rc_add_default_file (build-path dir "gtkrc"))))
|
(gtk_rc_add_default_file (build-path dir "gtkrc"))))
|
||||||
|
|
||||||
(gtk_init 0 #f)
|
|
||||||
(define pump-thread (gtk-start-event-pump))
|
(define pump-thread (gtk-start-event-pump))
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
"../common/queue.rkt"
|
"../common/queue.rkt"
|
||||||
"../common/freeze.rkt"
|
"../common/freeze.rkt"
|
||||||
"const.rkt"
|
"const.rkt"
|
||||||
"w32.rkt")
|
"w32.rkt"
|
||||||
|
"unique.rkt")
|
||||||
|
|
||||||
(provide gtk-start-event-pump
|
(provide gtk-start-event-pump
|
||||||
|
|
||||||
|
@ -20,12 +21,65 @@
|
||||||
queue-event
|
queue-event
|
||||||
yield)
|
yield)
|
||||||
|
|
||||||
|
|
||||||
|
;; ------------------------------------------------------------
|
||||||
|
;; Gtk initialization
|
||||||
|
|
||||||
|
(define-gtk gtk_init_check (_fun (_ptr io _int) (_ptr io _gcpointer) -> _gboolean))
|
||||||
|
|
||||||
|
(let* ([argc-ptr (scheme_register_process_global "PLT_X11_ARGUMENT_COUNT" #f)]
|
||||||
|
[argc (or (and argc-ptr (cast argc-ptr _pointer _long)) 0)]
|
||||||
|
[argv (and (positive? argc)
|
||||||
|
(scheme_register_process_global "PLT_X11_ARGUMENTS" #f))]
|
||||||
|
[display (getenv "DISPLAY")])
|
||||||
|
;; Convert X11 arguments, if any, to Gtk form:
|
||||||
|
(let-values ([(args single-instance?)
|
||||||
|
(if (zero? argc)
|
||||||
|
(values null #f)
|
||||||
|
(let loop ([i 1][si? #f])
|
||||||
|
(if (= i argc)
|
||||||
|
(values null si?)
|
||||||
|
(let ([s (ptr-ref argv _bytes i)])
|
||||||
|
(cond
|
||||||
|
[(bytes=? s #"-display")
|
||||||
|
(let-values ([(args si?) (loop (+ i 2) si?)]
|
||||||
|
[(d) (ptr-ref argv _bytes (add1 i))])
|
||||||
|
(set! display (bytes->string/utf-8 d #\?))
|
||||||
|
(values (list* #"--display" d args)
|
||||||
|
si?))]
|
||||||
|
[(bytes=? s #"-synchronous")
|
||||||
|
(let-values ([(args si?) (loop (+ i 1) si?)])
|
||||||
|
(values (cons #"--sync" args)
|
||||||
|
si?))]
|
||||||
|
[(bytes=? s #"-singleInstance")
|
||||||
|
(loop (add1 i) #t)]
|
||||||
|
[(or (bytes=? s #"-iconic")
|
||||||
|
(bytes=? s #"-rv")
|
||||||
|
(bytes=? s #"+rv")
|
||||||
|
(bytes=? s #"-reverse"))
|
||||||
|
;; ignored with 0 arguments
|
||||||
|
(loop (add1 i) #t)]
|
||||||
|
[else
|
||||||
|
;; all other ignored flags have a single argument
|
||||||
|
(loop (+ i 2) #t)])))))])
|
||||||
|
(let-values ([(new-argc new-argv)
|
||||||
|
(if (null? args)
|
||||||
|
(values 0 #f)
|
||||||
|
(values (add1 (length args))
|
||||||
|
(cast (cons (ptr-ref argv _bytes 0)
|
||||||
|
args)
|
||||||
|
(_list i _bytes)
|
||||||
|
_pointer)))])
|
||||||
|
(unless (gtk_init_check new-argc new-argv)
|
||||||
|
(error (format
|
||||||
|
"Gtk initialization failed for display ~s"
|
||||||
|
(or display ":0"))))
|
||||||
|
(when single-instance?
|
||||||
|
(do-single-instance)))))
|
||||||
|
|
||||||
;; ------------------------------------------------------------
|
;; ------------------------------------------------------------
|
||||||
;; Gtk event pump
|
;; Gtk event pump
|
||||||
|
|
||||||
(define-gtk gtk_init (_fun _int _pointer -> _void))
|
|
||||||
(gtk_init 0 #f)
|
|
||||||
|
|
||||||
(define-gtk gtk_events_pending (_fun -> _gboolean))
|
(define-gtk gtk_events_pending (_fun -> _gboolean))
|
||||||
(define-gtk gtk_main_iteration_do (_fun _gboolean -> _gboolean))
|
(define-gtk gtk_main_iteration_do (_fun _gboolean -> _gboolean))
|
||||||
|
|
||||||
|
|
86
collects/mred/private/wx/gtk/unique.rkt
Normal file
86
collects/mred/private/wx/gtk/unique.rkt
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#lang racket/base
|
||||||
|
(require ffi/unsafe
|
||||||
|
ffi/unsafe/define
|
||||||
|
racket/draw/bstr
|
||||||
|
net/base64
|
||||||
|
"types.rkt"
|
||||||
|
"utils.rkt")
|
||||||
|
|
||||||
|
(provide do-single-instance)
|
||||||
|
|
||||||
|
(define unique-lib
|
||||||
|
(with-handlers ([exn:fail? (lambda (exn) #f)])
|
||||||
|
(ffi-lib "libunique-1.0" '("0"))))
|
||||||
|
|
||||||
|
(define-ffi-definer define-unique unique-lib
|
||||||
|
#:default-make-fail make-not-available)
|
||||||
|
|
||||||
|
(define _gsize _ulong)
|
||||||
|
|
||||||
|
(define UNIQUE_RESPONSE_OK 1)
|
||||||
|
|
||||||
|
(define _UniqueApp _GtkWidget) ; not a widget, but we want to connect a signal
|
||||||
|
(define _UniqueMessageData (_cpointer 'UniqueMessageData))
|
||||||
|
|
||||||
|
(define-unique unique_app_new (_fun _string _string -> _UniqueApp)
|
||||||
|
#:fail (lambda () (lambda args #f)))
|
||||||
|
(define-unique unique_app_add_command (_fun _UniqueApp _string _int -> _void))
|
||||||
|
(define-unique unique_app_is_running (_fun _UniqueApp -> _gboolean))
|
||||||
|
(define-unique unique_app_send_message (_fun _UniqueApp _int _UniqueMessageData -> _int))
|
||||||
|
|
||||||
|
(define-unique unique_message_data_new (_fun -> _UniqueMessageData))
|
||||||
|
(define-unique unique_message_data_free (_fun _UniqueMessageData -> _void))
|
||||||
|
(define-unique unique_message_data_set (_fun _UniqueMessageData _pointer _gsize -> _void))
|
||||||
|
(define-unique unique_message_data_get (_fun _UniqueMessageData (len : (_ptr o _gsize))
|
||||||
|
-> (data : _bytes)
|
||||||
|
-> (scheme_make_sized_byte_string
|
||||||
|
data
|
||||||
|
len
|
||||||
|
0)))
|
||||||
|
|
||||||
|
(define-signal-handler connect-message-received "message-received"
|
||||||
|
(_fun _UniqueApp _int _UniqueMessageData _uint -> _int)
|
||||||
|
(lambda (app cmd data time)
|
||||||
|
UNIQUE_RESPONSE_OK))
|
||||||
|
|
||||||
|
(define-mz gethostname (_fun _pointer _long -> _int)
|
||||||
|
#:fail (lambda () #f))
|
||||||
|
|
||||||
|
(define HOSTLEN 256)
|
||||||
|
|
||||||
|
(define (build-app-name)
|
||||||
|
(let-values ([(path) (simplify-path
|
||||||
|
(path->complete-path
|
||||||
|
(or (find-executable-path (find-system-path 'run-file) #f)
|
||||||
|
(find-system-path 'run-file))
|
||||||
|
(current-directory)))]
|
||||||
|
[(host) (or (and gethostname
|
||||||
|
(let ([b (make-bytes HOSTLEN)])
|
||||||
|
(and (zero? (gethostname b HOSTLEN))
|
||||||
|
(bytes->string/utf-8 (car (regexp-match #rx#"^[^\0]*" b)) #\?))))
|
||||||
|
"")])
|
||||||
|
(string->bytes/utf-8
|
||||||
|
(format "org.racket-lang.~a"
|
||||||
|
(encode
|
||||||
|
(format "~a~a~a" host path (version)))))))
|
||||||
|
|
||||||
|
(define (encode s)
|
||||||
|
(regexp-replace* #rx"\r\n" (base64-encode (string->bytes/utf-8 s)) ""))
|
||||||
|
|
||||||
|
(define (send-command-line app)
|
||||||
|
(let ([msg (unique_message_data_new)]
|
||||||
|
[b (let ([o (open-output-bytes)])
|
||||||
|
(write (current-command-line-arguments) o)
|
||||||
|
(get-output-bytes o))])
|
||||||
|
(unique_message_data_set msg b (bytes-length b))
|
||||||
|
(unique_app_send_message app 42 msg)))
|
||||||
|
|
||||||
|
(define (do-single-instance)
|
||||||
|
(let ([app (unique_app_new (build-app-name) #f)])
|
||||||
|
(when app
|
||||||
|
(unique_app_add_command app "startup" 42)
|
||||||
|
(when (unique_app_is_running app)
|
||||||
|
(when (= (send-command-line app)
|
||||||
|
UNIQUE_RESPONSE_OK)
|
||||||
|
(exit 0)))
|
||||||
|
(connect-message-received app))))
|
|
@ -18,6 +18,11 @@ static int wx_in_terminal = 0;
|
||||||
struct Scheme_Env;
|
struct Scheme_Env;
|
||||||
static char *get_gr_init_filename(struct Scheme_Env *env);
|
static char *get_gr_init_filename(struct Scheme_Env *env);
|
||||||
|
|
||||||
|
#ifdef wx_xt
|
||||||
|
# define PRE_FILTER_CMDLINE_ARGUMENTS
|
||||||
|
static void pre_filter_cmdline_arguments(int *argc, char ***argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
#define UNIX_INIT_FILENAME "~/.gracketrc"
|
#define UNIX_INIT_FILENAME "~/.gracketrc"
|
||||||
#define WINDOWS_INIT_FILENAME "%%HOMEDIRVE%%\\%%HOMEPATH%%\\gracketrc.rktd"
|
#define WINDOWS_INIT_FILENAME "%%HOMEDIRVE%%\\%%HOMEPATH%%\\gracketrc.rktd"
|
||||||
#define MACOS9_INIT_FILENAME "PREFERENCES:gracketrc.rktd"
|
#define MACOS9_INIT_FILENAME "PREFERENCES:gracketrc.rktd"
|
||||||
|
@ -93,8 +98,16 @@ static void yield_indefinitely()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/* Win32 handling */
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
|
||||||
|
/* ---------------------------------------- */
|
||||||
|
/* stdio to console */
|
||||||
|
/* ---------------------------------------- */
|
||||||
|
|
||||||
static void MrEdSchemeMessages(char *, ...);
|
static void MrEdSchemeMessages(char *, ...);
|
||||||
static Scheme_Object *stdin_pipe;
|
static Scheme_Object *stdin_pipe;
|
||||||
|
|
||||||
|
@ -495,6 +508,10 @@ static int parse_command_line(char ***_command, char *buf)
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------- */
|
||||||
|
/* command-line parsing */
|
||||||
|
/* ---------------------------------------- */
|
||||||
|
|
||||||
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR ignored, int nCmdShow)
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR ignored, int nCmdShow)
|
||||||
{
|
{
|
||||||
LPWSTR m_lpCmdLine;
|
LPWSTR m_lpCmdLine;
|
||||||
|
@ -582,3 +599,86 @@ END_XFORM_SKIP;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/* X11 flag handling */
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
|
#ifdef wx_xt
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *flag;
|
||||||
|
int arg_count;
|
||||||
|
} X_flag_entry;
|
||||||
|
|
||||||
|
#define SINGLE_INSTANCE "-singleInstance"
|
||||||
|
|
||||||
|
X_flag_entry X_flags[] = {
|
||||||
|
{ "-display", 1 },
|
||||||
|
{ "-geometry", 1 },
|
||||||
|
{ "-bg", 1 },
|
||||||
|
{ "-background", 1 },
|
||||||
|
{ "-fg", 1 },
|
||||||
|
{ "-foreground", 1 },
|
||||||
|
{ "-fn", 1 },
|
||||||
|
{ "-font", 1 },
|
||||||
|
{ "-iconic", 0 },
|
||||||
|
{ "-name", 1 },
|
||||||
|
{ "-rv", 0 },
|
||||||
|
{ "-reverse", 0 },
|
||||||
|
{ "+rv", 0 },
|
||||||
|
{ "-selectionTimeout", 1 },
|
||||||
|
{ "-synchronous", 0 },
|
||||||
|
{ "-title", 1 },
|
||||||
|
{ "-xnllanguage", 1 },
|
||||||
|
{ "-xrm", 1 },
|
||||||
|
{ SINGLE_INSTANCE, 0},
|
||||||
|
{ NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int filter_x_readable(char **argv, int argc)
|
||||||
|
XFORM_SKIP_PROC
|
||||||
|
{
|
||||||
|
int pos = 1, i;
|
||||||
|
|
||||||
|
while (pos < argc) {
|
||||||
|
for (i = 0; X_flags[i].flag; i++) {
|
||||||
|
if (!strcmp(X_flags[i].flag, argv[pos]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!X_flags[i].flag)
|
||||||
|
return pos;
|
||||||
|
else {
|
||||||
|
int newpos = pos + X_flags[i].arg_count + 1;
|
||||||
|
if (newpos > argc) {
|
||||||
|
printf("%s: X Window System flag \"%s\" expects %d arguments, %d provided\n",
|
||||||
|
argv[0], argv[pos], X_flags[i].arg_count, argc - pos - 1);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
pos = newpos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pre_filter_cmdline_arguments(int *argc, char ***argv)
|
||||||
|
XFORM_SKIP_PROC
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
char **naya;
|
||||||
|
|
||||||
|
pos = filter_x_readable(*argv, *argc);
|
||||||
|
if (pos > 1) {
|
||||||
|
scheme_register_process_global("PLT_X11_ARGUMENT_COUNT", (void *)(long)pos);
|
||||||
|
scheme_register_process_global("PLT_X11_ARGUMENTS", *argv);
|
||||||
|
naya = malloc((*argc - (pos - 1)) * sizeof(char *));
|
||||||
|
memcpy(naya, *argv + (pos - 1), (*argc - (pos - 1)) * sizeof(char *));
|
||||||
|
naya[0] = (*argv)[0];
|
||||||
|
*argv = naya;
|
||||||
|
*argc -= (pos - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -307,37 +307,42 @@ static int main_after_stack(void *data)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WINDOWS_UNICODE_MAIN
|
#ifdef WINDOWS_UNICODE_MAIN
|
||||||
{
|
{
|
||||||
char *a;
|
char *a;
|
||||||
int i, j, l;
|
int i, j, l;
|
||||||
argv = (char **)malloc(sizeof(char*)*argc);
|
argv = (char **)malloc(sizeof(char*)*argc);
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
for (j = 0; wargv[i][j]; j++) {
|
for (j = 0; wargv[i][j]; j++) {
|
||||||
}
|
}
|
||||||
l = scheme_utf8_encode((unsigned int*)wargv[i], 0, j,
|
l = scheme_utf8_encode((unsigned int*)wargv[i], 0, j,
|
||||||
NULL, 0,
|
NULL, 0,
|
||||||
1 /* UTF-16 */);
|
1 /* UTF-16 */);
|
||||||
a = malloc(l + 1);
|
a = malloc(l + 1);
|
||||||
scheme_utf8_encode((unsigned int *)wargv[i], 0, j,
|
scheme_utf8_encode((unsigned int *)wargv[i], 0, j,
|
||||||
(unsigned char *)a, 0,
|
(unsigned char *)a, 0,
|
||||||
1 /* UTF-16 */);
|
1 /* UTF-16 */);
|
||||||
a[l] = 0;
|
a[l] = 0;
|
||||||
argv[i] = a;
|
argv[i] = a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if !defined(NO_USER_BREAK_HANDLER) || defined(DOS_FILE_SYSTEM)
|
#if !defined(NO_USER_BREAK_HANDLER) || defined(DOS_FILE_SYSTEM)
|
||||||
break_handle = scheme_get_main_thread_break_handle();
|
break_handle = scheme_get_main_thread_break_handle();
|
||||||
signal_handle = scheme_get_signal_handle();
|
signal_handle = scheme_get_signal_handle();
|
||||||
# ifndef NO_USER_BREAK_HANDLER
|
# ifndef NO_USER_BREAK_HANDLER
|
||||||
MZ_SIGSET(SIGINT, user_break_hit);
|
MZ_SIGSET(SIGINT, user_break_hit);
|
||||||
# endif
|
# endif
|
||||||
# ifdef DOS_FILE_SYSTEM
|
# ifdef DOS_FILE_SYSTEM
|
||||||
SetConsoleCtrlHandler(ConsoleBreakHandler, TRUE);
|
SetConsoleCtrlHandler(ConsoleBreakHandler, TRUE);
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PRE_FILTER_CMDLINE_ARGUMENTS
|
||||||
|
pre_filter_cmdline_arguments(&argc, &MAIN_argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
rval = run_from_cmd_line(argc, argv, scheme_basic_env, cont_run);
|
rval = run_from_cmd_line(argc, argv, scheme_basic_env, cont_run);
|
||||||
|
|
||||||
#ifndef DEFER_EXPLICIT_EXIT
|
#ifndef DEFER_EXPLICIT_EXIT
|
||||||
|
|
|
@ -2553,7 +2553,8 @@ void *scheme_register_process_global(const char *key, void *val)
|
||||||
long len;
|
long len;
|
||||||
|
|
||||||
#if defined(MZ_USE_MZRT)
|
#if defined(MZ_USE_MZRT)
|
||||||
mzrt_mutex_lock(process_global_lock);
|
if (process_global_lock)
|
||||||
|
mzrt_mutex_lock(process_global_lock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (pg = process_globals; pg; pg = pg->next) {
|
for (pg = process_globals; pg; pg = pg->next) {
|
||||||
|
@ -2575,7 +2576,8 @@ void *scheme_register_process_global(const char *key, void *val)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MZ_USE_MZRT)
|
#if defined(MZ_USE_MZRT)
|
||||||
mzrt_mutex_unlock(process_global_lock);
|
if (process_global_lock)
|
||||||
|
mzrt_mutex_unlock(process_global_lock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return old_val;
|
return old_val;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user