mongoose gtk logo align= gnome-run


How EuGTK Works


Overview:

From the GTK docs:

"A GTK+ user interface is constructed by nesting widgets inside widgets. Container widgets are the inner nodes in the resulting tree of widgets: they contain other widgets. So, for example, you might have a GtkWindow containing a GtkFrame containing a GtkLabel. If you wanted an image instead of a textual label inside the frame, you might replace the GtkLabel widget with a GtkImage widget.

There are two major kinds of container widgets in GTK+. Both are subclasses of the abstract GtkContainer base class. The first type of container widget has a single child widget and derives from GtkBin. These containers are decorators, which add some kind of functionality to the child. For example, a GtkButton makes its child into a clickable button; a GtkFrame draws a frame around its child and a GtkWindow places its child widget inside a top-level window.

The second type of container can have more than one child; its purpose is to manage layout. This means that these containers assign sizes and positions to their children. For example, a GtkBox arranges its children in a horizontal [or vertical] row, and a GtkGrid arranges the widgets it contains in a two-dimensional grid."

To reiterate the last point: GTK does not expect the programmer to specify position and size of each widget as is required when programming for Windows™. GTK handles these things automatically, adjusting things 'on-the-fly', as the user resizes windows, changes fonts, etc... which makes your programs more user-friendly.

Quote:

"Note the inherent danger of setting any fixed size - themes, translations into other languages, different fonts, and user action can all change the appropriate size for a given widget. So, it's basically impossible to hardcode a size that will always be correct. "

If you are accustomed to writing programs for Windows™, you'll wonder why there's not a complex IDE to help lay out your GTK program interface. The answer is: because it's not necessary! You don't need to specify sizes and positions for GTK controls, GTK takes care of that task for you. Your main job will be writing Euphoria functions, for which a plain old text editor works just fine! You do have the option to use Glade to design your program interface if you wish. See Glade.html.


Keywords

EuGTK allows you to program in an object-oriented style.

There are only a handful of new keywords to know. You can create nice-looking, functional programs with only the six shown here:

You'll find a more complete list of keywords in functions.html


Create

New instances of EuGTK containers and controls (collectively called 'widgets' in GTK) are created by calling the create() function with a class name. These class names are enumerated in GtkEnums.e, and they are the same as those used by the GTK docs. These class names are the ONLY ones you can send to the create() function. Never try numbers or strings. No quotes. Spelling counts!

The create() function returns a 'handle' (a.k.a. pointer) to the newly created instance. That handle can (and usually should) be saved in a Euphoria constant for later access:

    constant win = create(GtkWindow) -- generally, a constant is best, because you won't be changing these;
Parameters, if any, which follow the class name vary, and are often optional. Refer to the demo programs and the GTK docs for details. Also, explore the new, more compact syntax options for the create() function here, as well as variants, below.

GtkEngine.e maintains a list of currently created GTK containers and controls, and directs calls from your Euphoria program to the appropriate 'method' based on the type of widget and whether the call is to set or to get one of that widget's properties.


Properties

Every GTK widget has a list of properties which can be written to or read from. For example, a window has a title, a border width, a default size, etc.

Widgets which display information or accept input from users have properties such as text for labels and text entries, value for numeric widgets, and active for widgets such as checkboxes.

To find out what properties exist for a given widget, refer to the GTK docs. Remember that widgets inherit properties from ancestor widgets, so if you don't find a property for a given widget, follow the Object Hierarchy links in the GTK docs. As an example, you can select the font, background or text color for a window, but these properties are actually implemented by GtkWindow's ancestor the GtkWidget, whereas border width is actually implemented by the GtkWindow's ancestor GtkContainer. But you don't need to be concerned about this, all you need do is tell the window what to do, and it - or its parents or grandparents - will see that it gets done.

