]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge remote-tracking branch 'Blei/gtk-image-loader'
authorJoe Groff <arcata@gmail.com>
Sat, 27 Aug 2011 21:07:18 +0000 (14:07 -0700)
committerJoe Groff <arcata@gmail.com>
Sat, 27 Aug 2011 21:07:18 +0000 (14:07 -0700)
Conflicts:
basis/alien/enums/enums-tests.factor
basis/alien/enums/enums.factor
basis/alien/parser/parser.factor
basis/gdk/pixbuf/ffi/ffi.factor
basis/glib/ffi/ffi.factor
basis/tools/deploy/shaker/shaker.factor
basis/ui/backend/gtk/gtk.factor
basis/windows/nt/nt.factor

1  2 
basis/gdk/pixbuf/ffi/ffi.factor
basis/glib/ffi/ffi.factor
basis/images/images.factor
basis/tools/deploy/shaker/shaker.factor
basis/ui/backend/gtk/gtk.factor
basis/windows/com/com.factor
core/vocabs/loader/loader-docs.factor

index 113cf8d0c860cfae358c600ac9473c490afca31c,38959c9004f31542a38c2823272b016c9957927f..2a4f64f042284557ee9e94e9ce5d16f5240bd6d4
@@@ -1,20 -1,26 +1,29 @@@
 -! Copyright (C) 2009 Anton Gorenko.
 +! Copyright (C) 2010 Anton Gorenko.
  ! See http://factorcode.org/license.txt for BSD license.
- USING: alien alien.libraries alien.syntax combinators
- gobject-introspection kernel system vocabs.loader ;
+ USING: alien alien.data alien.libraries alien.syntax
+ combinators gio.ffi glib.ffi gmodule.ffi gobject-introspection
+ gobject.ffi kernel libc sequences system ;
+ EXCLUDE: alien.c-types => pointer ;
  IN: gdk.pixbuf.ffi
  
- <<
 +"gio.ffi" require
- >>
 +
 +LIBRARY: gdk.pixbuf
 +
  <<
  "gdk.pixbuf" {
      { [ os winnt? ] [ "libgdk_pixbuf-2.0-0.dll" cdecl add-library ] }
 -    { [ os macosx? ] [ drop ] }
 -    { [ os unix? ] [ "libgdk_pixbuf-2.0.so" cdecl add-library ] }
 +    { [ os unix? ] [ drop ] }
  } cond
  >>
  
  GIR: vocab:gdk/pixbuf/GdkPixbuf-2.0.gir
+ : data>GInputStream ( data -- GInputStream )
+     [ malloc-byte-array &free ] [ length ] bi
+     f g_memory_input_stream_new_from_data ;
+ : GInputStream>GdkPixbuf ( GInputStream -- GdkPixbuf )
+     f { { pointer: GError initial: f } }
+     [ gdk_pixbuf_new_from_stream ] with-out-parameters
+     handle-GError ;
index 860d34bb8d2277b6a89b9e5ce53ff043795bc81b,22b40f47adbecb8377ab0784b2bb8c623cbcb5a8..5eefe08cd0e7288cb421d5faaba34933701e4ac0
@@@ -1,35 -1,75 +1,91 @@@
 -! Copyright (C) 2009 Anton Gorenko.
 +! Copyright (C) 2010 Anton Gorenko.
  ! See http://factorcode.org/license.txt for BSD license.
- USING: alien alien.destructors alien.libraries alien.syntax
- combinators kernel gobject-introspection
- gobject-introspection.standard-types system ;
+ USING: accessors alien alien.c-types alien.destructors
+ alien.libraries alien.strings alien.syntax combinators
 -gobject-introspection io.encodings.utf8 kernel system
 -vocabs.parser words ;
++gobject-introspection gobject-introspection.standard-types
++io.encodings.utf8 kernel system vocabs.parser words ;
  IN: glib.ffi
  
 +LIBRARY: glib
 +
  <<
  "glib" {
      { [ os winnt? ] [ "libglib-2.0-0.dll" cdecl add-library ] }
      { [ os macosx? ] [ "/opt/local/lib/libglib-2.0.0.dylib" cdecl add-library ] }
 -    { [ os unix? ] [ "libglib-2.0.so" cdecl add-library ] }
 +    { [ os unix? ] [ drop ] }
  } cond
  >>
  
- IMPLEMENT-STRUCTS: GPollFD GSource GSourceFuncs ;
++
+ TYPEDEF: char gchar
+ TYPEDEF: uchar guchar
+ TYPEDEF: short gshort
+ TYPEDEF: ushort gushort
+ TYPEDEF: long glong
+ TYPEDEF: ulong gulong
+ TYPEDEF: int gint
+ TYPEDEF: uint guint
+ <<
+ int c-type clone
+     [ >c-bool ] >>unboxer-quot
+     [ c-bool> ] >>boxer-quot
+     object >>boxed-class
+ "gboolean" current-vocab create typedef
+ >>
+ TYPEDEF: char gint8
+ TYPEDEF: uchar guint8
+ TYPEDEF: short gint16
+ TYPEDEF: ushort guint16
+ TYPEDEF: int gint32
+ TYPEDEF: uint guint32
+ TYPEDEF: longlong gint64
+ TYPEDEF: ulonglong guint64
+ TYPEDEF: float gfloat
+ TYPEDEF: double gdouble
+ TYPEDEF: long ssize_t
+ TYPEDEF: long time_t
+ TYPEDEF: size_t gsize
+ TYPEDEF: ssize_t gssize
+ TYPEDEF: size_t GType
+ TYPEDEF: void* gpointer
+ TYPEDEF: void* gconstpointer
+ TYPEDEF: guint8 GDateDay
+ TYPEDEF: guint16 GDateYear
+ TYPEDEF: gint GPid
+ TYPEDEF: guint32 GQuark
+ TYPEDEF: gint32 GTime
+ TYPEDEF: glong gintptr
+ TYPEDEF: gint64 goffset
+ TYPEDEF: gulong guintptr
+ TYPEDEF: guint32 gunichar
+ TYPEDEF: guint16 gunichar2
+ TYPEDEF: gpointer pointer
+ REPLACE-C-TYPE: long\sdouble double
+ REPLACE-C-TYPE: any gpointer
+ IMPLEMENT-STRUCTS: GError GPollFD GSource GSourceFuncs ;
  
 +CONSTANT: G_MININT8   HEX: -80
 +CONSTANT: G_MAXINT8   HEX:  7f
 +CONSTANT: G_MAXUINT8  HEX:  ff
 +CONSTANT: G_MININT16  HEX: -8000
 +CONSTANT: G_MAXINT16  HEX:  7fff
 +CONSTANT: G_MAXUINT16 HEX:  ffff
 +CONSTANT: G_MININT32  HEX: -80000000
 +CONSTANT: G_MAXINT32  HEX:  7fffffff
 +CONSTANT: G_MAXUINT32 HEX:  ffffffff
 +CONSTANT: G_MININT64  HEX: -8000000000000000
 +CONSTANT: G_MAXINT64  HEX:  7fffffffffffffff
 +CONSTANT: G_MAXUINT64 HEX:  ffffffffffffffff
 +
  GIR: vocab:glib/GLib-2.0.gir
  
  DESTRUCTOR: g_source_unref
