IMPLEMENTATION MODULE GtkUtils ; (* Implementation notes -------------------- CStrToM2 uses libc strncpy(): when the source is shorter than the buffer strncpy() pads with NUL, and we force the last byte to NUL so the result is always terminated. This avoids pointer walking (gm2 has no pointer arithmetic) and any CAST between integer sizes. IntToStr works on a LONGINT so that the magnitude of MIN(INTEGER) is representable, then reverses the digits into the caller buffer. *) FROM SYSTEM IMPORT ADDRESS, ADR; FROM libc IMPORT strncpy; FROM GObject IMPORT g_signal_connect_data, GConnectDefault, g_object_unref; FROM GLib IMPORT g_free; FROM GError IMPORT GError, g_error_free; FROM GtkApplication IMPORT gtk_application_set_accels_for_action; PROCEDURE CStrToM2 (src: ADDRESS; VAR dst: ARRAY OF CHAR); BEGIN IF src = NIL THEN dst[0] := 0C; RETURN END; strncpy(ADR(dst), src, HIGH(dst) + 1); dst[HIGH(dst)] := 0C END CStrToM2; PROCEDURE StrAppend (VAR dst: ARRAY OF CHAR; src: ARRAY OF CHAR); VAR i, j: CARDINAL; BEGIN (* locate the current end of dst *) i := 0; WHILE (i <= HIGH(dst)) AND (dst[i] # 0C) DO INC(i) END; (* append src, leaving room for the terminator *) j := 0; WHILE (i < HIGH(dst)) AND (j <= HIGH(src)) AND (src[j] # 0C) DO dst[i] := src[j]; INC(i); INC(j) END; IF i <= HIGH(dst) THEN dst[i] := 0C ELSE dst[HIGH(dst)] := 0C END END StrAppend; PROCEDURE IntToStr (n: INTEGER; VAR dst: ARRAY OF CHAR); VAR digits: ARRAY [0..31] OF CHAR; v: INTEGER; i, j: CARDINAL; negative: BOOLEAN; BEGIN v := n; negative := v < 0; IF negative THEN v := -v END; (* collect digits least-significant first *) i := 0; REPEAT digits[i] := CHR(ORD('0') + CARDINAL(v MOD 10)); v := v DIV 10; INC(i) UNTIL v = 0; IF negative THEN digits[i] := '-'; INC(i) END; (* reverse into dst *) j := 0; WHILE (i > 0) AND (j <= HIGH(dst)) DO DEC(i); dst[j] := digits[i]; INC(j) END; IF j <= HIGH(dst) THEN dst[j] := 0C ELSE dst[HIGH(dst)] := 0C END END IntToStr; PROCEDURE Connect (instance: ADDRESS; signal: ARRAY OF CHAR; handler: ADDRESS; data: ADDRESS) : [ LONGCARD ]; BEGIN RETURN g_signal_connect_data(instance, signal, handler, data, NIL, GConnectDefault) END Connect; PROCEDURE SetAccel (application: ADDRESS; action: ARRAY OF CHAR; accel: ARRAY OF CHAR); VAR accels: ARRAY [0..1] OF ADDRESS; BEGIN accels[0] := ADR(accel); accels[1] := NIL; gtk_application_set_accels_for_action(application, action, ADR(accels)) END SetAccel; PROCEDURE Unref (obj: ADDRESS); BEGIN IF obj # NIL THEN g_object_unref(obj) END END Unref; PROCEDURE Free (ptr: ADDRESS); BEGIN IF ptr # NIL THEN g_free(ptr) END END Free; PROCEDURE ErrorMessage (err: GError; VAR dst: ARRAY OF CHAR); BEGIN IF err = NIL THEN dst[0] := 0C ELSE CStrToM2(err^.message, dst) END END ErrorMessage; PROCEDURE ClearError (VAR err: GError); BEGIN IF err # NIL THEN g_error_free(err); err := NIL END END ClearError; END GtkUtils.