EuGTK takes care of finding these ancestor properties for you, but if you don't read the GTK docs, you won't be aware that these properties are available! In many cases you can just use common sense: for example, if it seems reasonable that a window should be able to have a blue background, just try it: set(win,"background","blue"). If you try something that isn't possible, such as setting a window's text, for example, you will get an error message on your terminal such as:

object class 'GtkWindow' has no property named 'text'

hint

Remember, when writing your EuGTK programs, you must run them from a terminal, in order to see warnings such as the one above!


Set

The set() function takes a 'handle' to a control, plus a 'property' to be set. Handle is almost always an atom (as assigned by the create() function), except when you are using Glade to design your interfaces, when you often use the name of the control in string form, e.g. "button1" or "help:window".

'property' is always a string! Following those are one or more parameters. The type and number of parameters requred must be determined by looking at the GTK documentation and the sample programs included here. Some examples:

    set(win,"title","My Program")
    set(win,"border_width",10)
    set(win,"default_size",300,200)
    set("help:window","Title","Using EuGTK") -- using widget name
     -- the window directly above is created in an include file 
     -- which has the namespace "help"

hint

Note that you can use widget names to refer to controls, rather than handles, if you give the control its own individual name.
(When using Glade, a name will be assigned automatically.)

For example: win = create(GtkWindow,"name=Main Window,size=400x300")

In the above line, you have named this window, and so can refer to it as "Main Window" in future set() or get() calls. Sometimes this can come in handy, resulting in more-readable code.

If you supply too many parameters, like:

    set(win,"title","My Program", "well isn't that swell?",1,2,3)
That won't usually cause any problem; the excess parameters are just discarded. You'll get an error message if you get carried away and try to send more than 10.

Too few parameters will usually cause problems, if not crashes, because unfilled values default to zero:

    set(win,"default_size")
This will set the window size to 0x0 pixels, i.e: nothing, which will make it kinda hard to see! No error message can help in this case, since such a setting could - for some strange reason - be intentional.

Mismatched parameter types - sending a string where an atom or integer is expected, or vice-versa - will usually give an error message, but sometimes a crash (segfault) is unavoidable. Again, read the GTK docs!


Get

The get() function takes a 'handle' to the control, plus a 'property' to be looked up. Handle is always an atom, except when using Glade to design your interface, in which case it is sometimes a string. And 'property' is always a string! Some examples:

    get(win,"title")  -- returns a string if a title was set, 0 otherwise 
    get(win,"border_width") -- returns an integer (pixels), 0 if unset
    get(win,"default_size") -- returns a sequence {x,y} e.g: {300,200} or {-1,-1} if unset
    get("prefs:spinbutton1","value")  -- returns an atom or integer
Sending the wrong number of parameters to the get() function will very likely cause problems! Sometimes a machine-level exception (signal 11). Fortunately, this is easy to avoid, as there normally AREN'T ANY parameters to 'get', other than the handle and the property name.


Conveniences

A few very frequently-used functions have simpler 'shorthand' ways to call them:

FunctionParametersShorthandParameters
 set(x,"add",z)  For functions on the left,

 x
and z must be atoms
 (widget handles) 
 or widget names as strings
 add(x,z)*  For shorthand notation,

 x
must be an atom 
 (a widget handle)
or a widget name as a string

 * z can be a handle
 or a {list} of handles
 set(x,"show") show(z)* 
 set(x,"show_all") show_all(z) 
 set(x,"hide") hide(z)*
 set(x,"hide all") hide_all(z)

These shortcut methods not only save a bit of typing, but more importantly, allow you to send {lists} of items, rather than calling the routine over and over, once for each item. {lists} are simply sequences of one or more handles to widgets. For example:

	add(panel,{img1,btn1,btn2,btn3})
	-- or
	add(panel,x)  -- where x can be a {list} of handles to any number of objects, of mixed types (don't all have to be buttons!)')
	-- or
	add(panel,x[1..5]) -- you can send slices as well