@@@ -38,3 -78,18 +94,18 @@@ DESTRUCTOR: g_fre
  CALLBACK: gboolean GSourceFuncsPrepareFunc ( GSource* source, gint* timeout_ ) ;
  CALLBACK: gboolean GSourceFuncsCheckFunc ( GSource* source ) ;
  CALLBACK: gboolean GSourceFuncsDispatchFunc ( GSource* source, GSourceFunc callback, gpointer user_data ) ;
+ ERROR: g-error domain code message ;
+ : GError>g-error ( GError -- g-error )
+     [ domain>> g_quark_to_string utf8 alien>string ]
+     [ code>> ]
+     [ message>> utf8 alien>string ] tri
+     \ g-error boa ;
+ : handle-GError ( GError/f -- )
+     [
+         [ GError>g-error ]
+         [ g_error_free ] bi
+         throw
+     ] when* ;
index 99f0bb91b9167d530c361b60ae0e283bd80642e0,db731d20452848df476fff541b801a51316ccffd..d033186fc0239fc6f538fe2a31b7950f5c021de8
@@@ -62,7 -62,10 +62,10 @@@ UNION: alpha-channel BGRA RGBA ABGR ARG
  
  UNION: alpha-channel-precedes-colors ABGR ARGB XBGR XRGB ;
  
- TUPLE: image dim component-order component-type upside-down? bitmap ;
+ TUPLE: image
+     dim component-order component-type
+     upside-down? premultiplied-alpha?
+     bitmap ;
  
  : <image> ( -- image ) image new ; inline
  
  
  : bytes-per-pixel ( image -- n )
      [ component-order>> ] [ component-type>> ] bi (bytes-per-pixel) ;
 +    
 +: bytes-per-image ( image -- n )
 +    [ dim>> product ] [ bytes-per-pixel ] bi * ;
  
  <PRIVATE
  
index 2329b06b1304839fb8d7d34478415ff9bcd3daec,e74bfda3ce49672844bb057ba48beef484e28950..dca9345cd1b6e73afb4e6a02e3b460420501a552
@@@ -93,13 -93,13 +93,20 @@@ IN: tools.deploy.shake
          run-file
      ] when ;
  
 +: strip-gobject ( -- )
 +    "gobject-introspection.types" vocab [
 +        "Stripping GObject type info" show
 +        "vocab:tools/deploy/shaker/strip-gobject.factor"
 +        run-file
 +    ] when ;
 +