GTK provides two 'pack' methods: pack_start and pack_end, which are identical except for direction. The original calls are still there, but for added convenience, I've also provided pack, which uses the - (neg.) sign to indicate pack at end. This may be helpful when packing several items in one call.

	pack(panel,btn1) -- pack_start (top to bottom for vert. containers, left to right for horiz.)
	-- or
	pack(panel,-btn1) -- pack_end (this item will go at the bottom / far right of the container)


Variants

There are some GTK widgets which have multiple ways to create them. An image, for example, might be created from:

EuGTK tries to figure out which you want by examining the params (if any) you send to the create() function:

	constant img = create(GtkImage) 
	--it seems you want an empty container which can hold an image to be set at a later time.

	constant img = create(GtkImage,"~/demos/thumbnails/BabyTux.jpg")
	-- looks like you want to create this from the file named, if such file exists. 
	-- Note: cannonical_path() is automatically called to convert the filename/path to a usable form.

	constant img = create(GtkImage,"gtk-ok",GTK_ICON_SIZE_DIALOG) 
	-- looks like you want a stock image, in the size given.
	-- Note: any name beginning with "gtk-" is considered to be a stock item

	constant img = create(GtkImage,"face-smile",GTK_ICON_SIZE_DIALOG)
	-- you want an icon, as named, from the current icon theme, in the size specified.
	-- size can be either one of the GTK_ICON_SIZE_ enums, or can be a pixel value, 
	-- usually between 16 and 256.

	constant pix = create(GdkPixbuf,"~/demos/thumbnails/mongoose.png",80,80,TRUE)
	constant img = create(GtkImage,pix)
	-- by creating a pixbuf from the file, you can specify a size for the image, 
	-- plus, you have a static pixbuf object which can be re-used. 
	-- If you create an image directly from a file, you can't resize or re-use that image 


Connecting controls to functions

It should be obvious, but just to be clear, GTK programs, like Windows™ programs, Apple™ programs, and almost every other computer program written in the last few decades, are event driven. If you aren't sure what that means, find out before you begin designing your nifty new program.

Your program will need to respond to user actions (events). The various events emit signals, for example, a button click emits a "clicked" signal. Your job is to connect a widget's signal to the appropriate function to handle the event.

    connect(win,"destroy","Quit") -- Always do this for the main window!
Where win is the handle, "destroy" [always a string] is a signal, a.k.a. the name of an event. "Quit" is what to do in that event. The example above will call the function Quit() when the program's main window is destroyed. Quit() - a function exported by GtkEngine.e - then shuts down the GTK engine and frees memory it has allocated.

Quit() is one of very few built-in EuGTK functions you will need to connect to. Most other connections will be made to Euphoria functions YOU write. Any Euphoria function used for this purpose must be:

  1. A function, not a procedure
  2. Visible to the code doing the calling

You usually do not have to write a separate line of code to connect a widget to a function. The most commonly-used widgets have a convenient way to make that connection at the time the widget is created, which leads to cleaner and easier to maintain code:

	(A) constant btn1 = create(GtkButton,"gtk-ok","Foo",42) 

	(B) constant btn1 = create(GtkButton,"gtk-ok","Foo","Hello World!")

	(C) constant foo = call_back(routine_id("Foo"))
	    constant btn1 = create(GtkButton,"gtk-ok",foo,"Hello World!")
(D) New in 4.11.4!
  constant btn1 = create(GtkButton,"gtk-ok",_("Foo"),[...])

  The _() function allows linking to local functions, instead of global.
  It works better than call_back(routine_id()), since it can 
  'look forward' to find functions which are defined 
  further down in your code, allowing cleaner program structure.

  Thanks to Greg Haberek for this function.

In any of the calls above, you are making a new button with the stock OK image, connecting its default signal (which is 'clicked', in the case of a button) to call your Euphoria function Foo(), and optionally sending some object as the data parameter to that function. The data item is always optional, and can contain almost anything you want.

See Data passing below for examples of how to pass various data types to your Euphoria functions.

If you use method (A) or (B) then your Euphoria function declaration could look like this:

    --------------------------------------------------------------
    global function Foo(atom ctl, object data) -- must be global!
    --------------------------------------------------------------
If you use method (C) or (D) then you can declare your Euphoria functions as local functions, not global:
   -----------------------------------------------------------
   function Foo(atom ctl, object data)
   -----------------------------------------------------------

The parameter ctl will be filled in with the handle of the control which dispatched the call, and data will be the data attached to that control, or null if no data value was provided.

If you compile a program which uses method (A) or (B) to link to functions, it may compile without error, but you will get a run-time error on the terminal like the following:

Error: function Foo is not in scope
****** (make it global or link via routine_id)


Use the COMPILE flag for a way to quickly detect these errors in advance, before you go to the trouble of compiling.

$ eui -d COMPILE myprogram.ex

Connections, alternate methods

You can also connect signals to controls by typing a separate line:

	(1) connect(btn1,"clicked","Foo",[...]) -- global function

	(2) connect(btn1,"clicked",call_back(routine_id("Foo")),[...])

	(3) connect(btn1,"clicked",_("Foo"),[...]) -- local function

	(4) constant foo = call_back(routine_id("Foo"))
	    connect(btn1,"clicked",foo,[...])

You might use this method instead of the previous one if you want to connect a signal other than the default, or if there is no default signal provided for that control. See GTK docs for appropriate signal names, and GtkEngine.e for the implemented defaults (around line 348 in the create() function). Again, if you plan to compile, use call_back(routine_id()) as shown in (2), (3) or (4).

Function Parameters

Different controls can pass different types and number of parameters to your Euphoria "handler" functions when activated, so be sure to check the GTK docs for the particular widget/signal you are using. The GTK docs usually show a prototype of an appropriate signal handler.

Often, your Euphoria functions can ignore the parameters that GTK passes to them. If you do not need to access these parameters, just don't bother to declare them!

hint

Note that you can connect more than one signal and/or more than one function to a control. The calls will be executed in order. To do this, use the alternate 'connect' syntax as shown in (1,2,3) above, repeating the connect line for each different function or signal to be called.


A practical application of this might be to trap your main window's "delete-event" signal first, perhaps calling a routine that saves your work if necessary, then allowing (or not) the "destroy" event to call the "Quit" function to end the program.

constant win = create(GtkWindow)
connect(win,"delete-event",_("AreYouSure")) --[1]
connect(win,"destroy","Quit") --[2]
-- note 1: this will be called first
-- note 2: this may be called next, depending upon the
-- value returned by #1

-------------------------------------------------
function AreYouSure()
-------------------------------------------------
if dirty then 
-- *save it* code goes here
end if
return Question(win,,"OK to Quit?") != MB_YES
end function

The value returned by the first function will determine whether the succeeding function(s) will be called or skipped. Note that we use the syntax not equal MB_YES. This is so closing the popup Question dialog window without actually answering YES or NO will not kill the program.

If a 1 is returned from the first called function, then succeeding functions will NOT be called, and a 0 will allow the succeeding function(s) to be called. One way to look at this so it makes sense is to think of the return value as a report: A 1 or TRUE means "I've handled this myself, don't bother any further", while a zero or FALSE means "I've done what I can, it's your turn now!".

If you find that you need to be able to disconnect a signal, use this alternate method, and save the signal_id:

   integer sigid = connect(btn1,"clicked",....)
so that later, you can disconnect that signal by calling:
   disconnect(btn1,sigid)
Do not use this to disable a control, because it does not change the appearance to indicate that the control is disabled. Instead, use
   set(btn1,"sensitive",FALSE)


How to figure out which control was activated

Since you can connect several controls to a single Eu function, your function may need to determine which control is doing the calling.

As a rule, the first parameter passed to a called Eu function will be the handle of the control that was activated. The second parameter is usually the data attached when the connection was made.