+ : strip-gtk-icon ( -- )
+     "ui.backend.gtk" vocab [
+         "Stripping GTK icon loading code" show
+         "vocab:tools/deploy/shaker/strip-gtk-icon.factor"
+         run-file
+     ] when ;
  : strip-specialized-arrays ( -- )
      strip-dictionary? "specialized-arrays" vocab and [
          "Stripping specialized arrays" show
@@@ -541,7 -541,7 +548,8 @@@ SYMBOL: deploy-voca
      strip-destructors
      strip-call
      strip-cocoa
 +    strip-gobject
+     strip-gtk-icon
      strip-debugger
      strip-ui-error-hook
      strip-specialized-arrays
index fba30fc15a5a01ffca2eecb0ae4388606efb36ce,c5b1ff9eeb1e4bc738792bb80e944a872106d036..db316120c46c0d0c94cd25f0a7e97f4e6e6156dc
@@@ -1,92 -1,65 +1,96 @@@
 -! Copyright (C) 2010 Anton Gorenko, Philipp BrĂ¼schweiler.
 +! Copyright (C) 2010, 2011 Anton Gorenko, Philipp Bruschweiler.
  ! See http://factorcode.org/license.txt for BSD license.
  USING: accessors alien.accessors alien.c-types alien.data
  alien.strings arrays assocs classes.struct command-line
 -destructors gdk.ffi gdk.gl.ffi gdk.pixbuf.ffi glib.ffi
 +continuations destructors environment gdk.ffi gdk.gl.ffi
- glib.ffi gobject-introspection.standard-types gobject.ffi
- gtk.ffi gtk.gl.ffi io.encodings.utf8 kernel libc literals locals
- math math.bitwise math.order math.vectors namespaces sequences
- strings system threads ui ui.backend ui.backend.gtk.input-methods
- ui.backend.gtk.io ui.clipboards ui.event-loop ui.gadgets
- ui.gadgets.private ui.gadgets.worlds ui.gestures
- ui.pixel-formats ui.pixel-formats.private ui.private
- vocabs.loader combinators prettyprint io ;
++gdk.pixbuf.ffi glib.ffi
++gobject-introspection.standard-types
+ gobject.ffi gtk.ffi gtk.gl.ffi io.backend
+ io.backend.unix.multiplexers io.encodings.binary
+ io.encodings.utf8 io.files io.thread kernel libc literals
+ locals math math.bitwise math.order math.vectors namespaces
 -sequences strings system threads ui ui.backend ui.clipboards
++sequences strings system threads ui ui.backend ui.backend.gtk.input-methods
++ui.backend.gtk.io ui.clipboards
+ ui.commands ui.event-loop ui.gadgets ui.gadgets.editors
+ ui.gadgets.menus ui.gadgets.private ui.gadgets.worlds
+ ui.gestures ui.pixel-formats ui.pixel-formats.private
 -ui.private ;
++ui.private vocabs.loader combinators io ;
  IN: ui.backend.gtk
  
  SINGLETON: gtk-ui-backend
  
  TUPLE: handle ;
 -TUPLE: window-handle < handle window fullscreen? im-context im-menu ;
 +TUPLE: window-handle < handle window fullscreen? im-context ;
  
  : <window-handle> ( window im-context -- window-handle )
      window-handle new
          swap >>im-context
          swap >>window ;
  
 +: connect-signal-with-data ( object signal-name callback data -- )
 +    [ utf8 string>alien ] 2dip g_signal_connect drop ;
 +
 +: connect-signal ( object signal-name callback -- )
 +    f connect-signal-with-data ;
 +
 +! Clipboards
 +
  TUPLE: gtk-clipboard handle ;
  
  C: <gtk-clipboard> gtk-clipboard
  
 -PIXEL-FORMAT-ATTRIBUTE-TABLE: gl-config-attribs ${ GDK_GL_USE_GL GDK_GL_RGBA } H{
 -    { double-buffered ${ GDK_GL_DOUBLEBUFFER } }
 -    { stereo ${ GDK_GL_STEREO } }
 -    ! { offscreen ${ GDK_GL_DRAWABLE_TYPE 2 } }
 -    ! { fullscreen ${ GDK_GL_DRAWABLE_TYPE 1 } }
 -    ! { windowed ${ GDK_GL_DRAWABLE_TYPE 1 } }
 -    { color-bits ${ GDK_GL_BUFFER_SIZE } }
 -    { red-bits ${ GDK_GL_RED_SIZE } }
 -    { green-bits ${ GDK_GL_GREEN_SIZE } }
 -    { blue-bits ${ GDK_GL_BLUE_SIZE } }
 -    { alpha-bits ${ GDK_GL_ALPHA_SIZE } }
 -    { accum-red-bits ${ GDK_GL_ACCUM_RED_SIZE } }
 -    { accum-green-bits ${ GDK_GL_ACCUM_GREEN_SIZE } }
 -    { accum-blue-bits ${ GDK_GL_ACCUM_BLUE_SIZE } }
 -    { accum-alpha-bits ${ GDK_GL_ACCUM_ALPHA_SIZE } }
 -    { depth-bits ${ GDK_GL_DEPTH_SIZE } }
 -    { stencil-bits ${ GDK_GL_STENCIL_SIZE } }
 -    { aux-buffers ${ GDK_GL_AUX_BUFFERS } }
 -    { sample-buffers ${ GDK_GL_SAMPLE_BUFFERS } }
 -    { samples ${ GDK_GL_SAMPLES } }
 -}
 +M: gtk-clipboard clipboard-contents
 +    [
 +        handle>> gtk_clipboard_wait_for_text
 +        [ &g_free utf8 alien>string ] [ f ] if*
 +    ] with-destructors ;
  
 -M: gtk-ui-backend (make-pixel-format)
 -    nip >gl-config-attribs-int-array gdk_gl_config_new ;
 +M: gtk-clipboard set-clipboard-contents
 +    swap [ handle>> ] [ utf8 string>alien ] bi*
 +    -1 gtk_clipboard_set_text ;
  
 -M: gtk-ui-backend (free-pixel-format)
 -    handle>> g_object_unref ;
 +: init-clipboard ( -- )
 +    selection "PRIMARY"
 +    clipboard "CLIPBOARD"
 +    [
 +        utf8 string>alien gdk_atom_intern_static_string
 +        gtk_clipboard_get <gtk-clipboard> swap set-global
 +    ] 2bi@ ;
  
 -M: gtk-ui-backend (pixel-format-attribute)
 -    [ handle>> ] [ >gl-config-attribs ] bi*
 -    { int } [ gdk_gl_config_get_attrib drop ]
 -    with-out-parameters ;
 +! Timer
 +
 +SYMBOL: next-fire-time
 +
 +: set-timeout*-value ( alien value -- )
 +    swap 0 set-alien-signed-4 ; inline
 +
 +: timer-prepare ( source timeout* -- ? )
 +    nip next-fire-time get-global nano-count [-]
 +    [ 1,000,000 /i set-timeout*-value ] keep 0 = ;
 +
 +: timer-check ( source -- ? )
 +    drop next-fire-time get-global nano-count [-] 0 = ;
 +
 +: timer-dispatch ( source callback user_data -- ? )
 +    3drop sleep-time [ 1,000,000,000 ] unless* nano-count +
 +    next-fire-time set-global
 +    yield t ;
 +
 +: <timer-funcs> ( -- timer-funcs )
 +    GSourceFuncs malloc-struct
 +        [ timer-prepare ] GSourceFuncsPrepareFunc >>prepare
 +        [ timer-check ] GSourceFuncsCheckFunc >>check
 +        [ timer-dispatch ] GSourceFuncsDispatchFunc >>dispatch ;
 +
 +:: with-timer ( quot -- )
 +    nano-count next-fire-time set-global
 +    <timer-funcs> &free
 +    GSource heap-size g_source_new &g_source_unref :> source
 +    source f g_source_attach drop
 +    [ quot call( -- ) ]
 +    [ source g_source_destroy ] [ ] cleanup ;
 +
 +! User input
  
  CONSTANT: events-mask
      flags{
@@@ -110,33 -83,33 +114,33 @@@ CONSTANT: modifier
  
  CONSTANT: action-key-codes
      H{
 -        { $ GDK_BackSpace "BACKSPACE" }
 -        { $ GDK_Tab "TAB" }
 -        { $ GDK_Return "RET" }
 -        { $ GDK_KP_Enter "ENTER" }
 -        { $ GDK_Escape "ESC" }
 -        { $ GDK_Delete "DELETE" }
 -        { $ GDK_Home "HOME" }
 -        { $ GDK_Left "LEFT" }
 -        { $ GDK_Up "UP" }
 -        { $ GDK_Right "RIGHT" }
 -        { $ GDK_Down "DOWN" }
 -        { $ GDK_Page_Up "PAGE_UP" }
 -        { $ GDK_Page_Down "PAGE_DOWN" }
 -        { $ GDK_End "END" }
 -        { $ GDK_Begin "BEGIN" }
 -        { $ GDK_F1 "F1" }
 -        { $ GDK_F2 "F2" }
 -        { $ GDK_F3 "F3" }
 -        { $ GDK_F4 "F4" }
 -        { $ GDK_F5 "F5" }
 -        { $ GDK_F6 "F6" }
 -        { $ GDK_F7 "F7" }
 -        { $ GDK_F8 "F8" }
 -        { $ GDK_F9 "F9" }
 -        { $ GDK_F10 "F10" }
 -        { $ GDK_F11 "F11" }
 -        { $ GDK_F12 "F12" }
 +        { $ GDK_KEY_BackSpace "BACKSPACE" }
 +        { $ GDK_KEY_Tab "TAB" }
 +        { $ GDK_KEY_Return "RET" }
 +        { $ GDK_KEY_KP_Enter "ENTER" }
 +        { $ GDK_KEY_Escape "ESC" }
 +        { $ GDK_KEY_Delete "DELETE" }
 +        { $ GDK_KEY_Home "HOME" }
 +        { $ GDK_KEY_Left "LEFT" }
 +        { $ GDK_KEY_Up "UP" }
 +        { $ GDK_KEY_Right "RIGHT" }
 +        { $ GDK_KEY_Down "DOWN" }
 +        { $ GDK_KEY_Page_Up "PAGE_UP" }
 +        { $ GDK_KEY_Page_Down "PAGE_DOWN" }
 +        { $ GDK_KEY_End "END" }
 +        { $ GDK_KEY_Begin "BEGIN" }
 +        { $ GDK_KEY_F1 "F1" }
 +        { $ GDK_KEY_F2 "F2" }
 +        { $ GDK_KEY_F3 "F3" }
 +        { $ GDK_KEY_F4 "F4" }
 +        { $ GDK_KEY_F5 "F5" }
 +        { $ GDK_KEY_F6 "F6" }
 +        { $ GDK_KEY_F7 "F7" }
 +        { $ GDK_KEY_F8 "F8" }
 +        { $ GDK_KEY_F9 "F9" }
 +        { $ GDK_KEY_F10 "F10" }
 +        { $ GDK_KEY_F11 "F11" }
 +        { $ GDK_KEY_F12 "F12" }
      }
  
  : event-modifiers ( event -- seq )
  : mouse-event>gesture ( event -- modifiers button loc )
      [ event-modifiers ] [ button>> ] [ event-loc ] tri ;
  
 -: on-motion ( sender event user-data -- result )
 +: on-motion ( win event user-data -- ? )
      drop swap
 -    [ GdkEventMotion memory>struct event-loc ] dip window
 +    [ event-loc ] dip window
      move-hand fire-motion t ;
  
 -: on-enter ( sender event user-data -- result )
 -    on-motion ;
 -
 -: on-leave ( sender event user-data -- result )
 +: on-leave ( win event user-data -- ? )
      3drop forget-rollover t ;
  
 -: on-button-press ( sender event user-data -- result )
 -    drop swap [
 -        GdkEventButton memory>struct
 -        mouse-event>gesture [ <button-down> ] dip
 -    ] dip window send-button-down t ;
 -
 -: on-button-release ( sender event user-data -- result )
 +:: on-button-press ( win event user-data -- ? )
 +    win window :> world
 +    event mouse-event>gesture :> ( modifiers button loc )
 +    button {
 +        { 8 [ ] }
 +        { 9 [ ] }
 +        [ modifiers swap <button-down> loc world
 +          send-button-down ]
 +    } case t ;
 +
 +:: on-button-release ( win event user-data -- ? )
 +    win window :> world
 +    event mouse-event>gesture :> ( modifiers button loc )
 +    button {
 +        { 8 [ world left-action send-action ] }
 +        { 9 [ world right-action send-action ] }
 +        [ modifiers swap <button-up> loc world
 +          send-button-up ]
 +    } case t ;
 +
 +: on-scroll ( win event user-data -- ? )
      drop swap [
 -        GdkEventButton memory>struct
 -        mouse-event>gesture [ <button-up> ] dip
 -    ] dip window send-button-up t ;
 -
 -: on-scroll ( sender event user-data -- result )
 -    drop swap [
 -        GdkEventScroll memory>struct
          [ scroll-direction ] [ event-loc ] bi
      ] dip window send-scroll t ;
  
      [ gdk_keyval_to_unicode [ f ] [ 1string ] if-zero f ] ?if ;
  
  : key-event>gesture ( event -- mods sym/f action? )
 -    GdkEventKey memory>struct
      [ event-modifiers ] [ key-sym ] bi ;
    
 -: on-key-press ( sender event user-data -- result )
 +: on-key-press ( win event user-data -- ? )
      drop swap [ key-event>gesture <key-down> ] [ window ] bi*
      propagate-key-gesture t ;
  
 -: on-key-release ( sender event user-data -- result )
 +: on-key-release ( win event user-data -- ? )
      drop swap [ key-event>gesture <key-up> ] [ window ] bi*
      propagate-key-gesture t ;
  
 -: on-focus-in ( sender event user-data -- result )
 +: on-focus-in ( win event user-data -- ? )
      2drop window focus-world t ;
  
 -: on-focus-out ( sender event user-data -- result )
 +: on-focus-out ( win event user-data -- ? )
      2drop window unfocus-world t ;
  
 -: on-expose ( sender event user-data -- result )
 -    2drop window relayout t ;
 -
 -: on-configure ( sender event user-data -- result )
 -    drop [ window ] dip GdkEventConfigure memory>struct
 -    [ event-loc >>window-loc ] [ event-dim >>dim  ] bi
 -    relayout-1 f ;
 -
 -: on-delete ( sender event user-data -- result )
 -    2drop window ungraft t ;
 -
 -: init-clipboard ( -- )
 -    selection "PRIMARY"
 -    clipboard "CLIPBOARD"
 -    [
 -        utf8 string>alien gdk_atom_intern_static_string
 -        gtk_clipboard_get <gtk-clipboard> swap set-global
 -    ] 2bi@ ;
 -
 -: io-source-prepare ( source timeout -- result )
 -    2drop f ;
 -
 -: io-source-check ( source -- result )
 -    poll_fds>> 0 g_slist_nth_data GPollFD memory>struct
 -    revents>> 0 = not ;
 -
 -: io-source-dispatch ( source callback user_data -- result )
 -     3drop
 -     0 mx get wait-for-events
 -     yield t ;
 -
 -CONSTANT: poll-fd-events
 -    flags{
 -        G_IO_IN
 -        G_IO_OUT
 -        G_IO_PRI
 -        G_IO_ERR
 -        G_IO_HUP
 -        G_IO_NVAL
 -    }
 -
 -: create-poll-fd ( -- poll-fd )
 -    GPollFD malloc-struct &free
 -        mx get fd>> >>fd
 -        poll-fd-events >>events ;
 -
 -HOOK: init-io-event-source io-backend ( -- )
 -
 -M: f init-io-event-source ;
 -M: c-io-backend init-io-event-source ;
 -
 -M: object init-io-event-source
 -    GSourceFuncs malloc-struct &free
 -        [ io-source-prepare ] GSourceFuncsPrepareFunc >>prepare
 -        [ io-source-check ] GSourceFuncsCheckFunc >>check
 -        [ io-source-dispatch ] GSourceFuncsDispatchFunc >>dispatch
 -    GSource heap-size g_source_new &g_source_unref
 -    [ create-poll-fd g_source_add_poll ]
 -    [ f g_source_attach drop ] bi ;
 -
 -SYMBOL: next-timeout
 -
 -: set-timeout*-value ( alien value -- )
 -    swap 0 set-alien-signed-4 ; inline
 -
 -: timeout-prepare ( source timeout* -- result )
 -    nip next-timeout get-global nano-count [-]
 -    [ 1,000,000 /i set-timeout*-value ] keep 0 = ;
 -
 -: timeout-check ( source -- result )
 -    drop next-timeout get-global nano-count [-] 0 = ;
 -
 -: timeout-dispatch ( source callback user_data -- result )
 -    3drop sleep-time [ 1,000,000,000 ] unless* nano-count +
 -    next-timeout set-global
 -    yield t ;
 -
 -: init-timeout ( -- )
 -    GSourceFuncs malloc-struct &free
 -        [ timeout-prepare ] GSourceFuncsPrepareFunc >>prepare
 -        [ timeout-check ] GSourceFuncsCheckFunc >>check
 -        [ timeout-dispatch ] GSourceFuncsDispatchFunc >>dispatch
 -    GSource heap-size g_source_new &g_source_unref
 -    f g_source_attach drop
 -    nano-count next-timeout set-global ;
 -
+ ! This word gets replaced when deploying. See 'Vocabulary icons'
+ ! in the docs and tools.deploy.shaker.gtk-icon
+ : get-icon-data ( -- byte-array )
+     "resource:misc/icons/Factor_48x48.png" binary file-contents ;
+ : load-icon ( -- )
+     get-icon-data [
+         data>GInputStream &g_object_unref
+         GInputStream>GdkPixbuf gtk_window_set_default_icon
+     ] with-destructors ;
 -M: gtk-ui-backend (with-ui)
 -    [
 -        f f gtk_init
 -        f f gtk_gl_init
 -        load-icon
 -        init-clipboard
 -        start-ui
 -        stop-io-thread
 -        [
 -            init-io-event-source
 -            init-timeout
 -            gtk_main
 -        ] with-destructors
 -    ] ui-running ;
 -
 -: connect-signal-with-data ( object signal-name callback data -- )
 -    [ utf8 string>alien ] 2dip g_signal_connect drop ;
 -
 -: connect-signal ( object signal-name callback -- )
 -    f connect-signal-with-data ;
 -
 -:: connect-signals ( win -- )
 +:: connect-user-input-signals ( win -- )
      win events-mask gtk_widget_add_events
 -    
 -    win "expose-event" [ on-expose yield ]
 -    GtkWidget:expose-event connect-signal
 -    win "configure-event" [ on-configure yield ]
 -    GtkWidget:configure-event connect-signal
      win "motion-notify-event" [ on-motion yield ]
      GtkWidget:motion-notify-event connect-signal
      win "leave-notify-event" [ on-leave yield ]
      GtkWidget:leave-notify-event connect-signal
 -    win "enter-notify-event" [ on-enter yield ]
 -    GtkWidget:enter-notify-event connect-signal
      win "button-press-event" [ on-button-press yield ]
      GtkWidget:button-press-event connect-signal
      win "button-release-event" [ on-button-release yield ]
      win "focus-in-event" [ on-focus-in yield ]
      GtkWidget:focus-in-event connect-signal
      win "focus-out-event" [ on-focus-out yield ]
 -    GtkWidget:focus-out-event connect-signal
 -    win "delete-event" [ on-delete yield ]
 -    GtkWidget:delete-event connect-signal ;
 -
 -! ----------------------
 +    GtkWidget:focus-out-event connect-signal ;
  
 -GENERIC: support-input-methods? ( gadget -- ? )
 -GENERIC: get-cursor-surrounding ( gadget -- text cursor-pos )
 -GENERIC: delete-cursor-surrounding ( offset count gadget -- )
 -GENERIC: set-preedit-string ( str cursor-pos gadget -- )
 -GENERIC: get-cursor-loc&dim ( gadget -- loc dim )
 +! Window state events
  
 -M: gadget support-input-methods? drop f ;
 -
 -M: editor support-input-methods? drop t ;
 -
 -M: editor get-cursor-surrounding
 -    dup editor-caret first2 [ swap editor-line ] dip ;
 +: on-expose ( win event user-data -- ? )
 +    2drop window relayout t ;
  
 -M: editor delete-cursor-surrounding
 -    3drop ;
 +: on-configure ( win event user-data -- ? )
 +    drop [ window ] [ GdkEventConfigure memory>struct ] bi*
 +    [ event-loc >>window-loc ] [ event-dim >>dim ] bi
 +    relayout-1 f ;
  
 -M: editor set-preedit-string
 -    nip dup [ editor-caret ] keep
 -    [ user-input* drop ] 2dip
 -    set-caret ;
 +: on-delete ( win event user-data -- ? )
 +    2drop window ungraft t ;
  
 -M: editor get-cursor-loc&dim
 -    [ caret-loc ] [ caret-dim ] bi ;
 +:: connect-win-state-signals ( win -- )
 +    win "expose-event" [ on-expose yield ]
 +    GtkWidget:expose-event connect-signal
 +    win "configure-event" [ on-configure yield ]
 +    GtkWidget:configure-event connect-signal
 +    win "delete-event" [ on-delete yield ]
 +    GtkWidget:delete-event connect-signal ;
  
 -! ----------------------
 +! Input methods
  
  : on-retrieve-surrounding ( im-context win -- ? )
      window world-focus dup support-input-methods? [
 -        get-cursor-surrounding [ utf8 string>alien -1 ] dip
 +        cursor-surrounding [ utf8 string>alien -1 ] dip
          gtk_im_context_set_surrounding t
      ] [ 2drop f ] if ;
  
      window world-focus dup support-input-methods?
      [ delete-cursor-surrounding t ] [ 3drop f ] if nip ;
  
 -: get-preedit-string ( im-context -- str cursor-pos )
 -    { void* int } [ f swap gtk_im_context_get_preedit_string ]
 -    with-out-parameters 
 -    [ [ utf8 alien>string ] [ g_free ] bi ] dip ;
 -            
 -: on-preedit-changed ( im-context user-data -- )
 -    window world-focus dup support-input-methods? [
 -        [ get-preedit-string ] dip set-preedit-string
 -    ] [ 2drop ] if ;
 -
 -: on-commit ( sender str user_data -- )
 +: on-commit ( im-context str win -- )
      [ drop ] [ utf8 alien>string ] [ window ] tri* user-input ;
  
 -: gadget-location ( gadget -- loc )
 -    [ loc>> ] [ parent>> [ gadget-location v+ ] when* ] bi ;
 -
  : gadget-cursor-location ( gadget -- rectangle )
 -    [ gadget-location ] [ get-cursor-loc&dim ] bi [ v+ ] dip
 -    [ first2 ] bi@ GdkRectangle <struct-boa> ;
 +    [ screen-loc ] [ cursor-loc&dim ] bi [ v+ ] dip
 +    [ first2 [ >fixnum ] bi@ ] bi@
 +    cairo_rectangle_int_t <struct-boa> ;
  
  : update-cursor-location ( im-context gadget -- )
      gadget-cursor-location gtk_im_context_set_cursor_location ;
  
  ! has to be called before the window signal handler
 -:: im-on-key-event ( sender event im-context -- result )
 -    sender window world-focus :> gadget
 +:: im-on-key-event ( win event im-context -- ? )
 +    win window world-focus :> gadget
      gadget support-input-methods? [
          im-context gadget update-cursor-location
          im-context event gtk_im_context_filter_keypress
      ] [ im-context gtk_im_context_reset f ] if ;
  
 -: im-on-focus-in ( sender event user-data -- result )
 -    2drop window handle>> im-context>>
 +: im-on-focus-in ( win event im-context -- ? )
 +    2nip
      [ gtk_im_context_focus_in ] [ gtk_im_context_reset ] bi f ;
  
 -: im-on-focus-out ( sender event user-data -- result )
 -    2drop window handle>> im-context>>
 +: im-on-focus-out ( win event im-context -- ? )
 +    2nip
      [ gtk_im_context_focus_out ] [ gtk_im_context_reset ] bi f ;
  
 -: im-on-destroy ( sender user-data -- )
 +: im-on-destroy ( win im-context -- )
      nip [ f gtk_im_context_set_client_window ]
 -    [ g_object_unref ] bi ;
 -
 -! for testing only
 -
 -: com-input-method ( world -- )
 -    find-world handle>> im-menu>> f f f f 0
 -    gtk_get_current_event_time gtk_menu_popup ;
 -
 -: im-menu ( world -- )
 -    { com-input-method } show-commands-menu ;
 -
 -editor "input-method" f  {
 -    { T{ button-down f { S+ C+ } 3 } im-menu }
 -} define-command-map
 -
 -! --------
 +    ! weird GLib-GObject-WARNING message appears after calling this code
 +    ! [ g_object_unref ] bi ;
 +    [ drop ] bi ;
  
  :: configure-im ( win im -- )
      im win gtk_widget_get_window gtk_im_context_set_client_window
      im f gtk_im_context_set_use_preedit
 -
 -    gtk_menu_new :> menu
 -    im menu gtk_im_multicontext_append_menuitems
 -    menu win window handle>> im-menu<<
      
      im "commit" [ on-commit yield ]
      GtkIMContext:commit win connect-signal-with-data
      GtkIMContext:retrieve-surrounding win connect-signal-with-data
      im "delete-surrounding" [ on-delete-surrounding yield ]
      GtkIMContext:delete-surrounding win connect-signal-with-data
 -    im "preedit-changed" [ on-preedit-changed yield ]
 -    GtkIMContext:preedit-changed win connect-signal-with-data
  
      win "key-press-event" [ im-on-key-event yield ]
      GtkWidget:key-press-event im connect-signal-with-data
      win "destroy" [ im-on-destroy yield ]
      GtkObject:destroy im connect-signal-with-data ;
  
 +! Window controls
 +
  CONSTANT: window-controls>decor-flags
      H{
          { close-button 0 }
@@@ -361,58 -492,10 +376,58 @@@ CONSTANT: window-controls>func-flag
          GDK_FUNC_MOVE bitor gdk_window_set_functions
      ] 2tri ;
  
 -: setup-gl ( world -- ? )
 +! OpenGL and Pixel formats
 +
 +PIXEL-FORMAT-ATTRIBUTE-TABLE: gl-config-attribs
 +    ${ GDK_GL_USE_GL GDK_GL_RGBA }
 +    H{
 +        { double-buffered ${ GDK_GL_DOUBLEBUFFER } }
 +        { stereo ${ GDK_GL_STEREO } }
 +        ! { offscreen ${ GDK_GL_DRAWABLE_TYPE 2 } }
 +        ! { fullscreen ${ GDK_GL_DRAWABLE_TYPE 1 } }
 +        ! { windowed ${ GDK_GL_DRAWABLE_TYPE 1 } }
 +        { color-bits ${ GDK_GL_BUFFER_SIZE } }
 +        { red-bits ${ GDK_GL_RED_SIZE } }
 +        { green-bits ${ GDK_GL_GREEN_SIZE } }
 +        { blue-bits ${ GDK_GL_BLUE_SIZE } }
 +        { alpha-bits ${ GDK_GL_ALPHA_SIZE } }
 +        { accum-red-bits ${ GDK_GL_ACCUM_RED_SIZE } }
 +        { accum-green-bits ${ GDK_GL_ACCUM_GREEN_SIZE } }
 +        { accum-blue-bits ${ GDK_GL_ACCUM_BLUE_SIZE } }
 +        { accum-alpha-bits ${ GDK_GL_ACCUM_ALPHA_SIZE } }
 +        { depth-bits ${ GDK_GL_DEPTH_SIZE } }
 +        { stencil-bits ${ GDK_GL_STENCIL_SIZE } }
 +        { aux-buffers ${ GDK_GL_AUX_BUFFERS } }
 +        { sample-buffers ${ GDK_GL_SAMPLE_BUFFERS } }
 +        { samples ${ GDK_GL_SAMPLES } }
 +    }
 +
 +M: gtk-ui-backend (make-pixel-format)
 +    nip >gl-config-attribs-int-array gdk_gl_config_new ;
 +
 +M: gtk-ui-backend (free-pixel-format)
 +    handle>> g_object_unref ;
 +
 +M: gtk-ui-backend (pixel-format-attribute)
 +    [ handle>> ] [ >gl-config-attribs ] bi*
 +    { gint } [ gdk_gl_config_get_attrib drop ]
 +    with-out-parameters ;
 +
 +M: window-handle select-gl-context ( handle -- )
 +    window>>
 +    [ gtk_widget_get_gl_window ] [ gtk_widget_get_gl_context ] bi
 +    gdk_gl_drawable_make_current drop ;
 +
 +M: window-handle flush-gl-context ( handle -- )
 +    window>> gtk_widget_get_gl_window
 +    gdk_gl_drawable_swap_buffers ;
 +
 +! Window
 +
 +: configure-gl ( world -- )
      [
          [ handle>> window>> ] [ handle>> ] bi*
 -        f t GDK_GL_RGBA_TYPE gtk_widget_set_gl_capability
 +        f t GDK_GL_RGBA_TYPE gtk_widget_set_gl_capability drop
      ] with-world-pixel-format ;
  
  : auto-position ( win loc -- )
  M:: gtk-ui-backend (open-window) ( world -- )
      GTK_WINDOW_TOPLEVEL gtk_window_new :> win
      gtk_im_multicontext_new :> im
 -    
 +
      win im <window-handle> world handle<<
  
      world win register-window
      
      win world [ window-loc>> auto-position ]
      [ dim>> first2 gtk_window_set_default_size ] 2bi
 +
 +    win "factor" "Factor" [ utf8 string>alien ] bi@
 +    gtk_window_set_wmclass
      
 -    world setup-gl drop
 +    world configure-gl
  
      win gtk_widget_realize
      win world window-controls>> configure-window-controls
      
      win im configure-im
 -    win connect-signals
 +    win connect-user-input-signals
 +    win connect-win-state-signals
  
      win gtk_widget_show_all ;
  
@@@ -482,40 -561,35 +497,41 @@@ M: gtk-ui-backend (ungrab-input
      window>>
      [ gtk_grab_remove ] [ GDK_LEFT_PTR set-cursor ] bi ;
  
 -M: window-handle select-gl-context ( handle -- )
 -    window>>
 -    [ gtk_widget_get_gl_window ] [ gtk_widget_get_gl_context ] bi
 -    gdk_gl_drawable_make_current drop ;
 -
 -M: window-handle flush-gl-context ( handle -- )
 -    window>> gtk_widget_get_gl_window
 -    gdk_gl_drawable_swap_buffers ;
 +! Misc.
  
  M: gtk-ui-backend beep
      gdk_beep ;
  
  M:: gtk-ui-backend system-alert ( caption text -- )
 -    f GTK_DIALOG_MODAL GTK_MESSAGE_WARNING GTK_BUTTONS_OK
 -    caption utf8 string>alien f gtk_message_dialog_new
 -    [ text utf8 string>alien f gtk_message_dialog_format_secondary_text ]
 -    [ gtk_dialog_run drop ]
 -    [ gtk_widget_destroy ] tri ;
 -
 -M: gtk-clipboard clipboard-contents
      [
 -        handle>> gtk_clipboard_wait_for_text
 -        [ &g_free utf8 alien>string ] [ f ] if*
 +        f GTK_DIALOG_MODAL GTK_MESSAGE_WARNING GTK_BUTTONS_OK
 +        caption utf8 string>alien f
 +        gtk_message_dialog_new &gtk_widget_destroy
 +        [
 +            text utf8 string>alien f
 +            gtk_message_dialog_format_secondary_text
 +        ] [ gtk_dialog_run drop ] bi
      ] with-destructors ;
  
 -M: gtk-clipboard set-clipboard-contents
 -    swap [ handle>> ] [ utf8 string>alien ] bi*
 -    -1 gtk_clipboard_set_text ;
 +M: gtk-ui-backend (with-ui)
 +    [
 +        0 gint <ref> f void* <ref> gtk_init
 +        0 gint <ref> f void* <ref> gtk_gl_init
++        load-icon
 +        init-clipboard
 +        start-ui
 +        [
 +            [ [ gtk_main ] with-timer ] with-event-loop
 +        ] with-destructors
 +    ] ui-running ;
 +
  
  gtk-ui-backend ui-backend set-global
  
 -[ "ui.tools" ] main-vocab-hook set-global
 +{ "ui.backend.gtk" "io.backend.unix" }
 +"ui.backend.gtk.io.unix" require-when
 +
 +{ "ui.backend.gtk" "ui.gadgets.editors" }
 +"ui.backend.gtk.input-methods.editors" require-when
 +
 +[ "DISPLAY" os-env "ui.tools" "listener" ? ] main-vocab-hook set-global
index e4b6d1e85a9f559023fd99924c033fbf72a5100d,46ae1ae154d1a07b0d3754ea4de83436ee1e6c8b..7bdf8d1a9fead752b03ef0b6bd0761adab675a55
@@@ -1,6 -1,6 +1,6 @@@
  USING: alien alien.c-types alien.destructors windows.com.syntax
  windows.ole32 windows.types continuations kernel alien.syntax
- libc destructors accessors alien.data ;
+ libc destructors accessors alien.data classes.struct windows.kernel32 ;
  IN: windows.com
  
  LIBRARY: ole32
@@@ -31,14 -31,64 +31,63 @@@ COM-INTERFACE: IDropTarget IUnknown {00
      HRESULT DragLeave ( )
      HRESULT Drop ( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) ;
  
+ COM-INTERFACE: ISequentialStream IUnknown {0C733A30-2A1C-11CE-ADE5-00AA0044773D}
+     HRESULT Read ( void* pv, ULONG cb, ULONG* pcbRead )
+     HRESULT Write ( void* pv, ULONG cb, ULONG* pcbWritten ) ;
+ STRUCT: STATSTG
+     { pwcsName LPOLESTR }
+     { type DWORD }
+     { cbSize ULARGE_INTEGER }
+     { mtime FILETIME }
+     { ctime FILETIME }
+     { atime FILETIME }
+     { grfMode DWORD }
+     { grfLocksSupported DWORD }
+     { clsid CLSID }
+     { grfStateBits DWORD }
+     { reserved DWORD } ;
+ CONSTANT: STGM_READ 0
+ CONSTANT: STGM_WRITE 1
+ CONSTANT: STGM_READWRITE 2
+ CONSTANT: STG_E_INVALIDFUNCTION HEX: 80030001
+ CONSTANT: STGTY_STORAGE   1
+ CONSTANT: STGTY_STREAM    2
+ CONSTANT: STGTY_LOCKBYTES 3
+ CONSTANT: STGTY_PROPERTY  4
+ CONSTANT: STREAM_SEEK_SET 0
+ CONSTANT: STREAM_SEEK_CUR 1
+ CONSTANT: STREAM_SEEK_END 2
+ CONSTANT: LOCK_WRITE     1
+ CONSTANT: LOCK_EXCLUSIVE 2
+ CONSTANT: LOCK_ONLYONCE  4
+ CONSTANT: GUID_NULL GUID: {00000000-0000-0000-0000-000000000000}
+ COM-INTERFACE: IStream ISequentialStream {0000000C-0000-0000-C000-000000000046}
+     HRESULT Seek ( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition )
+     HRESULT SetSize ( ULARGE_INTEGER* libNewSize )
+     HRESULT CopyTo ( IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten )
+     HRESULT Commit ( DWORD grfCommitFlags )
+     HRESULT Revert ( )
+     HRESULT LockRegion ( ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType )
+     HRESULT UnlockRegion ( ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType )
+     HRESULT Stat ( STATSTG* pstatstg, DWORD grfStatFlag )
+     HRESULT Clone ( IStream** ppstm ) ;
  FUNCTION: HRESULT RegisterDragDrop ( HWND hWnd, IDropTarget* pDropTarget ) ;
  FUNCTION: HRESULT RevokeDragDrop ( HWND hWnd ) ;
  FUNCTION: void ReleaseStgMedium ( LPSTGMEDIUM pmedium ) ;
  
  : com-query-interface ( interface iid -- interface' )
 -    [
 -        void* malloc-object &free
 -        [ IUnknown::QueryInterface ole32-error ] keep *void*
 -    ] with-destructors ;
 +    { void* }
 +    [ IUnknown::QueryInterface ole32-error ]
 +    with-out-parameters ;
  
  : com-add-ref ( interface -- interface )
       [ IUnknown::AddRef drop ] keep ; inline
      over [ com-release ] curry [ ] cleanup ; inline
  
  DESTRUCTOR: com-release
index bcb4463e6ed114da41af9083930a2e7f053919db,033479f91036b068b3376775e67226b93f72d101..8a0a346a1b5a8cb7d28f63989db27f4530fcd46f
@@@ -10,8 -10,8 +10,8 @@@ $n
  "The first way is to use an environment variable. Factor looks at the " { $snippet "FACTOR_ROOTS" } " environment variable for a list of " { $snippet ":" } "-separated paths (on Unix) or a list of " { $snippet ";" } "-separated paths (on Windows)."
  $nl
  "The second way is to create a configuration file. You can list additional vocabulary roots in a file that Factor reads at startup:"
 -{ $subsections "factor-roots" }
 -"Finally, you can add vocabulary roots by calling a word from your " { $snippet "factor-rc" } " file (see " { $link "factor-rc" } "):"
 +{ $subsections ".factor-roots" }
 +"Finally, you can add vocabulary roots by calling a word from your " { $snippet ".factor-rc" } " file (see " { $link ".factor-rc" } "):"
  { $subsections add-vocab-root } ;
  
  ARTICLE: "vocabs.roots" "Vocabulary roots"
  { $subsections "add-vocab-roots" } ;
  
  ARTICLE: "vocabs.icons" "Vocabulary icons"
- "An icon file representing the vocabulary can be provided for use by " { $link "tools.deploy" } ". A file named " { $snippet "icon.ico" } " will be used as the application icon when the application is deployed on Windows. A file named " { $snippet "icon.icns" } " will be used when the application is deployed on MacOS X." ;
+ "An icon file representing the vocabulary can be provided for use by " { $link "tools.deploy" } ". If any of the following files exist inside the vocabulary directory, they will be used as icons when the application is deployed."
+ { $list
+     { { $snippet "icon.ico" } " on Windows" }
+     { { $snippet "icon.icns" } " on MacOS X" }
+     { { $snippet "icon.png" } " on Linux and *BSD" }
+ } ;
  
  ARTICLE: "vocabs.loader" "Vocabulary loader"
  "The " { $link POSTPONE: USE: } " and " { $link POSTPONE: USING: } " words load vocabularies using the vocabulary loader. The vocabulary loader is implemented in the " { $vocab-link "vocabs.loader" } " vocabulary."
@@@ -81,7 -86,7 +86,7 @@@ HELP: vocab-root
  HELP: add-vocab-root
  { $values { "root" "a pathname string" } }
  { $description "Adds a directory pathname to the list of vocabulary roots." }
 -{ $see-also "factor-roots" } ;
 +{ $see-also ".factor-roots" } ;
  
  HELP: find-vocab-root
  { $values { "vocab" "a vocabulary specifier" } { "path/f" "a pathname string" } }