These 'rules' vary on occasion. See the GTK docs for a prototype of the respective callback routine.

Here are two ways to determine which control was activated:

--------------------------------------------
function Foo(atom ctl, atom data)
--------------------------------------------
-- within this function, you might choose to:
  1. Match the ctl parameter to known control handles

  2. Use the data parameter to pass a unique identifier
Note:
For control groups (such as RadioButtons), which send a 'toggled' signal, there will be two controls responding to events, and thus two calls to your Eu function! You must check the 'active' property to see which of the two you should respond to. In some cases, you may want to respond to both , deactivating or closing one thing, and activating or showing another, for example.


Data passing

Frequently, it is convenient to be able to attach data items to an individual control, which that control will pass to functions it calls when activated. One advantage of doing things this way is that it allows you to write a single Eu function which can handle events from multiple controls. Another advantage is that it makes your code easier to read and maintain.

Depending upon the method chosen, the data can be almost anything, from a simple integer to a complex Euphoria sequence containing strings, pointers, routine_id's, and perhaps even images or other GTK 'widgets'.

Method 1

Often it is enough to simply attach the data to a control's data space, as in the examples below. This is also the cleanest and most readable method.

(1) -- passing an integer
constant 
  btn1 = create(GtkButton,"Justin",_("DisplayAge"),17),
  btn2 = create(GtkButton,"Jamie",_("DisplayAge"),15)

---------------------------------------------------------------
function DisplayAge(atom ctl, integer age)
---------------------------------------------------------------
 printf(1,"Age = %d\n",age)

Integers are passed and used directly, with no conversion needed. 
All other data types are passed as pointers, 
and must be 'decoded' by using the unpack() function.

(2) -- passing a float

 constant btn1 = create(GtkButton,"gtk-ok",_("Foo"),123.456) 

 ---------------------------------------------------------------
 function Foo(atom ctl, object data)
 ---------------------------------------------------------------
 atom num = unpack(data)
 
 The unpack() function will return an atom

(3) -- passing a string

 constant btn1 = create(GtkButton,"gtk-ok",_("Foo"),"James Brown") 

 ---------------------------------------------------------------
 function Foo(atom ctl, object data) -- must be object 
 ---------------------------------------------------------------
 data = unpack(data)
 
 The unpack() function will return a string

 (4) -- passing a Euphoria sequence {} containing almost any mix of data  
 
 constant 
     btn1 = create(GtkButton,"_Pie",_("Foo"),{"Apple Pie",1.95}),
     btn2 = create(GtkButton,"_Cake",_("Foo"),{"Carrot Cake",2.10})

 ---------------------------------------------------------------
 function Foo(atom ctl, object data) -- must be object
 ---------------------------------------------------------------
 data = unpack(data)
    Info(win,"Flo's Bakery",
        format("Two orders of [1]",data),
        format("$[2.2]",data*2))

The unpack() function will return a sequence

Method 2

Sometimes, the best way to pass multiple data values of varying types might be with Euphoria's map functions. One advantage of this method is that it allows you to access the values by name, rather than by position, as shown in the method above. The disadvantage - verbosity.

test84
    object jerry = map:new()
        map:put(jerry,"Name","Jerry")
        map:put(jerry,"School","Central High")
        map:put(jerry,"Age",17)
        map:put(jerry,"Pix",create(GdkPixbuf,"~/demos/thumbnails/Jerry.jpg"))
        -- above, we store a 'handle' to a picture of 
        -- Jerry in the map structure
        
    constant btn1 = create(GtkButton,"Student 1",_("ShowDetails"),jerry)
    
    ----------------------------------------------------------------
    function ShowDetails(atom ctl, atom data)
    ----------------------------------------------------------------
    Info(win,"Student",map:get(data,"Name"),
        sprintf("School:\n %s\nAge:\n %d",
            {map:get(data,"School"),
             map:get(data,"Age")}),,map:get(data,"Pix"))
        -- above, we use the passed 'handle' to 
        -- display Jerry's photo  in the Info pop-up


Method 3

Another way is to use each control's "data" space to pass name/value pairs. It is possible to combine this method with one of the others listed above to pass even more data.

A drawback to this method is that you can only pass strings, not numbers. You can either pass the numbers as strings, e.g. "$1.95", or use one of the above methods instead.

flo.jpg
constant pie = "~/demos/thumbnails/pie.png"
constant cake = "~/demos/thumbnails/cake.png"

constant 
    btn1 = create(GtkButton,"gtk-quit","Quit"),
    btn2 = create(GtkButton,pie & "#_Pie"),
    btn3 = create(GtkButton,cake & "#_Cake")
    connect({btn2,btn3},"clicked",_("Foo"))
    add(box,{btn1,btn2,btn3})
    
    set(btn2,"data","dessert","Pumpkin Pie")
    set(btn2,"data","price","$1.95")
    set(btn2,"data","pix",pie)
    
    set(btn3,"data","dessert","Birthday Cake")
    set(btn3,"data","price","$2.10")
    set(btn3,"data","pix",cake)

show_all(win)
main()

--------------------------------
function Foo(atom ctl)
--------------------------------
Info(win,"Flo's Bakery",
            get(ctl,"data","dessert"),
            get(ctl,"data","price"),,,
            get(ctl,"data","pix"))
return 1
end function

But Wait, There's More!

You can pass almost any type of Euphoria variable as data attached to a control, which means that you can also pass Euphoria routine_id's - so your connected function can execute whatever Eu function is attached as its data item.
If you combine this with the ability to store and pass other information in name/value pairs as shown in Method 3 above, you can have a single Eu function that provides a number of different 'services' with very little code.


Calendarscalendar


The GtkCalendar widget has a variety of ways to set and get the calendar date:

calendar
get(cal,"day") => 26 -- as integers
get(cal,"month") => 4
get(cal,"year") => 2015

set(cal,"day",23) -- changes day only
set(cal,"month",3) -- changes month only
set(cal,"year",1946) -- changes year only

get(cal,"eu_date") => {115,4,26} -- Y in Eu format
set(cal,"eu_date",{115,1,4}) => Jan 4, 2015
set(cal,"eu_date",date()) => current computer date

set(cal,"date",{1960,11,2}) => Nov 2, 1960 
set(cal,"date",{44,11,15}) => Nov 15, 1944 

set(cal,"date","11/25/1940") => Nov 25, 1940
setcal,"date","1924/4/25") => Apr 25, 1924 

get(cal,"datetime") => returns calendar date and current clock time in datetime format.
get(cal,"datetime",0) => returns calendar date in datetime format with h,m,s = 0.

get(cal,"date") => Tuesday, May 26, 2015 -- if no format provided,returns a string in default format shown
get(cal,"date","%a on %A!") => "Sun on Sunday!" -- this will be right as often as the weather bureau!

Format string can include the following specifiers, along with other characters of your choice:
    %% -- a literal %
    %a -- locale's abbreviated weekday name (e.g., Sun)
    %A -- locale's full weekday name (e.g., Sunday)
    %b -- locale's abbreviated month name (e.g., Jan)
    %B -- locale's full month name (e.g., January)
    %C -- century; like %Y, except omit last two digits (e.g., 21)
    %d -- day of month (e.g, 01)
    %j -- day of year (001..366)
    %m -- month (01..12)
    %u -- day of week (1..7); 1 is Monday
    %w -- day of week (0..6); 0 is Sunday
    %y -- last two digits of year (00..99)
    %Y -- year 

For example, get(cal,"date","Today is %A, day #%j of the year %Y")

Results
Today is Monday, day #126 of the year 2013 The calendar will normally open with the current computer date, if you don't tell it otherwise. You may also use a datetime function, such as: today = datetime:now() gtk:set(cal,"date",today) or gtk:set(cal,"date",datetime:add(today,30,DAYS)) -- shows date 30 days from now


RGBA Colors colors


GTK 3 uses a 32-bit RGBA color structure which can be a bit tricky to use, so EuGTK implements some functions to make the process simpler. With EuGTK, you can specify colors by:

To retrieve colors from, for example, the GtkColorChooserDialog, use:

 object color = get(ccd,"rgba") -- returns rgb or rgba string
To make manipulating colors easier, there are several format options available for the above call:
 object color = get(ccd,"rgba",N) -- see table below for N values
Note: there is no mapping back to a xcolor name from any of the above color formats.


Memory Usagegoose


eui
A modest sized EuGTK program, when run in interpreted mode, may use a relatively large amount of memory, (a minimum of 25 to 50 megs on my computer). This is because almost all of the Euphoria std libraries are loaded by EuGTK.
The source code will, however, run on both 32-bit and 64-bit machines, if they have Euphoria installed. WEE editor, for example, uses 107 megs. when interpreted.

eubind
The same program, when bound, may only require 10 or 20 megs, and the bound source will take up perhaps 4 or 5 megs of disk space, since the binder removes the unused routines. Bound programs run almost instantly, compared with interpreted programs.
In addition, binding takes only a moment - often less than a second. Remember that bound programs must be distributed in two forms - 32-bit and 64-bit versions. WEE uses 35.6 megs.

eushroud
This also works nicely, producing an obfuscated .il file which loads and runs very quickly. In addition, the .il file will be much smaller than a bound file - perhaps 1/2 to 1/5 the size. Like bound programs, there must be both a 32-bit version and a 64-bit version. WEE uses 22.7 megs.

euc
When compiled, the program will use only 3 or 4 megs of memory, and the runtime will be small, perhaps 1 or 2 megs, and will start even faster, but it takes quite a while to compile. I only compile a program when I'm certain that all the bugs have been worked out. You may prefer to distribute your program in compiled form. Just remember, you will need to provide separate 32-bit and 64-bit versions. WEE uses only 8.3 megs!

Conserving Memory
In general, each widget you create will require some amount of memory, so you should avoid creating (or re-creating) them in loops that might run for many iterations. Instead, create them outside the loop, and simply hide() and show() them as required. If widgets must be created within function calls, try to destroy() them before returning from the call to keep from wasting memory.


Debuggingbug


In the table below are some command-line switches you may use to get into the inner workings of EuGTK. All but the first are generally only needed when maintaining EuGTK itself, but there may be times when you can use them to help you find a programming error. Of course, you must run your program from an x-terminal in order to see the output!

SwitchOutputComment
-d COMPILE
Caution: function Foo will not link when compiled!
********
Use before compiling so you can fix links
-d CREATE
Create
    Call: GtkWindow->new
    Params: Int 
    Return type: Ptr 
    Vector: 101
    Args: {0}
    GtkWindow=>37278096
Vector is the routine_id assigned to the function "gtk_window_new" by EuGTK's "init" procedure.

The number following the => is the 'handle' to the newly-created window.
-d SET
Set
    Call: GtkWindow->set_default_size
    Params: Ptr Int Int 
    Return type: None
    Vector: 107
    Args: {37278096,300,80}
Args are: 'handle' to the widget being 'set', and following that are the parameters being passed, in this case, two integers, width and height.
-d GET
Get
    Call: GtkComboBoxEntry->get_active_text
    Params: Ptr 
    Return type: Str 
    Vector: 277
    Args: {30175312}
    Result: Banana
Vectors > 0 are direct calls to GTK routines generated via define_c_func or define_c_proc.Vectors less than -1 mean that the call is to a function written in Euphoria, in which case the vector is the negated RID.
-d INIT
Init class:GtkButton...
    set_image_position 510
    get_image_position 511
    set_always_show_image -1
    get_always_show_image -1
The numbers represent the routine_id that Euphoria has assigned to the GTK calls.
Use -d INITX for detailed listing.
-d INIT_ERR
ERR:GtkWindow set_titlebar -1
ERR:GtkWindow close -1
ERR:GtkBox set_baseline_position -1
ERR:GtkBox get_baseline_position -1
ERR:GtkButton set_always_show_image -1
ERR:GtkButton get_always_show_image -1
ERR:GtkWidget get_frame_clock -1
When the number is -1, that means the call is invalid, usually because the version of GTK you are using does not implement that call.

'always_show_image' is only available in GTK 3.6+, for example.
-d INI
-- Ini file for test173.ex
My Calendar={"date",{2015,4,5}}
ColorButton={"rgba","rgb(255,255,255)"}
MyCheckButton1={"active",1}
FontButton={"font name","Sans"}
Used to display data written to settings (ini) file on x-term
-d FUNC
FUNC g_slist_nth_data 162
    PARAMS {50331649,16777220}
    Values {24122256,103}
Debug calls to gtk_func() and gtk_str_func()
-d PROC
PROC g_set_prgname 37
    PARAMS {117440516}
    Values  widgets.ex
Debug calls to gtk_proc
-d PIXBUF
Pixbuf from file /home/irv/Pictures/IMG_0020.JPG
Scaled 300x300 1
For debugging pixbuf creation
-d PIXBUF_ERR
CAUTION: cannot create pixbuf from /home/irv/Pictures/map.pdf
For debugging pixbuf errors
-d BUILDER Screenshot Used to display namespaced objects loaded from Glade


Settingsgears


Updated for EuGTK 4.11.10

The ability to very easily save selected settings from one run to the next has been added in EuGTK 4.10.0. This includes saving the 'state' of active controls, such as spin buttons, check buttons, color buttons, font buttons, etc. as well as saving selected properties of any GtkWidget, such as the preferred background color, font, position or size of windows, etc., from run to run.

IOW, your arrangement of things at the time the program was closed will be restored next time the program is run. Refer to test153.ex and test153.ini for some examples. Below is a sample file, which can have any name and extension. .ini works fine, and is familiar. Note that it is plain text, so it's easily edited, and comments are preserved when it's updated. It uses simple name (dot) property notation.

For commonly-used controls, there is a default property defined in GtkSettings.e, which can be saved/loaded simply by adding the control's handle or name to a list of controls to pass to settings:Save(). Note that controls to be saved MUST have a name! These default states are restored when the ini file is loaded.

For saving other (non-default) properties, you must add one line of code to save that property. No additional effort is required when loading the settings, the property will be reset automatically to the saved value when the ini is loaded.

For saving bits of data which are NOT properties of a given widget, you can use the widget's named data spaces (a.k.a. key/value pairs) to store almost anything you want. For these, your program code must specifically read the data item when it needs to use it:
get("MainWindow","data","Foobar") => "Baz!"


----------------------------------------------------------------------------
-- Following items are 'persistent', only changed by editing this file:
----------------------------------------------------------------------------
--!MainWindow.icon=face-smile
--!MainWindow.border width=20

--!Label1.text=Move, resize, change color, etc...
--!ColorChooserButton.tooltip text=Pick a color for the Main Window background
--!Font Button.tooltip text=Select font for calendar

------------------------------------------------------------
-- Following items are added by the settings:Save() command
-- using the default properties for the controls on the list 
-- your program provides, or by the settings:Add() command,
-- using properties you specify.
------------------------------------------------------------

MainWindow.data.Foobar=Baz!
MainWindow.data.Message=Thanks a lot!
MainWindow.background=#729FCF
MyCalendar.font=Serif Bold Italic 12
ColorChooserButton.rgba=#729FCF
FontButton.font name=Serif Bold Italic 12
MyCalendar.date={2016,4,10}