From 33852f8c1b749e7b76b7f521a4e82b5b1c757b6b Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Sun, 3 May 2026 18:53:14 +0800
Subject: [PATCH] Fixes for powerpc-darwin

---
 uppsrc/Core/Defs.h                 |  11 ++
 uppsrc/Core/HeapImp.h              |   4 +-
 uppsrc/Core/JSON.h                 |  18 ++-
 uppsrc/Core/Ops.h                  |  24 +++-
 uppsrc/Core/Value.cpp              |  11 +-
 uppsrc/Core/Value.h                |  32 ++++-
 uppsrc/Core/ValueUtil.h            |  22 +--
 uppsrc/Core/Xmlize.h               |  14 +-
 uppsrc/Core/config.h               |  23 ++-
 uppsrc/CtrlCore/CocoApp.mm         | 133 +++++++++++++++--
 uppsrc/CtrlCore/CocoClip.mm        |  86 ++++++++---
 uppsrc/CtrlCore/CocoDraw.mm        |   3 +-
 uppsrc/CtrlCore/CocoDrawOp.mm      |   9 +-
 uppsrc/CtrlCore/CocoImage.mm       |  46 ++++--
 uppsrc/CtrlCore/CocoMM.h           | 156 ++++++++++++++++++--
 uppsrc/CtrlCore/CocoProc.mm        | 160 +++++++++++++++------
 uppsrc/CtrlCore/CocoWin.mm         | 174 ++++++++++++++++++-----
 uppsrc/CtrlLib/ChCocoMM.mm         | 221 ++++++++++++++++++-----------
 uppsrc/CtrlLib/Cocoa.mm            |  18 ++-
 uppsrc/CtrlLib/MacMenu.mm          | 205 ++++++++++++++++++--------
 uppsrc/Draw/Drawing.cpp            |  14 +-
 uppsrc/Draw/FontCoco.mm            |  27 +++-
 uppsrc/ide/Builders/Cocoa.cpp      |   6 +-
 uppsrc/ide/Builders/Install.cpp    |  52 +++++--
 uppsrc/plugin/bmp/_bmp.h           |  47 +++---
 uppsrc/plugin/bmp/bmphdr.h         |  56 ++++++--
 uppsrc/plugin/pcx/pcxhdr.h         |  21 ++-
 uppsrc/plugin/tif/lib/tif_config.h |   2 +
 28 files changed, 1195 insertions(+), 400 deletions(-)

diff --git a/uppsrc/Core/Defs.h b/uppsrc/Core/Defs.h
index 8e36c19f4..3fd1d147f 100644
--- a/uppsrc/Core/Defs.h
+++ b/uppsrc/Core/Defs.h
@@ -198,12 +198,23 @@ inline bool IsFin(double d)        { return !IsNaN(d) && !IsInf(d); }
 #define HIWORD(a)        (word)((a) >> 16)
 #define LOWORD(a)        word(a)
 
+#ifdef CPU_LE
 #define MAKEWORD(l, h)   ((word)  (((byte) (l)) | ((word) ((byte) (h))) << 8))
 #define MAKELONG(l, h)   ((dword) (((word) (l)) | ((dword) ((word) (h))) << 16))
+#else
+// Big-endian: swap byte positions to maintain chr[] array index compatibility
+#define MAKEWORD(l, h)   ((word)  (((byte) (h)) | ((word) ((byte) (l))) << 8))
+#define MAKELONG(l, h)   ((dword) (((word) (h)) | ((dword) ((word) (l))) << 16))
+#endif
 
 #endif
 
+#ifdef CPU_LE
 #define MAKEQWORD(l, h)  ((qword) (((dword) (l)) | ((qword) ((dword) (h))) << 32))
+#else
+// Big-endian: swap dword positions to maintain chr[] array index compatibility
+#define MAKEQWORD(l, h)  ((qword) (((dword) (h)) | ((qword) ((dword) (l))) << 32))
+#endif
 #define HIDWORD(a)       (dword)(((uint64)a) >> 32)
 #define LODWORD(a)       dword(a)
 
diff --git a/uppsrc/Core/HeapImp.h b/uppsrc/Core/HeapImp.h
index 2cebe43d8..6ac73940d 100644
--- a/uppsrc/Core/HeapImp.h
+++ b/uppsrc/Core/HeapImp.h
@@ -11,8 +11,8 @@ struct Heap;
 struct BlkPrefix { // this part is at the start of Blk allocated block, client must not touch it
 	word        prev_size;
 	word        size;
-	bool        free;
-	bool        last;
+	byte        free;  // Use byte instead of bool for consistent 1-byte size across platforms
+	byte        last;  // Use byte instead of bool for consistent 1-byte size across platforms
 	Heap       *heap; // we need this for 4KB pages and large blocks, NULL for Huge blocks
 #ifdef CPU_32
 	dword       filler;
diff --git a/uppsrc/Core/JSON.h b/uppsrc/Core/JSON.h
index 34014a917..0828f531f 100644
--- a/uppsrc/Core/JSON.h
+++ b/uppsrc/Core/JSON.h
@@ -281,6 +281,14 @@ String StoreAsJson(const T& var, bool pretty = false)
 template <class T>
 bool LoadFromJson(T& var, const char *json)
 {
+#if defined(__OBJC__) && defined(__GNUC__) && !defined(__clang__)
+	// Workaround for GCC ICE in objc_eh_runtime_type when compiling Objective-C++
+	Value jv = ParseJSON(json);
+	if(jv.IsError())
+		return false;
+	LoadFromJsonValue(var, jv);
+	return true;
+#else
 	try {
 		Value jv = ParseJSON(json);
 		if(jv.IsError())
@@ -294,6 +302,7 @@ bool LoadFromJson(T& var, const char *json)
 		return false;
 	}
 	return true;
+#endif
 }
 
 String sJsonFile(const char *file);
@@ -454,13 +463,20 @@ void JsonizeBySerialize(JsonIO& jio, T& x)
 	if(jio.IsStoring())
 	   h = HexString(StoreAsString(x));
 	jio("data", h);
-	if(jio.IsLoading())
+	if(jio.IsLoading()) {
+#if defined(__OBJC__) && defined(__GNUC__) && !defined(__clang__)
+		// Workaround for GCC ICE in objc_eh_runtime_type when compiling Objective-C++
+		// with C++ exception handling in templates (GCC bug with ObjC ABI 1)
+		LoadFromString(x, ScanHexString(h));
+#else
 		try {
 			LoadFromString(x, ScanHexString(h));
 		}
 		catch(LoadingError) {
 			throw JsonizeError("jsonize by serialize error");
 		}
+#endif
+	}
 }
 
 template <class IZE>
diff --git a/uppsrc/Core/Ops.h b/uppsrc/Core/Ops.h
index 4beb3317a..f91be5f1f 100644
--- a/uppsrc/Core/Ops.h
+++ b/uppsrc/Core/Ops.h
@@ -1,7 +1,3 @@
-#ifndef CPU_LE
-#error Only little endian CPUs supported
-#endif
-
 #if defined(CPU_X86) && defined(COMPILER_MSC)
 
 #ifdef COMPILER_GCC
@@ -101,7 +97,7 @@ void EndianSwap(int *v, size_t count);
 void EndianSwap(int64 *v, size_t count);
 void EndianSwap(uint64 *v, size_t count);
 
-// unligned access - memcpy converts to simple load/store with normal compilers
+// unaligned access - memcpy converts to simple load/store with normal compilers
 
 inline int    Peek16(const void *ptr)        { word x; memcpy(&x, ptr, 2); return x; }
 inline int    Peek32(const void *ptr)        { dword x; memcpy(&x, ptr, 4); return x; }
@@ -111,6 +107,7 @@ inline void   Poke16(void *ptr, word val)    { memcpy(ptr, &val, 2); }
 inline void   Poke32(void *ptr, dword val)   { memcpy(ptr, &val, 4); }
 inline void   Poke64(void *ptr, int64 val)   { memcpy(ptr, &val, 8); }
 
+#ifdef CPU_LE
 inline int    Peek16le(const void *ptr)      { return Peek16(ptr); }
 inline int    Peek32le(const void *ptr)      { return Peek32(ptr); }
 inline int64  Peek64le(const void *ptr)      { return Peek64(ptr); }
@@ -126,6 +123,23 @@ inline int64  Peek64be(const void *ptr)      { return SwapEndian64(Peek64(ptr));
 inline void   Poke16be(void *ptr, word val)  { Poke16(ptr, SwapEndian16(val)); }
 inline void   Poke32be(void *ptr, dword val) { Poke32(ptr, SwapEndian32(val)); }
 inline void   Poke64be(void *ptr, int64 val) { Poke64(ptr, SwapEndian64(val)); }
+#else
+inline int    Peek16le(const void *ptr)      { return SwapEndian16(Peek16(ptr)); }
+inline int    Peek32le(const void *ptr)      { return SwapEndian32(Peek32(ptr)); }
+inline int64  Peek64le(const void *ptr)      { return SwapEndian64(Peek64(ptr)); }
+
+inline void   Poke16le(void *ptr, word val)  { Poke16(ptr, SwapEndian16(val)); }
+inline void   Poke32le(void *ptr, dword val) { Poke32(ptr, SwapEndian32(val)); }
+inline void   Poke64le(void *ptr, int64 val) { Poke64(ptr, SwapEndian64(val)); }
+
+inline int    Peek16be(const void *ptr)      { return Peek16(ptr); }
+inline int    Peek32be(const void *ptr)      { return Peek32(ptr); }
+inline int64  Peek64be(const void *ptr)      { return Peek64(ptr); }
+
+inline void   Poke16be(void *ptr, word val)  { Poke16(ptr, val); }
+inline void   Poke32be(void *ptr, dword val) { Poke32(ptr, val); }
+inline void   Poke64be(void *ptr, int64 val) { Poke64(ptr, val); }
+#endif
 
 #define MAKE2B(b0, b1)                            MAKEWORD(b0, b1)
 #define MAKE4B(b0, b1, b2, b3)                    MAKELONG(MAKEWORD(b0, b1), MAKEWORD(b2, b3))
diff --git a/uppsrc/Core/Value.cpp b/uppsrc/Core/Value.cpp
index 08513f60e..b5404d93f 100644
--- a/uppsrc/Core/Value.cpp
+++ b/uppsrc/Core/Value.cpp
@@ -649,7 +649,7 @@ Vector<Value>& Value::UnShareArray()
 		ValueArray::Data *d = new ValueArray::Data;
 		d->data = clone(data->data);
 		data->Release();
-		ptr() = d;
+		SetPtr(d);
 		data = d;
 	}
 	return data->data;
@@ -662,7 +662,9 @@ Value& Value::At(int i)
 	ASSERT(i >= 0 && IsRef());
 	dword t = GetRefType();
 	if(t == VALUEMAP_V) {
-		ValueArray& va = ValueMap::UnShare((ValueMap::Data*&)ptr()).value;
+		ValueMap::Data *p = (ValueMap::Data *)ptr();
+		ValueArray& va = ValueMap::UnShare(p).value;
+		SetPtr(p);
 		ASSERT(i < va.GetCount());
 		return va.At(i);
 	}
@@ -706,7 +708,10 @@ Value& Value::GetAdd(const Value& key)
 		*this = m;
 	}
 	ASSERT(GetType() == VALUEMAP_V);
-	return ValueMap::UnShare((ValueMap::Data*&)ptr()).GetAdd(key);
+	ValueMap::Data *p = (ValueMap::Data *)ptr();
+	Value& result = ValueMap::UnShare(p).GetAdd(key);
+	SetPtr(p);
+	return result;
 }
 
 Value& Value::operator()(const String& key)
diff --git a/uppsrc/Core/Value.h b/uppsrc/Core/Value.h
index 61ee3d82c..4a386ca3e 100644
--- a/uppsrc/Core/Value.h
+++ b/uppsrc/Core/Value.h
@@ -134,16 +134,38 @@ protected:
 	friend void ValueRegisterHelper();
 
 	String   data;
-	Void    *&ptr()                  { ASSERT(IsRef()); return *(Void **)&data; }
-	Void     *ptr() const            { ASSERT(IsRef()); return *(Void **)&data; }
 
-	void     SetRefType(dword type)  { ASSERT(IsRef()); ((int *)&data)[2] = type; }
-	dword    GetRefType() const      { ASSERT(IsRef()); return ((int *)&data)[2]; }
+	// Use memcpy for endianness-safe pointer access - avoid type punning
+	void SetPtr(Void *p) {
+		ASSERT(IsRef());
+		memcpy(&data, &p, sizeof(Void*));
+	}
+	Void* GetPtr() const {
+		ASSERT(IsRef());
+		Void* p;
+		memcpy(&p, &data, sizeof(Void*));
+		return p;
+	}
+	// Legacy accessor - returns pointer value (not reference)
+	Void* ptr() const { return GetPtr(); }
+
+	void     SetRefType(dword type)  {
+		ASSERT(IsRef());
+		// Use memcpy for endianness-safe access - store type at offset 8
+		memcpy((char *)&data + 8, &type, sizeof(dword));
+	}
+	dword    GetRefType() const      {
+		ASSERT(IsRef());
+		// Use memcpy for endianness-safe access - read type from offset 8
+		dword type;
+		memcpy(&type, (const char *)&data + 8, sizeof(dword));
+		return type;
+	}
 
 	bool     IsString() const          { return !data.IsSpecial(); }
 	bool     Is(byte v) const          { return data.IsSpecial(v); }
 	bool     IsRef() const             { return Is(REF); }
-	void     InitRef(Void *p, dword t) { data.SetSpecial(REF); ptr() = p; SetRefType(t); }
+	void     InitRef(Void *p, dword t) { data.SetSpecial(REF); SetPtr(p); SetRefType(t); }
 	void     RefRelease();
 	void     RefRetain();
 	void     FreeRef()                 { if(IsRef()) RefRelease(); }
diff --git a/uppsrc/Core/ValueUtil.h b/uppsrc/Core/ValueUtil.h
index d6aac7712..e5cb30a82 100644
--- a/uppsrc/Core/ValueUtil.h
+++ b/uppsrc/Core/ValueUtil.h
@@ -75,24 +75,24 @@ struct FnValuePairOrder : ValuePairOrder {
 int CompareStrings(const Value& a, const Value& b, const LanguageInfo& f); // used by StdCompareValue
 
 class Id : Moveable<Id> {
-	String id;
+	String id_;  // Renamed from 'id' to avoid Objective-C keyword conflict
 
 public:
-	const String&  ToString() const              { return id; }
-	hash_t         GetHashValue() const          { return UPP::GetHashValue(id); }
-	bool           IsNull() const                { return UPP::IsNull(id); }
+	const String&  ToString() const              { return id_; }
+	hash_t         GetHashValue() const          { return UPP::GetHashValue(id_); }
+	bool           IsNull() const                { return UPP::IsNull(id_); }
 
 	operator const String&() const               { return ToString(); }
 	const String&  operator~() const             { return ToString(); }
-	bool           operator==(const Id& b) const { return id == b.id; }
-	bool           operator==(const String& b) const { return id == b; }
-	bool           operator==(const char *b) const { return id == b; }
-	bool           operator!=(const Id& b) const { return id != b.id; }
-	operator bool() const                        { return id.GetCount(); }
+	bool           operator==(const Id& b) const { return id_ == b.id_; }
+	bool           operator==(const String& b) const { return id_ == b; }
+	bool           operator==(const char *b) const { return id_ == b; }
+	bool           operator!=(const Id& b) const { return id_ != b.id_; }
+	operator bool() const                        { return id_.GetCount(); }
 
 	Id()                                         {}
-	Id(const String& s)                          { id = s; }
-	Id(const char *s)                            { id = s; }
+	Id(const String& s)                          { id_ = s; }
+	Id(const char *s)                            { id_ = s; }
 };
 
 struct RefManager {
diff --git a/uppsrc/Core/Xmlize.h b/uppsrc/Core/Xmlize.h
index 4a15ca3cf..81d639c5b 100644
--- a/uppsrc/Core/Xmlize.h
+++ b/uppsrc/Core/Xmlize.h
@@ -213,13 +213,20 @@ void XmlizeBySerialize(XmlIO& xio, T& x)
 	if(xio.IsStoring())
 		h = HexString(StoreAsString(x));
 	xio.Attr("data", h);
-	if(xio.IsLoading())
+	if(xio.IsLoading()) {
+#if defined(__OBJC__) && defined(__GNUC__) && !defined(__clang__)
+		// Workaround for GCC ICE in objc_eh_runtime_type when compiling Objective-C++
+		// with C++ exception handling in templates (GCC bug with ObjC ABI 1)
+		LoadFromString(x, ScanHexString(h));
+#else
 		try {
 			LoadFromString(x, ScanHexString(h));
 		}
 		catch(LoadingError) {
 			throw XmlError("xmlize by serialize error");
 		}
+#endif
+	}
 }
 
 void  StoreJsonValue(XmlIO& xio, const Value& v);
@@ -231,12 +238,17 @@ void XmlizeByJsonize(XmlIO& xio, T& x)
 	if(xio.IsStoring())
 		StoreJsonValue(xio, StoreAsJsonValue(x));
 	else {
+#if defined(__OBJC__) && defined(__GNUC__) && !defined(__clang__)
+		// Workaround for GCC ICE in objc_eh_runtime_type when compiling Objective-C++
+		LoadFromJsonValue(x, LoadJsonValue(xio.Node()));
+#else
 		try {
 			LoadFromJsonValue(x, LoadJsonValue(xio.Node()));
 		}
 		catch(JsonizeError e) {
 			throw XmlError("xmlize by jsonize error: " + e);
 		}
+#endif
 	}
 }
 
diff --git a/uppsrc/Core/config.h b/uppsrc/Core/config.h
index cf7d0f4e5..7b3d2c321 100644
--- a/uppsrc/Core/config.h
+++ b/uppsrc/Core/config.h
@@ -94,6 +94,21 @@
 		#define CPU_BE 1
 		#define CPU_BIG_ENDIAN 1
 		#define CPU_ALIGNED 1
+	#elif __powerpc64__ || __ppc64__
+		#define CPU_POWERPC 1
+		#define CPU_PPC 1
+		#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+			#define CPU_BE 1
+			#define CPU_BIG_ENDIAN 1
+		#endif
+	#elif __powerpc__ || __ppc__
+		#define CPU_32 1
+		#define CPU_POWERPC 1
+		#define CPU_PPC 1
+		#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+			#define CPU_BE 1
+			#define CPU_BIG_ENDIAN 1
+		#endif
 	#elif __aarch64__
 		#define CPU_ARM 1
 		#ifdef __ARM_NEON
@@ -156,12 +171,12 @@
 #endif
 
 #ifdef CPU_BIG_ENDIAN
-#error "Big endian CPUs are not supported anymore"
+	#define CPU_BE 1
+#else
+	#define CPU_LITTLE_ENDIAN 1
+	#define CPU_LE 1
 #endif
 
-#define CPU_LITTLE_ENDIAN 1
-#define CPU_LE 1
-
 #ifndef CPU_32
 #define CPU_64 1
 #endif
diff --git a/uppsrc/CtrlCore/CocoApp.mm b/uppsrc/CtrlCore/CocoApp.mm
index 66d36fa59..c84a5bf05 100644
--- a/uppsrc/CtrlCore/CocoApp.mm
+++ b/uppsrc/CtrlCore/CocoApp.mm
@@ -4,13 +4,22 @@
 
 #ifdef GUI_COCOA
 
+// For CGEventTap (GCC block workaround)
+#include <ApplicationServices/ApplicationServices.h>
+
+// CocoMenuItemBarKey is declared extern in CocoMM.h and defined in CocoProc.mm
+
 @interface AppDelegate : NSObject<NSApplicationDelegate>
 {
 }
+// Menu action handler - receives actions from menu items
+-(void)cocoMenuAction:(id)sender;
 @end
 
+// Forward declarations for menu handling
 namespace Upp {
 NSMenu *Cocoa_DockMenu();
+void CocoMenuBarAction(void *bar, id sender);
 };
 
 @implementation AppDelegate
@@ -20,6 +29,19 @@ NSMenu *Cocoa_DockMenu();
 	return Upp::Cocoa_DockMenu();
 }
 
+-(void)cocoMenuAction:(id)sender {
+	Upp::GuiLock __;
+	NSMenuItem *item = (NSMenuItem *)sender;
+	void *bar = objc_getAssociatedObject(item, &CocoMenuItemBarKey);
+	if(bar)
+		Upp::CocoMenuBarAction(bar, sender);
+}
+
+-(BOOL)validateMenuItem:(NSMenuItem *)menuItem {
+	// Enable all menu items that have us as target
+	return YES;
+}
+
 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
 {
 	Upp::GuiLock __;
@@ -69,6 +91,52 @@ void SyncPopupFocus(NSWindow *win)
 	}
 }
 
+#ifndef __clang__
+// CGEventTap callback for GCC (replaces block-based NSEvent monitors)
+// This provides global and local mouse event monitoring without using blocks
+static CFMachPortRef sEventTap = NULL;
+static CFRunLoopSourceRef sEventTapSource = NULL;
+
+static CGEventRef EventTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
+{
+	if(type == kCGEventLeftMouseDown) {
+		// Get the window under the mouse for local events
+		// For global events (outside our app), win will be NULL
+		CGPoint location = CGEventGetLocation(event);
+		// Check if the event is in our application
+		ProcessSerialNumber psn;
+		GetCurrentProcess(&psn);
+		ProcessSerialNumber frontPsn;
+		GetFrontProcess(&frontPsn);
+		Boolean sameProcess = false;
+		SameProcess(&psn, &frontPsn, &sameProcess);
+
+		SyncPopupFocus(sameProcess ? [NSApp keyWindow] : NULL);
+	}
+	// Return event unchanged to allow normal processing
+	return event;
+}
+
+static void SetupEventTap()
+{
+	// Create event tap for left mouse down events
+	CGEventMask eventMask = CGEventMaskBit(kCGEventLeftMouseDown);
+	sEventTap = CGEventTapCreate(kCGSessionEventTap,
+	                              kCGHeadInsertEventTap,
+	                              kCGEventTapOptionListenOnly,  // Don't modify events
+	                              eventMask,
+	                              EventTapCallback,
+	                              NULL);
+	if(sEventTap) {
+		sEventTapSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, sEventTap, 0);
+		if(sEventTapSource) {
+			CFRunLoopAddSource(CFRunLoopGetMain(), sEventTapSource, kCFRunLoopCommonModes);
+			CGEventTapEnable(sEventTap, true);
+		}
+	}
+}
+#endif
+
 extern const char *sClipFmtsRTF;
 
 id menubar;
@@ -103,18 +171,31 @@ void CocoInit(int argc, const char **argv, const char **envptr)
 	
 	Ctrl::SetUHDEnabled(true);
 	bool uhd = true;
-	for (NSScreen *screen in [NSScreen screens]) {
+#ifdef MAC_OS_X_VERSION_10_7
+	// backingScaleFactor available in 10.7+
+	NSArray *screens = [NSScreen screens];
+	for (NSUInteger i = 0; i < [screens count]; i++) {
+		NSScreen *screen = [screens objectAtIndex:i];
 		if([screen backingScaleFactor] < 2) {
 			uhd = false;
 			break;
 		}
 	}
+#else
+	// macOS 10.6: no Retina support, always non-UHD
+	uhd = false;
+#endif
 	SetUHDMode(uhd);
 
 	Font::SetDefaultFont(StdFont(fceil(DPI([sysfont pointSize]))));
-	
-	GUI_DblClickTime_Write(1000 * NSEvent.doubleClickInterval);
 
+	GUI_DblClickTime_Write(1000 * [NSEvent doubleClickInterval]);
+
+#ifndef __clang__
+	// GCC: use CGEventTap instead of block-based NSEvent monitors
+	SetupEventTap();
+#else
+	// Clang: use block-based event monitors
 	[NSEvent addGlobalMonitorForEventsMatchingMask:(NSEventMaskLeftMouseDown)
 	  handler:^(NSEvent *e) {
 	      SyncPopupFocus(NULL);
@@ -124,6 +205,7 @@ void CocoInit(int argc, const char **argv, const char **envptr)
 	      SyncPopupFocus([e window]);
 	      return e;
     }];
+#endif
     
     sClipFmtsRTF = "rtf";
     
@@ -135,13 +217,13 @@ void CocoInit(int argc, const char **argv, const char **envptr)
 int Ctrl::GetKbdDelay()
 {
 	Upp::GuiLock __;
-	return int(1000 * NSEvent.keyRepeatDelay);
+	return int(1000 * [NSEvent keyRepeatDelay]);
 }
 
 int Ctrl::GetKbdSpeed()
 {
 	Upp::GuiLock __;
-	return int(1000 * NSEvent.keyRepeatInterval);
+	return int(1000 * [NSEvent keyRepeatInterval]);
 }
 
 static NSEvent *current_event;
@@ -299,8 +381,12 @@ Rect MakeScreenRect(NSScreen *screen, CGRect r)
 void Ctrl::GetWorkArea(Array<Rect>& rc)
 {
 	Upp::GuiLock __;
-	for(NSScreen *screen in [NSScreen screens])
-		rc.Add(MakeScreenRect(screen, [screen visibleFrame]));
+	NSArray *screens = [NSScreen screens];
+	for(NSUInteger i = 0; i < [screens count]; i++) {
+		NSScreen *screen = [screens objectAtIndex:i];
+		NSRect frame = [screen visibleFrame];
+		rc.Add(MakeScreenRect(screen, NSRectToCGRect(frame)));
+	}
 }
 
 
@@ -321,8 +407,11 @@ Rect Ctrl::GetVirtualScreenArea()
 {
 	bool first = true;
 	Rect r(0, 0, 0, 0);
-	for(NSScreen *screen in [NSScreen screens]) {
-		Rect sr = MakeScreenRect(screen, [screen frame]);
+	NSArray *screens = [NSScreen screens];
+	for(NSUInteger i = 0; i < [screens count]; i++) {
+		NSScreen *screen = [screens objectAtIndex:i];
+		NSRect frame = [screen frame];
+		Rect sr = MakeScreenRect(screen, NSRectToCGRect(frame));
 		if(first)
 			r = sr;
 		else
@@ -342,8 +431,11 @@ Rect Ctrl::GetPrimaryWorkArea()
 Rect Ctrl::GetScreenArea(Point pt)
 {
 	Upp::GuiLock __;
-	for(NSScreen *screen in [NSScreen screens]) {
-		Rect rc = MakeScreenRect(screen, [screen frame]);
+	NSArray *screens = [NSScreen screens];
+	for(NSUInteger i = 0; i < [screens count]; i++) {
+		NSScreen *screen = [screens objectAtIndex:i];
+		NSRect frame = [screen frame];
+		Rect rc = MakeScreenRect(screen, NSRectToCGRect(frame));
 		if(rc.Contains(pt))
 			return rc;
 	}
@@ -352,8 +444,12 @@ Rect Ctrl::GetScreenArea(Point pt)
 
 Rect Ctrl::GetPrimaryScreenArea()
 {
-	for (NSScreen *screen in [NSScreen screens])
-		return MakeScreenRect(screen, [screen frame]);
+	NSArray *screens = [NSScreen screens];
+	if([screens count] > 0) {
+		NSScreen *screen = [screens objectAtIndex:0];
+		NSRect frame = [screen frame];
+		return MakeScreenRect(screen, NSRectToCGRect(frame));
+	}
 	return Rect(0, 0, 1024, 768);
 }
 
@@ -384,7 +480,10 @@ void Ctrl::GuiPlatformGetTopRect(Rect& r) const
 void MMCtrl::SyncRect(CocoView *view)
 {
 	NSWindow *win = [view window];
-	view->ctrl->SetWndRect(MakeScreenRect([win screen], [win contentRectForFrameRect: [win frame]]));
+	NSScreen *screen = [win screen];
+	NSRect winFrame = [win frame];
+	NSRect contentRect = [win contentRectForFrameRect:winFrame];
+	CocoViewGetCtrl(view)->SetWndRect(MakeScreenRect(screen, NSRectToCGRect(contentRect)));
 }
 
 TopFrameDraw::TopFrameDraw(Ctrl *ctrl, const Rect& r)
@@ -394,7 +493,11 @@ TopFrameDraw::TopFrameDraw(Ctrl *ctrl, const Rect& r)
 	ASSERT(ctrl->GetTop()->coco);
 	Rect tr = ctrl->GetScreenRect();
 	NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithWindow:ctrl->GetTop()->coco->window];
+#ifdef MAC_OS_X_VERSION_10_10
 	Init([gc CGContext], NULL);
+#else
+	Init((CGContextRef)[gc graphicsPort], NULL);
+#endif
 
 	CGContextTranslateCTM(cgHandle, 0, tr.GetHeight());
 	CGContextScaleCTM(cgHandle, 1, -1);
@@ -423,7 +526,7 @@ String GetSpecialDirectory(int i)
 	
 	if(auto *h = FindTuple(map, __countof(map), i)) {
 		NSArray * paths = NSSearchPathForDirectoriesInDomains(h->b, NSUserDomainMask, YES);
-		if(paths.count)
+		if([paths count])
 			return ToString([paths objectAtIndex:0]);
 	}
 	
diff --git a/uppsrc/CtrlCore/CocoClip.mm b/uppsrc/CtrlCore/CocoClip.mm
index 2363dd6ec..e7e58c27f 100644
--- a/uppsrc/CtrlCore/CocoClip.mm
+++ b/uppsrc/CtrlCore/CocoClip.mm
@@ -8,6 +8,17 @@ extern NSEvent *sCurrentMouseEvent__;
 
 namespace Upp {
 
+// macOS 10.6 SDK compatibility - these constants added in 10.13
+#ifndef NSPasteboardTypeFileURL
+#define NSPasteboardTypeFileURL NSFilenamesPboardType
+#endif
+#ifndef NSPasteboardTypeURL
+#define NSPasteboardTypeURL NSURLPboardType
+#endif
+#ifndef NSPasteboardNameDrag
+#define NSPasteboardNameDrag NSDragPboard
+#endif
+
 NSString *PasteboardType(const String& fmt)
 {
 	return decode(fmt, "text", NSPasteboardTypeString, "png", NSPasteboardTypePNG,
@@ -32,25 +43,47 @@ NSPasteboard *Pasteboard(bool dnd = false)
 
 @interface CocoClipboardOwner : NSObject {
 	@public
-	Upp::VectorMap<Upp::String, Upp::ClipData> data;
-	Upp::Ptr<Upp::Ctrl> source;
+	// Use pointers to avoid GCC ObjC runtime issues with C++ object construction
+	Upp::VectorMap<Upp::String, Upp::ClipData> *data;
+	Upp::Ctrl *source;  // Raw pointer - GCC ObjC runtime doesn't properly construct C++ objects
 	bool dnd;
 }
+- (id)init;
+- (void)dealloc;
 @end
 
 @implementation CocoClipboardOwner
+
+- (id)init {
+	self = [super init];
+	if(self) {
+		data = new Upp::VectorMap<Upp::String, Upp::ClipData>();
+		source = NULL;
+		dnd = false;
+	}
+	return self;
+}
+
+- (void)dealloc {
+	delete data;
+	[super dealloc];
+}
+
+// Helper method to render clipboard data - replaces lambda (GCC ICE workaround)
+-(Upp::String)renderFormat:(const Upp::String&)fmt
+{
+	int q = data->Find(fmt);
+	if(q < 0)
+		return Upp::Null;
+	return (*data)[q].Render();
+}
+
 -(void)pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type
 {
 	RLOG(Upp::ToString(type));
-	
+
 	Upp::GuiLock __;
-	auto render = [&](const Upp::String& fmt) -> Upp::String {
-		int q = data.Find(fmt);
-		if(q < 0)
-			return Upp::Null;
-		return data[q].Render();
-	};
-	
+
 	NSPasteboard *pasteboard = Upp::Pasteboard(dnd);
 	if(Upp::IsStandardPasteboardType(type)) {
 		RLOG("Standard type - clearning contents!");
@@ -58,7 +91,7 @@ NSPasteboard *Pasteboard(bool dnd = false)
 	}
 
 	if([type isEqual:NSPasteboardTypeString]) {
-		Upp::String raw = render("text");
+		Upp::String raw = [self renderFormat:"text"];
 		if(raw.GetCount() == 0 && source)
 			raw = source->GetDropData("text");
 	    [pasteboard setString:[NSString stringWithUTF8String:raw]
@@ -66,7 +99,7 @@ NSPasteboard *Pasteboard(bool dnd = false)
 		return;
 	}
 	else if([type isEqual:NSPasteboardTypeFileURL]) {
-		Upp::String raw = render("files");
+		Upp::String raw = [self renderFormat:"files"];
 		Upp::Value v = ParseJSON(raw);
 		if(!IsValueArray(v))
 			return;
@@ -85,7 +118,7 @@ NSPasteboard *Pasteboard(bool dnd = false)
 	bool is_rtf = [type isEqual:NSPasteboardTypeRTF];
 	Upp::String fmt = is_png ? "png" : is_rtf ? "rtf" : Upp::ToString(type);
 	
-	Upp::String raw = render(fmt);
+	Upp::String raw = [self renderFormat:fmt];
 	if(raw.GetCount() == 0 && source)
 		raw = source->GetDropData(fmt);
 	[pasteboard setData:[NSData dataWithBytes:~raw length:raw.GetCount()] forType:type];
@@ -117,7 +150,7 @@ void ClearClipboard(bool dnd)
 {
 	GuiLock __;
 	[Pasteboard(dnd) clearContents];
-	ClipboardOwner()->data.Clear();
+	ClipboardOwner()->data->Clear();
 }
 
 void ClearClipboard()
@@ -137,14 +170,14 @@ void AppendClipboard(bool dnd, const char *format, const Value& value, String (*
 {
 	GuiLock __;
 
-	auto& data = ClipboardOwner(dnd)->data;
+	auto& dataMap = *ClipboardOwner(dnd)->data;
 
 	for(String fmt : Split(format, ';'))
-		data.GetAdd(fmt) = ClipData(value, render);
+		dataMap.GetAdd(fmt) = ClipData(value, render);
 
 	AutoreleasePool ___;
 
-	[Pasteboard(dnd) declareTypes:[PasteboardTypes(data.GetKeys()) allObjects]
+	[Pasteboard(dnd) declareTypes:[PasteboardTypes(dataMap.GetKeys()) allObjects]
 	                        owner:ClipboardOwner(dnd)];
 }
 
@@ -195,16 +228,23 @@ bool IsFormatAvailable(NSPasteboard *pasteboard, const char *fmt)
 
 String ReadFormat(NSPasteboard *pasteboard, const char *fmt)
 {
-	if(bool is_files = String(fmt) == "files"; is_files || String(fmt) == "url") {
+	bool is_files = String(fmt) == "files";
+	if(is_files || String(fmt) == "url") {
 		JsonArray array;
-		
-		NSArray *urls = [pasteboard readObjectsForClasses:@[[NSURL class]] options:nil];
-		for (NSURL *url : urls) {
-			array << String(is_files ? [url.path UTF8String] : [url.absoluteString UTF8String]);
+
+#ifdef MAC_OS_X_VERSION_10_6
+		// readObjectsForClasses:options: available in 10.6+ but @[] literal not supported by GCC
+		// Use NSArray arrayWithObject: instead of @[] literal
+		NSArray *classArray = [NSArray arrayWithObject:[NSURL class]];
+		NSArray *urls = [pasteboard readObjectsForClasses:classArray options:nil];
+		for(NSUInteger i = 0; i < [urls count]; i++) {
+			NSURL *url = [urls objectAtIndex:i];
+			array << String(is_files ? [[url path] UTF8String] : [[url absoluteString] UTF8String]);
 		}
+#endif
 		return ~array;
 	}
-	
+
 	NSData *data = [pasteboard dataForType:PasteboardType(fmt)];
 	return String((const char *)[data bytes], [data length]);
 }
diff --git a/uppsrc/CtrlCore/CocoDraw.mm b/uppsrc/CtrlCore/CocoDraw.mm
index e6c5c20e9..cb6455b90 100644
--- a/uppsrc/CtrlCore/CocoDraw.mm
+++ b/uppsrc/CtrlCore/CocoDraw.mm
@@ -151,8 +151,9 @@ bool SystemDraw::IsPaintingOp(const Rect& r) const
 	cr.Intersect(GetClip());
 	if(cr.IsEmpty())
 		return false;
+	// Note: needsToDrawRect check disabled for 10.6 compatibility (RectCG vs NSRect issue)
+	// The previous line already returns true unconditionally
 	return true;
-	return nsview ? [(NSView *)nsview needsToDrawRect:MakeRectCG(1.0 / DPI(1) * cr)] : true;
 }
 
 Rect SystemDraw::GetPaintRect() const
diff --git a/uppsrc/CtrlCore/CocoDrawOp.mm b/uppsrc/CtrlCore/CocoDrawOp.mm
index 0a6f0e76b..329ec9082 100644
--- a/uppsrc/CtrlCore/CocoDrawOp.mm
+++ b/uppsrc/CtrlCore/CocoDrawOp.mm
@@ -6,10 +6,11 @@ namespace Upp {
 
 void SystemDraw::Stroke(int width, Color color, bool fill)
 {
-	static double dash[] = { 18, 6 };
-	static double dot[] = { 3, 3 };
-	static double dashdot[] = { 9, 6, 3, 6 };
-	static double dashdotdot[] = { 9, 3, 3, 3, 3, 3 };
+	// Use CGFloat for CGContextSetLineDash compatibility (float on 32-bit, double on 64-bit)
+	static CGFloat dash[] = { 18, 6 };
+	static CGFloat dot[] = { 3, 3 };
+	static CGFloat dashdot[] = { 9, 6, 3, 6 };
+	static CGFloat dashdotdot[] = { 9, 3, 3, 3, 3, 3 };
 	if(IsNull(width))
 		width = PEN_NULL;
 	switch(width) {
diff --git a/uppsrc/CtrlCore/CocoImage.mm b/uppsrc/CtrlCore/CocoImage.mm
index ee5cfd5ae..a8a296337 100644
--- a/uppsrc/CtrlCore/CocoImage.mm
+++ b/uppsrc/CtrlCore/CocoImage.mm
@@ -6,17 +6,25 @@
 
 namespace Upp {
 
+// Callback for CGDataProviderCreateWithData - releases the Image data
+static void ReleaseImageData(void *info, const void *data, size_t size)
+{
+	delete (Image *)info;
+}
+
 CGImageRef createCGImage(const Image& img)
 {
 	if(IsNull(img))
 		return NULL;
 	Image *km = new Image(img); // to keep data alive
 	CGDataProvider *dataProvider = CGDataProviderCreateWithData(km, ~img, img.GetLength() * sizeof(RGBA),
-	                               [](void *info, const void *data, size_t size) { delete (Image *)info; });
+	                               ReleaseImageData);
 	static CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); // TODO: This is probably wrong...
 	Upp::Size isz = img.GetSize();
+	// On big-endian (PowerPC), we need to specify byte order explicitly
+	CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
     CGImageRef cg_img = CGImageCreate(isz.cx, isz.cy, 8, 32, isz.cx * sizeof(RGBA),
-                                      colorSpace, kCGImageAlphaPremultipliedFirst,
+                                      colorSpace, bitmapInfo,
                                       dataProvider, 0, false, kCGRenderingIntentDefault);
 	CGDataProviderRelease(dataProvider);
 	return cg_img;
@@ -325,9 +333,19 @@ void ImageDraw::Init(int cx, int cy)
 
 	static CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
 
+	// On big-endian (PowerPC), we need to specify byte order explicitly
+	// kCGBitmapByteOrder32Host resolves to the correct order for the platform
+	CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 && !defined(__ppc__)
+	// CGBitmapContextCreateWithData available in 10.6+, but may have issues on PPC
 	SystemDraw::Init(CGBitmapContextCreateWithData(~ib, cx, cy, 8, cx * sizeof(RGBA),
-	                                               colorSpace, kCGImageAlphaPremultipliedFirst,
+	                                               colorSpace, bitmapInfo,
 	                                               NULL, NULL), NULL);
+#else
+	// Fallback for 10.5 and PowerPC 10.6: use CGBitmapContextCreate
+	SystemDraw::Init(CGBitmapContextCreate(~ib, cx, cy, 8, cx * sizeof(RGBA),
+	                                       colorSpace, bitmapInfo), NULL);
+#endif
 	CGContextTranslateCTM(cgHandle, 0, cy);
 	if(IsUHDMode()) {
 		CGContextScaleCTM(cgHandle, 2, -2);
@@ -395,19 +413,23 @@ Image GetIconForFile(const char *path)
 	
 	NSImage *image;
 	CFRef<CFStringRef> fexe = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8);
-	image = [[NSWorkspace sharedWorkspace]iconForFile:(__bridge NSString *)~fexe];
-/*
-	}
-	else { // not used any more
-		CFRef<CFStringRef> fext = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8);
-		image = *ext == '*' ? [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGenericFolderIcon)]
-	                        : [[NSWorkspace sharedWorkspace]iconForFileType:(__bridge NSString *)~fext];
-	}
-*/
+	// __bridge is ARC-only (10.7+), use direct cast for non-ARC
+	image = [[NSWorkspace sharedWorkspace] iconForFile:(NSString *)~fexe];
+
+#ifdef MAC_OS_X_VERSION_10_10
     NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithCGContext:cg flipped:YES];
+#else
+    // macOS 10.6-10.9: use graphicsContextWithGraphicsPort:flipped:
+    NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithGraphicsPort:cg flipped:YES];
+#endif
     NSGraphicsContext* cgc = [NSGraphicsContext currentContext];
     [NSGraphicsContext setCurrentContext:gc];
+#ifdef MAC_OS_X_VERSION_10_9
     [image drawInRect:NSMakeRect(0, 0, DPI(16), DPI(16))];
+#else
+    // macOS 10.6-10.8: drawInRect: without extra params not available
+    [image drawInRect:NSMakeRect(0, 0, DPI(16), DPI(16)) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
+#endif
 	[NSGraphicsContext setCurrentContext:cgc];
 	
 	return iw;
diff --git a/uppsrc/CtrlCore/CocoMM.h b/uppsrc/CtrlCore/CocoMM.h
index 900081660..51f21938d 100644
--- a/uppsrc/CtrlCore/CocoMM.h
+++ b/uppsrc/CtrlCore/CocoMM.h
@@ -5,6 +5,13 @@
 
 #if defined(PLATFORM_COCOA) && !defined(VIRTUALGUI)
 
+// Disable old-style Carbon assertion macros (check, verify, require, etc.)
+// to avoid conflicts with identifiers in U++ code (e.g., IMAGE_ID(check))
+// See: https://github.com/opencv/opencv/issues/6047
+#ifndef __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES
+#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
+#endif
+
 #define Point NS_Point
 #define Rect  NS_Rect
 #define Size  NS_Size
@@ -13,6 +20,112 @@
 #undef  Rect
 #undef  Size
 
+// macOS 10.6 SDK compatibility - modern names for older constants
+#ifndef MAC_OS_X_VERSION_10_12
+  #define NSEventModifierFlagShift     NSShiftKeyMask
+  #define NSEventModifierFlagControl   NSControlKeyMask
+  #define NSEventModifierFlagOption    NSAlternateKeyMask
+  #define NSEventModifierFlagCommand   NSCommandKeyMask
+  #define NSEventModifierFlagCapsLock  NSAlphaShiftKeyMask
+  #define NSEventModifierFlagNumericPad NSNumericPadKeyMask
+
+  #define NSEventTypeKeyDown           NSKeyDown
+  #define NSEventTypeKeyUp             NSKeyUp
+  #define NSEventTypeFlagsChanged      NSFlagsChanged
+  #define NSEventTypeLeftMouseDown     NSLeftMouseDown
+  #define NSEventTypeLeftMouseUp       NSLeftMouseUp
+  #define NSEventTypeRightMouseDown    NSRightMouseDown
+  #define NSEventTypeRightMouseUp      NSRightMouseUp
+  #define NSEventTypeOtherMouseDown    NSOtherMouseDown
+  #define NSEventTypeOtherMouseUp      NSOtherMouseUp
+  #define NSEventTypeLeftMouseDragged  NSLeftMouseDragged
+  #define NSEventTypeRightMouseDragged NSRightMouseDragged
+  #define NSEventTypeOtherMouseDragged NSOtherMouseDragged
+  #define NSEventTypeMouseMoved        NSMouseMoved
+  #define NSEventTypeScrollWheel       NSScrollWheel
+  #define NSEventTypeMouseEntered      NSMouseEntered
+  #define NSEventTypeMouseExited       NSMouseExited
+  #define NSEventTypeApplicationDefined NSApplicationDefined
+
+  #define NSWindowStyleMaskTitled      NSTitledWindowMask
+  #define NSWindowStyleMaskClosable    NSClosableWindowMask
+  #define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
+  #define NSWindowStyleMaskResizable   NSResizableWindowMask
+  #define NSWindowStyleMaskBorderless  NSBorderlessWindowMask
+
+  #define NSEventMaskAny               NSAnyEventMask
+  #define NSEventMaskLeftMouseDown     NSLeftMouseDownMask
+
+  // NSControlSize constants renamed in 10.12
+  #define NSControlSizeRegular         NSRegularControlSize
+  #define NSControlSizeSmall           NSSmallControlSize
+  #define NSControlSizeMini            NSMiniControlSize
+
+  // NSButtonType constants renamed in 10.12
+  #define NSButtonTypeMomentaryLight       NSMomentaryLightButton
+  #define NSButtonTypePushOnPushOff        NSPushOnPushOffButton
+  #define NSButtonTypeToggle               NSToggleButton
+  #define NSButtonTypeSwitch               NSSwitchButton
+  #define NSButtonTypeRadio                NSRadioButton
+  #define NSButtonTypeMomentaryChange      NSMomentaryChangeButton
+  #define NSButtonTypeOnOff                NSOnOffButton
+  #define NSButtonTypeMomentaryPushIn      NSMomentaryPushInButton
+
+  // NSBezelStyle constants renamed in 10.12
+  #define NSBezelStyleRounded              NSRoundedBezelStyle
+  #define NSBezelStyleRegularSquare        NSRegularSquareBezelStyle
+  #define NSBezelStyleShadowlessSquare     NSShadowlessSquareBezelStyle
+  #define NSBezelStyleSmallSquare          NSSmallSquareBezelStyle
+  #define NSBezelStyleRoundedDisclosure    NSRoundedDisclosureBezelStyle
+  #define NSBezelStyleInline               NSInlineBezelStyle
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_9
+  #define NSModalResponseOK            NSOKButton
+  #define NSModalResponseCancel        NSCancelButton
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_13
+  #define NSControlStateValueOn        NSOnState
+  #define NSControlStateValueOff       NSOffState
+  #define NSControlStateValueMixed     NSMixedState
+#endif
+
+// macOS 10.7+ scroller styles - not available on 10.6
+#ifndef MAC_OS_X_VERSION_10_7
+  #define NSScrollerStyleLegacy        0
+  #define NSScrollerStyleOverlay       1
+  #define NSScrollerKnobStyleDefault   0
+  #define NSScrollerKnobStyleDark      1
+  #define NSScrollerKnobStyleLight     2
+#endif
+
+// NSControlStateValue type alias (was NSInteger before 10.10)
+#ifndef MAC_OS_X_VERSION_10_10
+  typedef NSInteger NSControlStateValue;
+#endif
+
+// Helper function: Convert NSColor to CGColorRef (for 10.6 compatibility)
+// NSColor.CGColor property not available until macOS 10.8
+inline CGColorRef NSColorToCGColor(NSColor *nscolor) {
+    NSColor *rgbColor = [nscolor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
+    if(!rgbColor)
+        rgbColor = [nscolor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
+    if(!rgbColor) {
+        CGFloat components[4] = {1.0, 1.0, 1.0, 1.0};
+        CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+        CGColorRef cgColor = CGColorCreate(colorSpace, components);
+        CGColorSpaceRelease(colorSpace);
+        return cgColor;
+    }
+    CGFloat components[4];
+    [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+    CGColorRef cgColor = CGColorCreate(colorSpace, components);
+    CGColorSpaceRelease(colorSpace);
+    return cgColor;
+}
+
 #endif
 
 #include "CtrlCore.h"
@@ -80,20 +193,43 @@ NSRect DesktopRect(const Upp::Rect& r);
 
 }
 
+// Use objc_setAssociatedObject/objc_getAssociatedObject to store data
+// This avoids GCC ObjC runtime issues with ivars
+#import <objc/runtime.h>
+
+// Keys for associated objects - declared extern, defined in CocoProc.mm
+// Must be unique addresses across all translation units
+extern char CocoViewCtrlKey;
+extern char CocoWindowCtrlKey;
+extern char CocoWindowActiveKey;
+extern char CocoMenuItemBarKey;
+
 @interface CocoView : NSView <NSWindowDelegate, NSTextInputClient>
-{
-	@public
-	Upp::Ptr<Upp::Ctrl> ctrl;
-}
 @end
 
-@interface CocoWindow : NSWindow
-{
-	@public
-	Upp::Ptr<Upp::Ctrl> ctrl;
-	bool active;
+// Use NSWindow directly - GCC ObjC runtime has issues with subclassing
+// canBecomeKeyWindow/canBecomeMainWindow are handled via method swizzling in CocoWin.mm
+typedef NSWindow CocoWindow;
+
+// Helper functions to get/set associated ctrl pointer
+inline Upp::Ctrl* CocoViewGetCtrl(CocoView *view) {
+	return (Upp::Ctrl*)objc_getAssociatedObject(view, &CocoViewCtrlKey);
+}
+inline void CocoViewSetCtrl(CocoView *view, Upp::Ctrl *c) {
+	objc_setAssociatedObject(view, &CocoViewCtrlKey, (id)c, OBJC_ASSOCIATION_ASSIGN);
+}
+inline Upp::Ctrl* CocoWindowGetCtrl(CocoWindow *win) {
+	return (Upp::Ctrl*)objc_getAssociatedObject(win, &CocoWindowCtrlKey);
+}
+inline void CocoWindowSetCtrl(CocoWindow *win, Upp::Ctrl *c) {
+	objc_setAssociatedObject(win, &CocoWindowCtrlKey, (id)c, OBJC_ASSOCIATION_ASSIGN);
+}
+inline bool CocoWindowGetActive(CocoWindow *win) {
+	return objc_getAssociatedObject(win, &CocoWindowActiveKey) != nil;
+}
+inline void CocoWindowSetActive(CocoWindow *win, bool a) {
+	objc_setAssociatedObject(win, &CocoWindowActiveKey, a ? (id)1 : nil, OBJC_ASSOCIATION_ASSIGN);
 }
-@end
 
 struct Upp::MMCtrl {
 	static void SyncRect(CocoView *view);
diff --git a/uppsrc/CtrlCore/CocoProc.mm b/uppsrc/CtrlCore/CocoProc.mm
index 84d0ad282..ace03c742 100644
--- a/uppsrc/CtrlCore/CocoProc.mm
+++ b/uppsrc/CtrlCore/CocoProc.mm
@@ -2,6 +2,12 @@
 
 #ifdef GUI_COCOA
 
+// Define associated object keys - declared extern in CocoMM.h
+char CocoViewCtrlKey;
+char CocoWindowCtrlKey;
+char CocoWindowActiveKey;
+char CocoMenuItemBarKey;
+
 NSEvent *sCurrentMouseEvent__; // needed for drag operation
 
 #define LLOG(x) // DLOG(x)
@@ -15,9 +21,12 @@ static Upp::Ptr<Upp::Ctrl> coco_capture;
 Upp::Ptr<Upp::Ctrl> Upp::Ctrl::lastActive;
 
 namespace Upp {
-	
+
 extern id menubar;
 
+// Declared in CocoApp.mm - syncs popup focus on mouse events
+void SyncPopupFocus(NSWindow *win);
+
 bool  GetShift() { return coco_flags & NSEventModifierFlagShift; }
 bool  GetCtrl() { return coco_flags & NSEventModifierFlagCommand; }
 bool  GetAlt() { return coco_flags & NSEventModifierFlagControl; }
@@ -101,7 +110,8 @@ struct MMImp {
 	
 	static bool MouseEvent(CocoView *view, NSEvent *e, int event, double zd = 0)
 	{
-		if(!view->ctrl)
+		Ctrl *ctrl = CocoViewGetCtrl(view);
+		if(!ctrl)
 			return false;
 		Flags(e);
 		sCurrentMouseEvent__ = e;
@@ -123,7 +133,7 @@ struct MMImp {
 			}
 		}
 		NSPoint np = [view convertPoint:[e locationInWindow] fromView:nil];
-		Rect r = view->ctrl->GetRect();
+		Rect r = ctrl->GetRect();
 		Upp::Point p(DPI(np.x), DPI(np.y));
 		coco_mouse_pos = p + r.TopLeft();
 
@@ -139,7 +149,9 @@ struct MMImp {
 				coco_capture->DispatchMouse(event, coco_mouse_pos - coco_capture->GetScreenRect().TopLeft(), 120 * sgn(zd));
 			else {
 				Vector<Ctrl *> t = Ctrl::GetTopCtrls(); // Find window that contains the mouse, from the top
-				for(NSNumber *num in [NSWindow windowNumbersWithOptions:0]) { // All app windows
+				NSArray *windowNumbers = [NSWindow windowNumbersWithOptions:0]; // All app windows
+				for(NSUInteger i = 0; i < [windowNumbers count]; i++) {
+					NSNumber *num = [windowNumbers objectAtIndex:i];
 					NSWindow *win = [NSApp windowWithWindowNumber:[num integerValue]];
 					if(win) {
 					    int q = FindMatch(t, [&](Ctrl *t) { return t->GetNSWindow() == win; });
@@ -156,21 +168,24 @@ struct MMImp {
 			}
 		}
 		else
-		if(view->ctrl->IsEnabled() && (view->ctrl->HasWndCapture() || r.Contains(coco_mouse_pos))) {
-	        if((event & Ctrl::ACTION) == Ctrl::DOWN && !view->ctrl->HasFocusDeep() && view->ctrl->IsWantFocus())
-	            view->ctrl->SetFocus();
-			view->ctrl->DispatchMouse(event, p, 120 * sgn(zd));
+		if(ctrl->IsEnabled() && (ctrl->HasWndCapture() || r.Contains(coco_mouse_pos))) {
+	        if((event & Ctrl::ACTION) == Ctrl::DOWN && !ctrl->HasFocusDeep() && ctrl->IsWantFocus())
+	            ctrl->SetFocus();
+			ctrl->DispatchMouse(event, p, 120 * sgn(zd));
 		}
-		
+
 		sCurrentMouseEvent__ = NULL;
 		return false;
 	}
 
 	static bool MouseDownEvent(CocoView *view, NSEvent *e, int button)
 	{
-		if(!view->ctrl)
+		Ctrl *ctrl = CocoViewGetCtrl(view);
+		if(!ctrl)
 			return false;
-		Upp::Ctrl::lastActive = view->ctrl;
+		// Sync popup focus on mouse down (replaces block-based event monitor for GCC)
+		SyncPopupFocus([e window]);
+		Upp::Ctrl::lastActive = ctrl;
 		if(Ctrl::ignoremouseup) {
 			Ctrl::KillRepeat();
 			Ctrl::ignoreclick = false;
@@ -212,8 +227,8 @@ struct MMImp {
 		Flags(e);
 		if(!ctrl->IsEnabled())
 			return false;
-		Upp::dword k = e.keyCode;
-		WString x = ToWString((CFStringRef)(e.charactersIgnoringModifiers));
+		Upp::dword k = [e keyCode];
+		WString x = ToWString((CFStringRef)([e charactersIgnoringModifiers]));
 		if(x.GetCount() == 1)
 			switch(ToUpper(x[0])) {
 			#define KEY(c) case #c[0]: k = kVK_ANSI_##c; break;
@@ -234,15 +249,15 @@ struct MMImp {
 		if(GetOption())
 			k |= K_OPTION;
 		
-		if(e.keyCode == kVK_Help) // TODO: This is Insert key, but all this is dubious
+		if([e keyCode] == kVK_Help) // TODO: This is Insert key, but all this is dubious
 			ctrl->DispatchKey(k & ~K_KEYUP, 1);
 
 		ctrl->DispatchKey(k, 1);
 		if(!up && !(k & (K_CTRL|K_ALT))) {
-			WString x = ToWString((CFStringRef)(e.characters));
-			if(e.keyCode == kVK_ANSI_KeypadEnter && *x != 13)
+			WString x = ToWString((CFStringRef)([e characters]));
+			if([e keyCode] == kVK_ANSI_KeypadEnter && *x != 13)
 				ctrl->DispatchKey(13, 1);
-			if(e.keyCode == kVK_Space && !(k & K_SHIFT))
+			if([e keyCode] == kVK_Space && !(k & K_SHIFT))
 				ctrl->DispatchKey(' ', 1);
 		}
 		return true;
@@ -335,9 +350,10 @@ struct MMImp {
 	static void PreeditText(Ctrl *ctrl, const WString& s)
 	{
 		if(ctrl)
-			for(Upp::wchar ch : s)
+			for(Upp::wchar ch : s) {
 				if(ch >= 32 && ch != 127 && ch != ' ')
 					ctrl->DispatchKey(ch, 1);
+			}
 	}
 	
 	static void CancelPreedit()
@@ -346,6 +362,9 @@ struct MMImp {
 	}
 };
 
+// Forward declaration for menu action handler (defined in MacMenu.mm)
+void CocoMenuBarAction(void *bar, id sender);
+
 };
 
 @implementation CocoView
@@ -356,9 +375,18 @@ struct MMImp {
 
 -(void)drawRect:(NSRect)r {
 	Upp::GuiLock __;
-	if(ctrl) {
-		Upp::SystemDraw w([[NSGraphicsContext currentContext] CGContext], self);
-		Upp::MMImp::Paint(ctrl, w, MakeRect(r, Upp::DPI(1)));
+	Upp::Ctrl *c = CocoViewGetCtrl(self);
+	if(c) {
+#ifdef MAC_OS_X_VERSION_10_10
+		CGContextRef cg = [[NSGraphicsContext currentContext] CGContext];
+#else
+		// macOS 10.6-10.9: use graphicsPort instead of CGContext
+		CGContextRef cg = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+#endif
+		Upp::SystemDraw w(cg, self);
+		// Convert NSRect to CGRect for MakeRect
+		CGRect cgr = CGRectMake(r.origin.x, r.origin.y, r.size.width, r.size.height);
+		Upp::MMImp::Paint(c, w, MakeRect(cgr, Upp::DPI(1)));
 	}
 }
 
@@ -373,7 +401,7 @@ struct MMImp {
 	Upp::GuiLock __;
 	int m = decode([e buttonNumber], 3, Upp::K_MOUSE_BACKWARD, 4, Upp::K_MOUSE_FORWARD, 0);
 	if(m)
-		Upp::MMImp::DispatchKey(ctrl, m);
+		Upp::MMImp::DispatchKey(CocoViewGetCtrl(self), m);
 	else
 		[super otherMouseDown:e];
 }
@@ -423,20 +451,40 @@ struct MMImp {
 
 - (void)keyDown:(NSEvent *)e {
 	Upp::GuiLock __;
-    [self interpretKeyEvents: [NSArray arrayWithObject: e]];
-	if(!Upp::MMImp::KeyEvent(ctrl, e, 0))
+	NSString *chars = [e characters];
+
+	// On macOS 10.6, interpretKeyEvents may not call insertText for simple characters
+	// So we handle character input directly here for printable characters
+	if(chars && [chars length] > 0) {
+		unichar ch = [chars characterAtIndex:0];
+		// Check if it's a printable character (not a control character)
+		// and no command key is pressed
+		if(ch >= 32 && ch != 127 && !([e modifierFlags] & NSEventModifierFlagCommand)) {
+			Upp::Ctrl *ctrl = CocoViewGetCtrl(self);
+			if(ctrl) {
+				// Dispatch the character directly using MMImp helper (DispatchKey is private)
+				Upp::MMImp::DispatchKey(ctrl, ch);
+			}
+		}
+	}
+
+	// Still call interpretKeyEvents for IME support
+	[self interpretKeyEvents: [NSArray arrayWithObject: e]];
+
+	// And KeyEvent for special keys (arrows, function keys, etc.)
+	if(!Upp::MMImp::KeyEvent(CocoViewGetCtrl(self), e, 0))
 		[super keyDown:e];
 }
 
 - (void)keyUp:(NSEvent *)e {
 	Upp::GuiLock __;
-	if(!Upp::MMImp::KeyEvent(ctrl, e, Upp::K_KEYUP))
+	if(!Upp::MMImp::KeyEvent(CocoViewGetCtrl(self), e, Upp::K_KEYUP))
 			[super keyUp:e];
 }
 
 - (void)flagsChanged:(NSEvent *)e {
 	Upp::GuiLock __;
-	if(!Upp::MMImp::KeyFlags(ctrl, e))
+	if(!Upp::MMImp::KeyFlags(CocoViewGetCtrl(self), e))
 		[super flagsChanged:e];
 }
 
@@ -446,10 +494,12 @@ struct MMImp {
 	Upp::MMImp::DoCursorShape();
 }
 
-- (BOOL)windowShouldClose:(NSWindow *)sender {
+// Use 'id' type for sender to match NSWindowDelegate protocol (pre-10.7)
+- (BOOL)windowShouldClose:(id)sender {
 	Upp::GuiLock __;
-	if(ctrl->IsEnabled())
-		Upp::MMImp::DoClose(ctrl);
+	Upp::Ctrl *c = CocoViewGetCtrl(self);
+	if(c && c->IsEnabled())
+		Upp::MMImp::DoClose(c);
 	return NO;
 }
 
@@ -465,12 +515,12 @@ struct MMImp {
 
 - (void)windowDidBecomeKey:(NSNotification *)notification {
 	Upp::GuiLock __;
-	Upp::MMImp::BecomeKey(ctrl);
+	Upp::MMImp::BecomeKey(CocoViewGetCtrl(self));
 }
 
 - (void)windowDidResignKey:(NSNotification *)notification {
 	Upp::GuiLock __;
-	Upp::MMImp::ResignKey(ctrl);
+	Upp::MMImp::ResignKey(CocoViewGetCtrl(self));
 }
 
 - (BOOL)acceptsFirstResponder {
@@ -479,46 +529,52 @@ struct MMImp {
 
 - (BOOL)canBecomeKeyView {
 	Upp::GuiLock __;
-	return ctrl->IsEnabled();
+	Upp::Ctrl *c = CocoViewGetCtrl(self);
+	return c && c->IsEnabled();
 }
 
 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
 {
 	Upp::GuiLock __;
-	return Upp::MMImp::DnD(ctrl, sender);
+	return Upp::MMImp::DnD(CocoViewGetCtrl(self), sender);
 }
 
 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
 {
 	Upp::GuiLock __;
-	return Upp::MMImp::DnD(ctrl, sender);
+	return Upp::MMImp::DnD(CocoViewGetCtrl(self), sender);
 }
 
 - (void)draggingEnded:(id <NSDraggingInfo>)sender
 {
 	Upp::GuiLock __;
-	Upp::MMImp::DnDLeave(ctrl);
+	Upp::MMImp::DnDLeave(CocoViewGetCtrl(self));
 }
 
 - (void)draggingExited:(id <NSDraggingInfo>)sender
 {
 	Upp::GuiLock __;
-	Upp::MMImp::DnDLeave(ctrl);
+	Upp::MMImp::DnDLeave(CocoViewGetCtrl(self));
 }
 
 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
 {
 	Upp::GuiLock __;
-	return Upp::MMImp::DnD(ctrl, sender, true) != NSDragOperationNone;
+	return Upp::MMImp::DnD(CocoViewGetCtrl(self), sender, true) != NSDragOperationNone;
 }
 
 - (void)updateTrackingAreas
 {
 	Upp::GuiLock __;
-	for(NSTrackingArea *t in [self trackingAreas])
+	NSArray *areas = [self trackingAreas];
+	for(NSUInteger i = 0; i < [areas count]; i++) {
+		NSTrackingArea *t = [areas objectAtIndex:i];
 		[self removeTrackingArea:t];
+	}
 
-	Upp::Size sz = ctrl->GetScreenRect().GetSize();
+	Upp::Ctrl *c = CocoViewGetCtrl(self);
+	if(!c) return;
+	Upp::Size sz = c->GetScreenRect().GetSize();
 	NSTrackingArea *ta = [[NSTrackingArea alloc]
 		initWithRect:NSMakeRect(0, 0, sz.cx, sz.cy)
 	         options:NSTrackingMouseEnteredAndExited|NSTrackingActiveAlways|
@@ -539,7 +595,7 @@ struct MMImp {
     NSString* pInsert = [aString isMemberOfClass: [NSAttributedString class]] ? [aString string] : aString;
 
 	if(pInsert)
-		Upp::MMImp::PreeditText(ctrl, Upp::ToWString(pInsert));
+		Upp::MMImp::PreeditText(CocoViewGetCtrl(self), Upp::ToWString(pInsert));
 }
 
 - (NSRange)markedRange
@@ -555,7 +611,7 @@ struct MMImp {
 - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
 {
 	Upp::GuiLock __;
-	return Upp::MMImp::PreeditRect(ctrl);
+	return Upp::MMImp::PreeditRect(CocoViewGetCtrl(self));
 }
 
 - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange
@@ -564,7 +620,7 @@ struct MMImp {
     if(![aString isKindOfClass:[NSAttributedString class]] )
         aString = [[[NSAttributedString alloc] initWithString:aString] autorelease];
 
-	Upp::MMImp::ShowPreedit(ctrl, Upp::ToWString([aString string]));
+	Upp::MMImp::ShowPreedit(CocoViewGetCtrl(self), Upp::ToWString([aString string]));
 }
 
 - (BOOL)hasMarkedText
@@ -597,6 +653,26 @@ struct MMImp {
 	return 0;
 }
 
+- (void)doCommandBySelector:(SEL)aSelector
+{
+	// Required by NSTextInputClient protocol
+	// Do nothing - U++ handles key events directly
+}
+
+// Menu action handler - called when menu items with nil target are clicked
+// This is in the responder chain as the first responder (key window's content view)
+- (void)cocoMenuAction:(id)sender
+{
+	Upp::GuiLock __;
+	NSMenuItem *item = (NSMenuItem *)sender;
+	// Get the bar pointer from the menu item's associated object
+	void *barPtr = objc_getAssociatedObject(item, &CocoMenuItemBarKey);
+	if(barPtr) {
+		// Forward to the Upp menu action handler (defined in MacMenu.mm)
+		Upp::CocoMenuBarAction(barPtr, sender);
+	}
+}
+
 @end
 
 #endif
diff --git a/uppsrc/CtrlCore/CocoWin.mm b/uppsrc/CtrlCore/CocoWin.mm
index 1323964ba..9ab967708 100644
--- a/uppsrc/CtrlCore/CocoWin.mm
+++ b/uppsrc/CtrlCore/CocoWin.mm
@@ -4,32 +4,85 @@
 
 #define LLOG(x)
 
-@implementation CocoWindow
+// Method swizzling for NSWindow to override canBecomeKeyWindow/canBecomeMainWindow
+// This avoids subclassing NSWindow which causes crashes with GCC's ObjC runtime
 
-- (void)becomeKeyWindow {
-	[super becomeKeyWindow];
-}
+static IMP sOriginalCanBecomeKeyWindow = NULL;
+static IMP sOriginalCanBecomeMainWindow = NULL;
 
-- (BOOL)canBecomeKeyWindow {
-	Upp::GuiLock __;
-    return active && ctrl && ctrl->IsEnabled();
+// Replacement for canBecomeKeyWindow - checks if our Ctrl is enabled
+// Note: The 'active' flag is only used for popup menus/tooltips that should never become key
+// Dialogs (TopWindow) should always be able to become key if enabled
+static BOOL Swizzled_canBecomeKeyWindow(id self, SEL _cmd)
+{
+	Upp::Ctrl *ctrl = CocoWindowGetCtrl((CocoWindow*)self);
+	// If this is our window, use our logic
+	if(ctrl) {
+		Upp::GuiLock __;
+		// Check if it's a TopWindow (dialog) - these should always be able to become key if enabled
+		// PopUp windows (menus, tooltips) have active=false and should not become key
+		bool active = CocoWindowGetActive((CocoWindow*)self);
+		Upp::TopWindow *tw = dynamic_cast<Upp::TopWindow*>(ctrl);
+		bool isTopWindow = (tw != NULL);
+		BOOL result = (active || isTopWindow) && ctrl->IsEnabled();
+		NSLog(@"canBecomeKeyWindow: ctrl=%p active=%d tw=%p isTopWindow=%d enabled=%d result=%d",
+		      ctrl, (int)active, tw, (int)isTopWindow, (int)ctrl->IsEnabled(), (int)result);
+		return result;
+	}
+	// Otherwise call original
+	NSLog(@"canBecomeKeyWindow: no ctrl, calling original");
+	if(sOriginalCanBecomeKeyWindow)
+		return ((BOOL(*)(id, SEL))sOriginalCanBecomeKeyWindow)(self, _cmd);
+	return YES; // NSWindow default
 }
 
-- (BOOL)canBecomeMainWindow {
-	Upp::GuiLock __;
-	LLOG("canBecomeMainWindow " << Upp::Name(ctrl) << ", owner " << Upp::Name(ctrl->GetOwner()));
-	return active && ctrl && ctrl->IsEnabled() && dynamic_cast<Upp::TopWindow *>(~ctrl) && !ctrl->GetOwner();
+// Replacement for canBecomeMainWindow - checks if TopWindow without owner
+static BOOL Swizzled_canBecomeMainWindow(id self, SEL _cmd)
+{
+	Upp::Ctrl *ctrl = CocoWindowGetCtrl((CocoWindow*)self);
+	// If this is our window, use our logic
+	if(ctrl) {
+		Upp::GuiLock __;
+		// Main window must be a TopWindow, enabled, and without owner
+		// The 'active' flag is not relevant for main window status
+		Upp::TopWindow *tw = dynamic_cast<Upp::TopWindow *>(ctrl);
+		return tw && ctrl->IsEnabled() && !ctrl->GetOwner();
+	}
+	// Otherwise call original
+	if(sOriginalCanBecomeMainWindow)
+		return ((BOOL(*)(id, SEL))sOriginalCanBecomeMainWindow)(self, _cmd);
+	return YES; // NSWindow default
 }
 
-- (NSMenu *)applicationDockMenu:(NSApplication *)sender {
-	Upp::GuiLock __;
-	NSMenu *menu = [[[NSMenu alloc] initWithTitle:@"DocTile Menu"] autorelease];
-	NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:@"Hello" action:@selector(hello) keyEquivalent:@"k"] autorelease];
-	[menu addItem:item];
-	return menu;
-}
+static void SwizzleNSWindowMethods()
+{
+	static bool swizzled = false;
+	if(swizzled) return;
+	swizzled = true;
+
+	NSLog(@"SwizzleNSWindowMethods: swizzling NSWindow methods");
+	Class windowClass = [NSWindow class];
+
+	// Swizzle canBecomeKeyWindow
+	Method origKey = class_getInstanceMethod(windowClass, @selector(canBecomeKeyWindow));
+	if(origKey) {
+		sOriginalCanBecomeKeyWindow = method_getImplementation(origKey);
+		method_setImplementation(origKey, (IMP)Swizzled_canBecomeKeyWindow);
+		NSLog(@"SwizzleNSWindowMethods: canBecomeKeyWindow swizzled, orig=%p new=%p", sOriginalCanBecomeKeyWindow, Swizzled_canBecomeKeyWindow);
+	} else {
+		NSLog(@"SwizzleNSWindowMethods: canBecomeKeyWindow NOT FOUND");
+	}
 
-@end
+	// Swizzle canBecomeMainWindow
+	Method origMain = class_getInstanceMethod(windowClass, @selector(canBecomeMainWindow));
+	if(origMain) {
+		sOriginalCanBecomeMainWindow = method_getImplementation(origMain);
+		method_setImplementation(origMain, (IMP)Swizzled_canBecomeMainWindow);
+		NSLog(@"SwizzleNSWindowMethods: canBecomeMainWindow swizzled");
+	} else {
+		NSLog(@"SwizzleNSWindowMethods: canBecomeMainWindow NOT FOUND");
+	}
+}
 
 namespace Upp {
 
@@ -46,9 +99,11 @@ Ctrl *Ctrl::GetOwner()
 Ctrl *Ctrl::GetActiveCtrl()
 {
 	GuiLock __;
-	for(Ctrl *p : mmtopctrl)
-		if(p && p->top && p->GetTop()->coco && p->GetTop()->coco->window.keyWindow)
+	for(int i = 0; i < mmtopctrl.GetCount(); i++) {
+		Ctrl *p = mmtopctrl[i];
+		if(p && p->top && p->GetTop()->coco && [p->GetTop()->coco->window isKeyWindow])
 			return p;
+	}
 	return lastActive;
 }
 
@@ -110,6 +165,9 @@ void Ctrl::DoCancelPreedit()
 void Ctrl::Create(Ctrl *owner, dword style, bool active)
 {
 	cancel_preedit = DoCancelPreedit; // We really need this just once, but whatever..
+
+	// Swizzle NSWindow methods for canBecomeKeyWindow/canBecomeMainWindow (GCC compatibility)
+	SwizzleNSWindowMethods();
 	
 	if(owner)
 		owner = owner->GetTopCtrl();
@@ -125,20 +183,23 @@ void Ctrl::Create(Ctrl *owner, dword style, bool active)
 	if(owner && owner->top && owner->GetTop()->coco)
 		[owner->GetTop()->coco->window addChildWindow:window ordered:NSWindowAbove];
 
-	window->ctrl = this;
-	window->active = active;
-	window.backgroundColor = [NSColor clearColor];
+	CocoWindowSetCtrl(window, this);
+	CocoWindowSetActive(window, active);
+	[window setBackgroundColor:[NSColor clearColor]];
 
 	isopen = true;
-		
+
 	CocoView *view = [[[CocoView alloc] initWithFrame:frame] autorelease];
-	view->ctrl = this;
+	CocoViewSetCtrl(view, this);
 	GetTop()->coco->view = view;
 	[window setContentView:view];
 	[window setDelegate:view];
 	[window setAcceptsMouseMovedEvents:YES];
-	[window makeFirstResponder:view];
+	BOOL frResult = [window makeFirstResponder:view];
+	NSLog(@"Create: window=%p view=%p makeFirstResponder=%d", window, view, (int)frResult);
 	[window makeKeyAndOrderFront:window];
+	NSLog(@"Create: after makeKeyAndOrderFront, isKeyWindow=%d firstResponder=%p",
+	      (int)[window isKeyWindow], [window firstResponder]);
 	
 	ONCELOCK {
 		[NSApp activateIgnoringOtherApps:YES];
@@ -155,6 +216,9 @@ void Ctrl::Create(Ctrl *owner, dword style, bool active)
 void Ctrl::WndDestroy()
 {
 	LLOG("WndDestroy " << Name());
+	NSLog(@"WndDestroy: ctrl=%p window=%p isTopWindow=%d",
+	      this, top ? GetTop()->coco->window : nil,
+	      dynamic_cast<TopWindow*>(this) != NULL);
 	if(!top)
 		return;
 	bool focus = HasFocusDeep();
@@ -163,9 +227,36 @@ void Ctrl::WndDestroy()
 	auto* coco = GetTop()->coco;
 	auto* window = coco->window;
 
-	[window setCollectionBehavior:NSWindowCollectionBehaviorTransient];
+	NSLog(@"WndDestroy: before close, window=%p isVisible=%d retainCount=%lu parentWindow=%p",
+	      window, (int)[window isVisible], (unsigned long)[window retainCount], [window parentWindow]);
+
+	// Remove from parent window's child list first
+	NSWindow *parent = [window parentWindow];
+	if(parent) {
+		NSLog(@"WndDestroy: removing from parent window %p", parent);
+		[parent removeChildWindow:window];
+	}
+
+	// Clear the delegate to prevent callbacks during close
+	[window setDelegate:nil];
+
+	// Clear the content view's ctrl reference to prevent further callbacks
+	CocoViewSetCtrl(coco->view, NULL);
+
+	// On macOS 10.6, we need to ensure the window is truly hidden
+	// setContentView:nil helps force release of the view
+	[window setContentView:nil];
+
+	// Order out and close
+	[window orderOut:nil];
+
+	// Force display update to ensure window disappears immediately
+	[window display];
+
 	[window close];
 
+	NSLog(@"WndDestroy: after close, isVisible=%d", (int)[window isVisible]);
+
 	delete coco;
 	DeleteTop();
 
@@ -191,7 +282,8 @@ void Ctrl::WndInvalidateRect(const Rect& r)
 {
 	GuiLock __;
 	if(top) {
-		NSRect nsr = (NSRect)CGRectDPI(r.Inflated(10, 10));
+		CGRect cgr = CGRectDPI(r.Inflated(10, 10));
+		NSRect nsr = NSMakeRect(cgr.origin.x, cgr.origin.y, cgr.size.width, cgr.size.height);
 		if(IsMainThread())
 			[GetTop()->coco->view setNeedsDisplayInRect:nsr];
 		else {
@@ -304,7 +396,8 @@ void TopWindow::SyncCaption()
 		SyncTitle();
 		NSWindow* window = GetTop()->coco->window;
 
-		NSWindowStyleMask mask = [window styleMask];
+		// NSWindowStyleMask is typedef'd in 10.12+; use NSUInteger for 10.6 compatibility
+		NSUInteger mask = [window styleMask];
 		mask = minimizebox ? (mask | NSWindowStyleMaskMiniaturizable)
 		                   : (mask & ~NSWindowStyleMaskMiniaturizable);
 		mask = maximizebox ? (mask | NSWindowStyleMaskResizable)
@@ -318,8 +411,9 @@ void TopWindow::SyncCaption()
 CGSize MMFrameSize(Size sz, dword style)
 {
 	double scale = 1.0 / DPI(1);
-	return [NSWindow frameRectForContentRect:
-				(NSRect)CGRectMake(100, 100, scale * sz.cx, scale * sz.cy) styleMask:style].size;
+	NSRect contentRect = NSMakeRect(100, 100, scale * sz.cx, scale * sz.cy);
+	NSRect frameRect = [NSWindow frameRectForContentRect:contentRect styleMask:style];
+	return CGSizeMake(frameRect.size.width, frameRect.size.height);
 }
 
 void TopWindow::SyncSizeHints()
@@ -329,8 +423,10 @@ void TopWindow::SyncSizeHints()
 		NSWindow *window = GetTop()->coco->window;
 		dword style = GetMMStyle();
 		Size sz = GetRect().GetSize();
-		[window setMinSize:MMFrameSize(sizeable ? GetMinSize() : sz, style)];
-		[window setMaxSize:MMFrameSize(sizeable ? GetMaxSize() : sz, style)];
+		CGSize minSz = MMFrameSize(sizeable ? GetMinSize() : sz, style);
+		CGSize maxSz = MMFrameSize(sizeable ? GetMaxSize() : sz, style);
+		[window setMinSize:NSMakeSize(minSz.width, minSz.height)];
+		[window setMaxSize:NSMakeSize(maxSz.width, maxSz.height)];
 	}
 }
 
@@ -364,7 +460,7 @@ void TopWindow::SerializePlacement(Stream& s, bool reminimize)
 void TopWindow::Maximize(bool effect)
 {
 	state = MAXIMIZED;
-	if(top && GetTop()->coco && GetTop()->coco->window && !GetTop()->coco->window.zoomed) {
+	if(top && GetTop()->coco && GetTop()->coco->window && ![GetTop()->coco->window isZoomed]) {
 		if(effect)
 			[GetTop()->coco->window performZoom:GetTop()->coco->window];
 		else
@@ -375,7 +471,7 @@ void TopWindow::Maximize(bool effect)
 void TopWindow::Minimize(bool effect)
 {
 	state = MINIMIZED;
-	if(top && GetTop()->coco && GetTop()->coco->window && !GetTop()->coco->window.miniaturized) {
+	if(top && GetTop()->coco && GetTop()->coco->window && ![GetTop()->coco->window isMiniaturized]) {
 		if(effect)
 			[GetTop()->coco->window performMiniaturize:GetTop()->coco->window];
 		else
@@ -386,15 +482,15 @@ void TopWindow::Minimize(bool effect)
 void TopWindow::Overlap(bool effect)
 {
 	state = OVERLAPPED;
-	if(top && GetTop()->coco && GetTop()->coco->window && GetTop()->coco->window.zoomed)
+	if(top && GetTop()->coco && GetTop()->coco->window && [GetTop()->coco->window isZoomed])
 		[GetTop()->coco->window zoom:GetTop()->coco->window];
-	if(top && GetTop()->coco && GetTop()->coco->window && GetTop()->coco->window.miniaturized)
+	if(top && GetTop()->coco && GetTop()->coco->window && [GetTop()->coco->window isMiniaturized])
 		[GetTop()->coco->window deminiaturize:GetTop()->coco->window];
 }
 
 bool Ctrl::IsCocoActive() const
 {
-	return top && GetTop()->coco && GetTop()->coco->window && GetTop()->coco->window->active;
+	return top && GetTop()->coco && GetTop()->coco->window && CocoWindowGetActive(GetTop()->coco->window);
 }
 
 }
diff --git a/uppsrc/CtrlLib/ChCocoMM.mm b/uppsrc/CtrlLib/ChCocoMM.mm
index 96e5b968c..4062f64bd 100644
--- a/uppsrc/CtrlLib/ChCocoMM.mm
+++ b/uppsrc/CtrlLib/ChCocoMM.mm
@@ -2,7 +2,11 @@
 
 #ifdef PLATFORM_COCOA
 
-#include <Carbon/Carbon.h> 
+// Disable old-style Carbon assertion macros (check, verify, require, etc.)
+// to avoid conflicts with identifiers in U++ code (e.g., IMAGE_ID(check))
+// See: https://github.com/opencv/opencv/issues/6047
+#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
+#include <Carbon/Carbon.h>
 
 #endif
 
@@ -12,94 +16,151 @@
 
 #include <CtrlCore/CocoMM.h>
 #include "ChCocoMM.h"
-	
-void Coco_PaintCh(void *cgcontext, int type, int value, int state)
+
+// Static helper function to perform the actual painting
+// Replaces lambda for GCC compatibility (GCC doesn't support Apple blocks)
+static void DoPaintChInternal(CGContextRef cg, int type, int value, int state)
 {
-	auto dopaint = [&] {
-		auto cg = (CGContextRef) cgcontext;
-		if(Upp::IsUHDMode())
-			CGContextScaleCTM(cg, 2, 2);
-		CGRect cr = CGRectMake(0, 0, 140, 140);
-		if(type == COCO_NSCOLOR) {
-			CGContextSaveGState(cg);
-			CGContextSetFillColorWithColor(cg, Upp::decode(value,
-				COCO_PAPER, [NSColor textBackgroundColor].CGColor,
-				COCO_SELECTEDTEXT, [NSColor selectedTextColor].CGColor,
-				COCO_SELECTEDPAPER, [NSColor selectedTextBackgroundColor].CGColor,
-				COCO_DISABLED, [NSColor disabledControlTextColor].CGColor,
-				COCO_WINDOW, [NSColor windowBackgroundColor].CGColor,
-				COCO_SELECTEDMENUTEXT, [NSColor selectedMenuItemTextColor].CGColor,
-				[NSColor textColor].CGColor
-			));
-			CGContextFillRect(cg, cr);
-			CGContextRestoreGState(cg);
+	if(Upp::IsUHDMode())
+		CGContextScaleCTM(cg, 2, 2);
+	CGRect cr = CGRectMake(0, 0, 140, 140);
+	NSRect frameRect = NSMakeRect(cr.origin.x, cr.origin.y, cr.size.width, cr.size.height);
+
+	if(type == COCO_NSCOLOR) {
+		CGContextSaveGState(cg);
+		// Use NSColorToCGColor helper for 10.6 compatibility (no .CGColor property)
+		CGColorRef fillColor;
+		NSColor *nscolor;
+		switch(value) {
+		case COCO_PAPER:
+			nscolor = [NSColor textBackgroundColor];
+			break;
+		case COCO_SELECTEDTEXT:
+			nscolor = [NSColor selectedTextColor];
+			break;
+		case COCO_SELECTEDPAPER:
+			nscolor = [NSColor selectedTextBackgroundColor];
+			break;
+		case COCO_DISABLED:
+			nscolor = [NSColor disabledControlTextColor];
+			break;
+		case COCO_WINDOW:
+			nscolor = [NSColor windowBackgroundColor];
+			break;
+		case COCO_SELECTEDMENUTEXT:
+			nscolor = [NSColor selectedMenuItemTextColor];
+			break;
+		default:
+			nscolor = [NSColor textColor];
+			break;
+		}
+		fillColor = NSColorToCGColor(nscolor);
+		CGContextSetFillColorWithColor(cg, fillColor);
+		CGColorRelease(fillColor);
+		CGContextFillRect(cg, cr);
+		CGContextRestoreGState(cg);
+	}
+	else
+	if(type == COCO_NSIMAGE) {
+		NSImage *img = [NSImage imageNamed:(value ? NSImageNameInfo : NSImageNameCaution)];
+#ifdef MAC_OS_X_VERSION_10_10
+		NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithCGContext:cg flipped:YES];
+		NSGraphicsContext *cgc = [NSGraphicsContext currentContext];
+		[NSGraphicsContext setCurrentContext:gc];
+		[img drawInRect:NSMakeRect(0, 0, 48, 48)];
+		[NSGraphicsContext setCurrentContext:cgc];
+#else
+		// macOS 10.6-10.9: use graphicsContextWithGraphicsPort:flipped:
+		NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithGraphicsPort:cg flipped:YES];
+		NSGraphicsContext *cgc = [NSGraphicsContext currentContext];
+		[NSGraphicsContext setCurrentContext:gc];
+		// drawInRect: without fromRect:operation:fraction: not available until 10.9
+		[img drawInRect:NSMakeRect(0, 0, 48, 48) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
+		[NSGraphicsContext setCurrentContext:cgc];
+#endif
+	}
+	else {
+		CGContextSaveGState(cg);
+		[NSGraphicsContext saveGraphicsState];
+#ifdef MAC_OS_X_VERSION_10_10
+		[NSGraphicsContext setCurrentContext:
+			[NSGraphicsContext graphicsContextWithCGContext:cg flipped:YES]];
+#else
+		[NSGraphicsContext setCurrentContext:
+			[NSGraphicsContext graphicsContextWithGraphicsPort:cg flipped:YES]];
+#endif
+
+		const NSRect dirtyRect = NSMakeRect(20, 20, 100, 100);
+
+		if(Upp::findarg(type, COCO_SCROLLTHUMB, COCO_SCROLLTRACK) >= 0) {
+#ifdef MAC_OS_X_VERSION_10_7
+			int cx = [NSScroller scrollerWidthForControlSize:NSControlSizeRegular scrollerStyle:NSScrollerStyleLegacy];
+#else
+			int cx = [NSScroller scrollerWidth];
+#endif
+			NSScroller *scroller = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 100, cx)];
+			[scroller setFloatValue:0];
+			[scroller setKnobProportion:1];
+#ifdef MAC_OS_X_VERSION_10_7
+			[scroller setKnobStyle:NSScrollerKnobStyleDefault];
+			[scroller setScrollerStyle:NSScrollerStyleLegacy];
+#endif
+			[scroller setFrame:frameRect];
+			if(type == COCO_SCROLLTHUMB)
+				[scroller drawKnob];
+			else
+				[scroller drawKnobSlotInRect:NSMakeRect(20, 20, 100, cx) highlight:YES];
+			[scroller release];
 		}
 		else
-		if(type == COCO_NSIMAGE) {
-			NSImage *img = [NSImage imageNamed:(value ? NSImageNameInfo : NSImageNameCaution)];
-		    NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithCGContext:cg flipped:YES];
-		    NSGraphicsContext* cgc = [NSGraphicsContext currentContext];
-		    [NSGraphicsContext setCurrentContext:gc];
-		    [img drawInRect:NSMakeRect(0, 0, 48, 48)];
-			[NSGraphicsContext setCurrentContext:cgc];
+		if(type == COCO_TEXTFIELD) {
+			NSTextField *tf = [[NSTextField alloc] init];
+			[tf setEnabled:YES];
+			[tf setEditable:YES];
+			[tf setBezeled:YES];
+			[tf setFrame:NSMakeRect(0, 0, 140, 40)];
+			[tf drawRect:dirtyRect];
+			[tf release];
 		}
 		else {
-		    CGContextSaveGState(cg);
-		    [NSGraphicsContext saveGraphicsState];
-		    [NSGraphicsContext setCurrentContext:
-				[NSGraphicsContext graphicsContextWithCGContext:cg flipped:YES]];
-		
-		    const CGRect dirtyRect = CGRectMake(20, 20, 100, 100);
-		
-			if(Upp::findarg(type, COCO_SCROLLTHUMB, COCO_SCROLLTRACK) >= 0) {
-				int cx = [NSScroller scrollerWidthForControlSize:NSControlSizeRegular scrollerStyle:NSScrollerStyleLegacy];
-				NSScroller *scroller = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 100, cx)];
-			    scroller.floatValue = 0;
-			    scroller.knobProportion = 1;
-				scroller.knobStyle = NSScrollerKnobStyleDefault;
-//				scroller.knobStyle = Upp::IsDarkTheme() ? NSScrollerKnobStyleDark : NSScrollerKnobStyleLight;
-				scroller.scrollerStyle = NSScrollerStyleLegacy;
-				scroller.frame = cr;
-				if(type == COCO_SCROLLTHUMB)
-					[scroller drawKnob];
-				else
-					[scroller drawKnobSlotInRect:CGRectMake(20, 20, 100, cx) highlight:YES];
-				[scroller release];
-			}
-			else
-			if(type == COCO_TEXTFIELD) {
-				NSTextField *tf = [[NSTextField alloc] init];
-				tf.enabled = YES;
-				tf.editable = YES;
-				tf.bezeled = YES;
-				tf.frame = CGRectMake(0, 0, 140, 40);
-				[tf drawRect:dirtyRect];
-				[tf release];
+			NSButton *bc = type == COCO_POPUPBUTTON ? [[NSPopUpButton alloc] init] : [[NSButton alloc] init];
+			[bc setAllowsMixedState:(type == COCO_CHECKBOX)];
+			[bc setTitle:@""];
+			[[bc cell] setControlSize:(type == COCO_RADIOBUTTON ? NSControlSizeSmall : NSControlSizeRegular)];
+			[bc setFrame:frameRect];
+			NSButtonType btnType;
+			switch(type) {
+			case COCO_CHECKBOX: btnType = NSButtonTypeSwitch; break;
+			case COCO_RADIOBUTTON: btnType = NSButtonTypeRadio; break;
+			default: btnType = NSButtonTypePushOnPushOff; break;
 			}
-			else {
-				NSButton *bc = type == COCO_POPUPBUTTON ? [[NSPopUpButton alloc] init] : [[NSButton alloc] init];
-				bc.allowsMixedState = type == COCO_CHECKBOX;
-				bc.title = @"";
-				bc.controlSize = type == COCO_RADIOBUTTON ? NSControlSizeSmall : NSControlSizeRegular;
-				bc.frame = cr;
-				bc.buttonType = Upp::decode(type, COCO_CHECKBOX, NSButtonTypeSwitch, COCO_RADIOBUTTON, NSButtonTypeRadio, NSButtonTypePushOnPushOff);
-				bc.bezelStyle = type == COCO_BUTTON ? NSBezelStyleRounded : NSBezelStyleRegularSquare;
-				bc.state = Upp::decode(value, 0, NSControlStateValueOff, 1, NSControlStateValueOn, NSControlStateValueMixed);
-		        [bc highlight: state == Upp::CTRL_PRESSED];
-				bc.enabled = state != Upp::CTRL_DISABLED;
-				[bc drawRect:dirtyRect];
-				[bc release];
+			[bc setButtonType:btnType];
+			[bc setBezelStyle:(type == COCO_BUTTON ? NSBezelStyleRounded : NSBezelStyleRegularSquare)];
+			NSControlStateValue stateValue;
+			switch(value) {
+			case 0: stateValue = NSControlStateValueOff; break;
+			case 1: stateValue = NSControlStateValueOn; break;
+			default: stateValue = NSControlStateValueMixed; break;
 			}
-		
-		    [NSGraphicsContext restoreGraphicsState];
-		    CGContextRestoreGState(cg);
+			[bc setState:stateValue];
+			[bc highlight:(state == Upp::CTRL_PRESSED)];
+			[bc setEnabled:(state != Upp::CTRL_DISABLED)];
+			[bc drawRect:dirtyRect];
+			[bc release];
 		}
-	};
-	if (@available(macOS 11.0, *)) {
-		[NSApp.effectiveAppearance performAsCurrentDrawingAppearance:^{ dopaint(); }];
-	} else {
-		dopaint();
+
+		[NSGraphicsContext restoreGraphicsState];
+		CGContextRestoreGState(cg);
 	}
 }
 
+void Coco_PaintCh(void *cgcontext, int type, int value, int state)
+{
+	CGContextRef cg = (CGContextRef)cgcontext;
+	// @available and performAsCurrentDrawingAppearance: require macOS 11.0+ and blocks
+	// For 10.6 compatibility with GCC, just call the paint function directly
+	// On macOS 11+ with Clang, appearance is handled automatically by the system
+	DoPaintChInternal(cg, type, value, state);
+}
+
 #endif
diff --git a/uppsrc/CtrlLib/Cocoa.mm b/uppsrc/CtrlLib/Cocoa.mm
index ae9f3ed76..95ba1b980 100644
--- a/uppsrc/CtrlLib/Cocoa.mm
+++ b/uppsrc/CtrlLib/Cocoa.mm
@@ -41,15 +41,25 @@ bool FileSelNative::Execute0(int open, const char *title)
 		}
 		if([panel runModal] == NSModalResponseOK) {
 			NSArray* urls = [panel URLs];
-			for(int i = 0; i < urls.count; i++)
-				path.Add([[urls objectAtIndex:i] fileSystemRepresentation]);
+			// Use traditional loop instead of for-in (GCC compatibility)
+			// Use [url path] then fileSystemRepresentation (NSURL method returns const char*)
+			for(NSUInteger i = 0; i < [urls count]; i++) {
+				NSURL *url = [urls objectAtIndex:i];
+				const char *fs = [[url path] fileSystemRepresentation];
+				if(fs)
+					path.Add(fs);
+			}
 		}
 	}
 	else {
 		NSSavePanel *panel = [NSSavePanel savePanel];
 		[panel setMessage:(NSString *)~mmtitle];
-		if([panel runModal] == NSModalResponseOK)
-			path.Add([[panel URL] fileSystemRepresentation]);
+		if([panel runModal] == NSModalResponseOK) {
+			NSURL *url = [panel URL];
+			const char *fs = [[url path] fileSystemRepresentation];
+			if(fs)
+				path.Add(fs);
+		}
 	}
 	return path.GetCount();
 }
diff --git a/uppsrc/CtrlLib/MacMenu.mm b/uppsrc/CtrlLib/MacMenu.mm
index 06e0959fc..092b57973 100644
--- a/uppsrc/CtrlLib/MacMenu.mm
+++ b/uppsrc/CtrlLib/MacMenu.mm
@@ -14,19 +14,50 @@ struct CocoMenuBar;
 
 };
 
-@interface CocoMenu : NSMenu<NSMenuDelegate>
-{
-@public
-	Upp::Ptr<Upp::CocoMenuBar> ptr;
-	Upp::Event<Upp::Bar&>      proc;
+// Associated object keys for menu data - defined in this file
+static char CocoMenuPtrKey;
+static char CocoMenuProcKey;
+
+// Use NSMenu directly (typedef) to avoid GCC ObjC runtime issues with subclassing
+typedef NSMenu CocoMenu;
+
+// Helper functions to get/set associated menu data
+static inline Upp::CocoMenuBar* CocoMenuGetPtr(NSMenu *menu) {
+	return (Upp::CocoMenuBar*)objc_getAssociatedObject(menu, &CocoMenuPtrKey);
+}
+static inline void CocoMenuSetPtr(NSMenu *menu, Upp::CocoMenuBar *p) {
+	objc_setAssociatedObject(menu, &CocoMenuPtrKey, (id)p, OBJC_ASSOCIATION_ASSIGN);
+}
+static inline Upp::Event<Upp::Bar&>* CocoMenuGetProc(NSMenu *menu) {
+	return (Upp::Event<Upp::Bar&>*)objc_getAssociatedObject(menu, &CocoMenuProcKey);
+}
+static inline void CocoMenuSetProc(NSMenu *menu, Upp::Event<Upp::Bar&> *p) {
+	objc_setAssociatedObject(menu, &CocoMenuProcKey, (id)p, OBJC_ASSOCIATION_ASSIGN);
 }
--(void)cocoMenuAction:(id)sender;
+
+// Associated object key for storing CocoMenuBar* on each NSMenuItem
+// NOTE: CocoMenuItemBarKey is declared extern in CocoMM.h and defined in CocoProc.mm
+// so that CocoApp.mm can use the same key for lookups
+
+// Track last selected menu item for GCC ObjC runtime workaround
+static NSMenuItem *lastSelectedMenuItem = nil;
+static BOOL menuItemWasClicked = NO;
+
+// Delegate object to handle NSMenuDelegate methods (menuWillOpen/menuDidClose)
+// Also handles menu item actions since GCC ObjC runtime doesn't dispatch action/target properly
+@interface CocoMenuDelegate : NSObject<NSMenuDelegate>
+- (void)menuItemAction:(id)sender;
+- (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item;
 @end
 
+// Global delegate instance - shared by all menus
+static CocoMenuDelegate *sharedMenuDelegate = nil;
+
 namespace Upp {
 
 struct CocoMenuBar : public Bar {
 	CocoMenu *cocomenu;
+	Event<Bar&> *proc;  // Heap-allocated to avoid C++ object in ObjC associated storage
 	int       lock = 0;
 	bool      dockmenu = false;
 	int       cy = 0; // estimate of height to place the menu correctly
@@ -58,20 +89,20 @@ struct CocoMenuBar : public Bar {
 
 		~Item() { if(nsitem) [nsitem release]; }
 	};
-	
+
 	Array<Item> item;
-	
+
 	void StartCheck() {
 		just_check = true;
 		check_i = 0;
 		is_same = true;
 	}
-	
+
 	bool CheckedIsSame() {
 		just_check = false;
 		return is_same;
 	}
-	
+
 	Item& AddItem() {
 		if(just_check) {
 			if(is_same && check_i < item.GetCount())
@@ -95,19 +126,26 @@ struct CocoMenuBar : public Bar {
 		Item& m = AddItem();
 		if(!just_check) {
 			m.cb = cb;
-			m.nsitem.target = cocomenu;
-			m.nsitem.action = @selector(cocoMenuAction:);
+			// Store bar pointer on the menu item for lookup in the action
+			objc_setAssociatedObject(m.nsitem, &CocoMenuItemBarKey, (id)this, OBJC_ASSOCIATION_ASSIGN);
+			// Use sharedMenuDelegate as target - it's an ObjC object created in this file
+			// so the selector should be properly registered with GCC ObjC runtime
+			// Note: sharedMenuDelegate is guaranteed to exist because New() creates it
+			ASSERT(sharedMenuDelegate != nil);
+			[m.nsitem setTarget:sharedMenuDelegate];
+			[m.nsitem setAction:@selector(menuItemAction:)];
 		}
 		return m;
 	}
-	
-	virtual Item&  AddSubMenu(Event<Bar&> proc) {
+
+	virtual Item&  AddSubMenu(Event<Bar&> proc_) {
 		Item& m = AddItem();
 		if(!just_check) {
 			m.submenu.Create();
-			m.submenu->cocomenu->proc = proc;
-			m.nsitem.action = @selector(cocoMenuAction:);
-			m.nsitem.submenu = m.submenu->cocomenu;
+			*m.submenu->proc = proc_;
+			// Note: submenu items don't need action/target - the submenu itself handles opening
+			// The action selector is for the submenu's delegate, not the menu item
+			[m.nsitem setSubmenu:m.submenu->cocomenu];
 		}
 		return m;
 	}
@@ -117,39 +155,37 @@ struct CocoMenuBar : public Bar {
 
 	virtual bool   IsEmpty() const;
 	virtual void   Separator();
-	
+
 	void MenuAction(id item);
-	
+
 	void Set(Event<Bar&> bar);
-	
+
 	void ClearItems() {
 		cy = 0;
 		just_check = false;
 		is_same = false;
 		item.Clear();
 	}
-	
+
 	void Clear() {
 		ClearItems();
 		if(cocomenu) {
+			CocoMenuSetPtr(cocomenu, NULL);
+			CocoMenuSetProc(cocomenu, NULL);
 			[cocomenu release];
 			cocomenu = NULL;
 		}
 	}
-	void New() {
-		Clear();
-		cocomenu = [CocoMenu new];
-		cocomenu.autoenablesItems = NO;
-		cocomenu->ptr = this;
-		cocomenu.delegate = cocomenu;
-	}
-	
+	void New();
+
 	CocoMenuBar() {
 		cocomenu = NULL;
+		proc = new Event<Bar&>();
 		New();
 	}
 	~CocoMenuBar() {
 		Clear();
+		delete proc;
 	}
 };
 
@@ -209,9 +245,9 @@ CocoMenuBar::Item& CocoMenuBar::Item::Text(const char *text)
 			h.Cat(*text++);
 	}
 	NSString *s = [NSString stringWithUTF8String:~h];
-	nsitem.title = s;
+	[nsitem setTitle:s];
 	if(submenu)
-		submenu->cocomenu.title = s;
+		[submenu->cocomenu setTitle:s];
 	return *this;
 }
 
@@ -234,11 +270,11 @@ CocoMenuBar::Item& CocoMenuBar::Item::Key(dword key)
 	auto *v = FindTuple(code, __countof(code), key & ~(K_CTRL|K_SHIFT|K_ALT|K_OPTION));
 	if(v) {
 		unichar chr = v->b;
-		nsitem.keyEquivalent = [NSString stringWithCharacters:&chr length:1];
-		nsitem.keyEquivalentModifierMask = (key & K_CTRL ? NSEventModifierFlagCommand : 0) |
-		                                   (key & K_SHIFT ? NSEventModifierFlagShift : 0) |
-		                                   (key & K_ALT ? NSEventModifierFlagControl : 0) |
-		                                   (key & K_OPTION ? NSEventModifierFlagOption : 0);
+		[nsitem setKeyEquivalent:[NSString stringWithCharacters:&chr length:1]];
+		[nsitem setKeyEquivalentModifierMask:(key & K_CTRL ? NSEventModifierFlagCommand : 0) |
+		                                     (key & K_SHIFT ? NSEventModifierFlagShift : 0) |
+		                                     (key & K_ALT ? NSEventModifierFlagControl : 0) |
+		                                     (key & K_OPTION ? NSEventModifierFlagOption : 0)];
 	}
 	return *this;
 }
@@ -247,7 +283,7 @@ CocoMenuBar::Item& CocoMenuBar::Item::Image(const class Image& img)
 {
 	if(FailCheck())
 		return *this;
-	nsitem.image = GetNSImage(img);
+	[nsitem setImage:GetNSImage(img)];
 	return *this;
 }
 
@@ -255,7 +291,7 @@ CocoMenuBar::Item& CocoMenuBar::Item::Check(bool check)
 {
 	if(FailCheck())
 		return *this;
-	nsitem.state = check ? NSControlStateValueOn : NSControlStateValueOff;
+	[nsitem setState:(check ? NSControlStateValueOn : NSControlStateValueOff)];
 	return *this;
 }
 
@@ -271,7 +307,7 @@ CocoMenuBar::Item& CocoMenuBar::Item::Enable(bool enable)
 	if(FailCheck(enabled == enable))
 		return *this;
 	enabled = enable;
-	nsitem.enabled = enable;
+	[nsitem setEnabled:enable];
 	return *this;
 }
 
@@ -288,39 +324,79 @@ bool CocoMenuBar::IsEmpty() const
 	return item.GetCount() == 0;
 }
 
+// Implementation of New() - must be after CocoMenuDelegate is declared but before it's used
+void CocoMenuBar::New() {
+	Clear();
+	if(!sharedMenuDelegate)
+		sharedMenuDelegate = [[CocoMenuDelegate alloc] init];
+	cocomenu = [[NSMenu alloc] init];
+	[cocomenu setAutoenablesItems:NO];
+	CocoMenuSetPtr(cocomenu, this);
+	CocoMenuSetProc(cocomenu, proc);
+	[cocomenu setDelegate:sharedMenuDelegate];
+}
+
+// Function called by AppDelegate when menu item is clicked
+// This is exposed so CocoApp.mm can call it
+// Called from CocoView::cocoMenuAction and AppDelegate::cocoMenuAction
+// Uses void* to allow extern declaration without struct definition
+void CocoMenuBarAction(void *barPtr, id sender) {
+	CocoMenuBar *bar = (CocoMenuBar *)barPtr;
+	if(bar)
+		bar->MenuAction(sender);
+}
+
 }
 
-@implementation CocoMenu
+@implementation CocoMenuDelegate
 
--(void)cocoMenuAction:(id)sender {
-	if(ptr)
-		ptr->MenuAction(sender);
+- (void)menuItemAction:(id)sender {
+	Upp::GuiLock __;
+	NSMenuItem *item = (NSMenuItem *)sender;
+	void *barPtr = objc_getAssociatedObject(item, &CocoMenuItemBarKey);
+	if(barPtr) {
+		Upp::CocoMenuBarAction(barPtr, sender);
+	}
+}
+
+- (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item {
+	// Track highlighted item - if it's a real item (not nil, not separator, not submenu parent)
+	if(item && ![item isSeparatorItem] && ![item hasSubmenu]) {
+		lastSelectedMenuItem = item;
+	}
 }
 
 - (void)menuWillOpen:(NSMenu *)menu {
-	CocoMenu *m = (CocoMenu *)menu;
-	if(m && m->ptr && m->ptr->dockmenu)
+	lastSelectedMenuItem = nil;
+	menuItemWasClicked = NO;
+	Upp::CocoMenuBar *ptr = CocoMenuGetPtr(menu);
+	Upp::Event<Upp::Bar&> *proc = CocoMenuGetProc(menu);
+	if(ptr && ptr->dockmenu)
 		return;
-	if(m && m->ptr && proc) {
-		m->ptr->ClearItems();
-		[m removeAllItems];
-		proc(*m->ptr);
+	if(ptr && proc && *proc) {
+		ptr->ClearItems();
+		[menu removeAllItems];
+		(*proc)(*ptr);
 	}
 }
 
 - (void)menuDidClose:(NSMenu *)menu {
-	CocoMenu *m = (CocoMenu *)menu;
-	if(m && m->ptr && m->ptr->dockmenu)
+	Upp::CocoMenuBar *ptr = CocoMenuGetPtr(menu);
+	if(ptr && ptr->dockmenu)
 		return;
-	// DO NOT CALL ClearItems here - menu is closed before MenuAction, we need items to find
-	// correct callback
-	[m removeAllItems];
-}
 
--(void)submenuAction:(id)sender {
-	if(ptr)
-		proc(*ptr);
-	[super submenuAction:sender];
+	// GCC ObjC runtime workaround: action/target dispatch doesn't work,
+	// so we manually invoke the action for the highlighted item when menu closes
+	if(lastSelectedMenuItem && [lastSelectedMenuItem isEnabled]) {
+		void *barPtr = objc_getAssociatedObject(lastSelectedMenuItem, &CocoMenuItemBarKey);
+		if(barPtr) {
+			Upp::GuiLock __;
+			Upp::CocoMenuBarAction(barPtr, lastSelectedMenuItem);
+		}
+		lastSelectedMenuItem = nil;
+	}
+
+	[menu removeAllItems];
 }
 
 @end
@@ -422,10 +498,13 @@ NSMenu *Cocoa_DockMenu() {
 		static Upp::CocoMenuBar bar;
 		bar.dockmenu = true;
 		bar.Clear();
-		bar.cocomenu = [[[CocoMenu alloc] initWithTitle:@"DocTile Menu"] autorelease];
-		bar.cocomenu.autoenablesItems = NO;
-		bar.cocomenu->ptr = &bar;
-		bar.cocomenu.delegate = bar.cocomenu;
+		bar.cocomenu = [[[NSMenu alloc] initWithTitle:@"DocTile Menu"] autorelease];
+		[bar.cocomenu setAutoenablesItems:NO];
+		CocoMenuSetPtr(bar.cocomenu, &bar);
+		CocoMenuSetProc(bar.cocomenu, bar.proc);
+		if(!sharedMenuDelegate)
+			sharedMenuDelegate = [[CocoMenuDelegate alloc] init];
+		[bar.cocomenu setDelegate:sharedMenuDelegate];
 		w->WhenDockMenu(bar);
 		CocoMenu *m = bar.cocomenu;
 		bar.cocomenu = NULL;
diff --git a/uppsrc/Draw/Drawing.cpp b/uppsrc/Draw/Drawing.cpp
index 088275185..295e22000 100644
--- a/uppsrc/Draw/Drawing.cpp
+++ b/uppsrc/Draw/Drawing.cpp
@@ -46,8 +46,8 @@ static void StreamUnpackPoints(Stream& stream, Point *out, int count)
 	byte *top = reinterpret_cast<byte *>(end) - count * 8;
 	stream.Get(top, count * 8);
 	for(; out < end; out++, top += 8) {
-		out -> x = (short)Peek32le(top + 0);
-		out -> y = (short)Peek32le(top + 4);
+		out -> x = Peek32le(top + 0);
+		out -> y = Peek32le(top + 4);
 	}
 }
 
@@ -68,7 +68,7 @@ static void StreamPackPoints(Stream& stream, const Point *in, int count)
 			Poke32le(pp + 0, in -> x);
 			Poke32le(pp + 4, in -> y);
 		}
-		stream.Put(part, part_count * 4);
+		stream.Put(part, part_count * 8);
 		count -= part_count;
 	}
 }
@@ -265,7 +265,10 @@ void DrawingDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font fo
 #ifdef CPU_LE
 	s.Put(text, n * sizeof(wchar));
 #else
-	#error big endiand not supported
+	Buffer<wchar> txt(n);
+	memcpy(txt, text, n * sizeof(wchar));
+	EndianSwap((dword *)(wchar *)txt, n);
+	s.Put(txt, n * sizeof(wchar));
 #endif
 	bool dxb = dx;
 	s % dxb;
@@ -558,6 +561,9 @@ void Draw::DrawDrawingOp(const Rect& target, const Drawing& w) {
 				if(cs == CHARSET_UTF32) {
 					Buffer<wchar> txt(n);
 					ps.Stream::Get(txt, n * sizeof(wchar));
+#ifdef CPU_BE
+					EndianSwap((dword *)(wchar *)txt, n);
+#endif
 					text = WString(txt, n);
 				}
 				else
diff --git a/uppsrc/Draw/FontCoco.mm b/uppsrc/Draw/FontCoco.mm
index 4d7cb0ac8..82d820c32 100644
--- a/uppsrc/Draw/FontCoco.mm
+++ b/uppsrc/Draw/FontCoco.mm
@@ -7,6 +7,11 @@
 
 #ifndef flagNOMM // Removes ObjectiveC and AppKit dependence in Draw (but disables Fonts)
 
+// Disable old-style Carbon assertion macros (check, verify, require, etc.)
+#ifndef __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES
+#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
+#endif
+
 #define Point NS_Point
 #define Rect  NS_Rect
 #define Size  NS_Size
@@ -15,6 +20,12 @@
 #undef  Rect
 #undef  Size
 
+// macOS 10.6 SDK compatibility - kCTFontOrientationHorizontal added in 10.8
+// kCTFontDefaultOrientation (value 0) is equivalent for horizontal text
+#ifndef kCTFontOrientationHorizontal
+#define kCTFontOrientationHorizontal kCTFontDefaultOrientation
+#endif
+
 namespace Upp {
 
 namespace Detail { // TODO: following utilities are normally defined in CtrlCore, rename to avoid name clash
@@ -194,9 +205,13 @@ CommonFontInfo GetFontInfoSys(Font font)
 		fi.ttf = true;
 
 		CFRef<CTFontDescriptorRef> fd = CTFontCopyFontDescriptor(ctfont);
-	    CFRef<CFURLRef> url = (CFURLRef)CTFontDescriptorCopyAttribute(fd, kCTFontURLAttribute);
-		CFRef<CFStringRef> path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
-		String p = ToString(path);
+	    CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(fd, kCTFontURLAttribute);
+		String p;
+		if(url) {
+			CFRef<CFStringRef> pathStr = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
+			p = ToString(pathStr);
+			CFRelease(url);
+		}
 
 		if(p.GetCount() < 250)
 			strcpy(fi.path, ~p);
@@ -254,7 +269,9 @@ Vector<FaceInfo> GetAllFacesSys()
 		fi.info = Font::SCALEABLE;
 		if(traits & kCTFontMonoSpaceTrait)
 			fi.info |= Font::FIXEDPITCH;
-		switch(traits & kCTFontClassMaskTrait) {
+		// Cast to int32 to avoid narrowing conversion error with kCTFontScriptsClass
+		// (which has high bit set and is defined as signed int)
+		switch((int32)(traits & kCTFontClassMaskTrait)) {
 		case kCTFontOldStyleSerifsClass:
 		case kCTFontTransitionalSerifsClass:
 		case kCTFontModernSerifsClass:
@@ -266,6 +283,8 @@ Vector<FaceInfo> GetAllFacesSys()
 		case kCTFontScriptsClass:
 			fi.info |= Font::SCRIPTSTYLE;
 		    break;
+		default:
+		    break;
 		}
 	}
 
diff --git a/uppsrc/ide/Builders/Cocoa.cpp b/uppsrc/ide/Builders/Cocoa.cpp
index 375c64129..be89dab3a 100644
--- a/uppsrc/ide/Builders/Cocoa.cpp
+++ b/uppsrc/ide/Builders/Cocoa.cpp
@@ -58,6 +58,10 @@ void GccBuilder::CocoaAppBundle()
 	}
 
 	if(IsNull(Info_plist)) {
+		// Get deployment target from environment, default to 10.6 for maximum compatibility
+		String macos_version = GetEnv("MACOSX_DEPLOYMENT_TARGET");
+		if(IsNull(macos_version) || macos_version.IsEmpty())
+			macos_version = "10.6";
 		Info_plist
 			<< "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 			<< "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
@@ -68,7 +72,7 @@ void GccBuilder::CocoaAppBundle()
 			<< "    <key>NSHighResolutionCapable</key>\n"
 		    << "    <string>True</string>\n"
 		    << "	<key>LSMinimumSystemVersion</key>\n"
-			<< "    <string>10.13.0</string>\n"
+			<< "    <string>" << macos_version << "</string>\n"
 		;
 		if(imgs.GetCount())
 			Info_plist
diff --git a/uppsrc/ide/Builders/Install.cpp b/uppsrc/ide/Builders/Install.cpp
index 87138c0fb..8260d267f 100644
--- a/uppsrc/ide/Builders/Install.cpp
+++ b/uppsrc/ide/Builders/Install.cpp
@@ -31,6 +31,33 @@ INCLUDE = "$INCLUDE$";
 LIB = "$LIB$";
 LINKMODE_LOCK = "0";)";
 
+const char *gcc_bm =
+R"(BUILDER = "GCC";
+COMPILER = "@CXX@";
+COMMON_OPTIONS = "$COMMON$";
+COMMON_CPP_OPTIONS = "-std=c++17 @ABI_FLAG@ -isystem@PREFIX@/include/LegacySupport";
+COMMON_C_OPTIONS = "-isystem@PREFIX@/include/LegacySupport";
+COMMON_LINK = "$COMMON$ -L@PREFIX@/lib -lMacportsLegacySupport";
+COMMON_FLAGS = "";
+DEBUG_INFO = "2";
+DEBUG_BLITZ = "1";
+DEBUG_LINKMODE = "1";
+DEBUG_OPTIONS = "-O0";
+DEBUG_FLAGS = "";
+DEBUG_LINK = "";
+RELEASE_BLITZ = "1";
+RELEASE_LINKMODE = "1";
+RELEASE_OPTIONS = "-O3 -ffunction-sections -fdata-sections";
+RELEASE_FLAGS = "";
+RELEASE_LINK = "";
+DEBUGGER = "gdb";
+ALLOW_PRECOMPILED_HEADERS = "0";
+DISABLE_BLITZ = "0";
+PATH = "";
+INCLUDE = "$INCLUDE$";
+LIB = "$LIB$";
+LINKMODE_LOCK = "0";)";
+
 #elif PLATFORM_SOLARIS
 
 const char *gcc_bm =
@@ -148,9 +175,9 @@ LINKMODE_LOCK = "0";)";
 void CreateBuildMethods()
 {
 #ifdef PLATFORM_COCOA
-	String bm_path = ConfigFile("CLANG.bm");
+	String bm_path = ConfigFile("GCC.bm");
 	if(IsNull(LoadFile(bm_path))) {
-		String bm = clang_bm;
+		String bm = gcc_bm;
 		
 		auto Path = [&](const char *var, const char *path) {
 			String h;
@@ -160,14 +187,11 @@ void CreateBuildMethods()
 			bm.Replace(var, h);
 		};
 		
-		Path("$INCLUDE$", "/opt/local/include;/usr/include;/usr/local/include;/opt/homebrew/include;/opt/homebrew/opt/openssl/include");
-		Path("$LIB$", "/opt/local/lib;/usr/lib;/usr/local/lib;/opt/homebrew/lib;/opt/homebrew/opt/openssl/lib");
-		
-		String common;
-	#ifdef CPU_ARM
-		common = "-arch arm64";
-	#endif
-		bm.Replace("$COMMON$", common);
+		Path("$INCLUDE$", "@PREFIX@/include/LegacySupport;@PREFIX@/include;/usr/include");
+		Path("$LIB$", "@PREFIX@/lib/libgcc;@PREFIX@/lib;/usr/lib");
+
+		// No hardcoded architecture flags - let compiler use native architecture
+		bm.Replace("$COMMON$", "");
 
 		SaveFile(bm_path, bm);
 	}
@@ -179,11 +203,9 @@ void CreateBuildMethods()
 			r.Replace("INCLUDE = \"\";", "INCLUDE = \"/usr/local/opt/openssl/include\";");
 			r.Replace("LIB = \"\";", "LIB = \"/usr/local/opt/openssl/lib\";");
 		}
-		String common;
-	#ifdef CPU_X86
-		common = "-mpopcnt";
-	#endif
-		r.Replace("$COMMON$", common);
+		// No hardcoded architecture flags for non-macOS POSIX
+		// -mpopcnt requires SSE4.2, not available on all x86 CPUs
+		r.Replace("$COMMON$", "");
 		return r;
 	};
 
diff --git a/uppsrc/plugin/bmp/_bmp.h b/uppsrc/plugin/bmp/_bmp.h
index 633310983..7f065cf3a 100644
--- a/uppsrc/plugin/bmp/_bmp.h
+++ b/uppsrc/plugin/bmp/_bmp.h
@@ -1,9 +1,6 @@
 #ifndef _nImage__bmp_h_
 #define _nImage__bmp_h_
 
-#ifdef CPU_BIG_ENDIAD
-#error "Fix big endian issues!"
-#endif
 
 #ifdef COMPILER_MSC
 #pragma pack(push, 1)
@@ -19,9 +16,9 @@ struct BMP_FILEHEADER {
 	void    EndianSwap()
 	{
 #ifdef CPU_BIG_ENDIAN
-		EndianSwap(bfType);
-		EndianSwap(bfSize);
-		EndianSwap(bfOffBits);
+		Upp::EndianSwap(bfType);
+		Upp::EndianSwap(bfSize);
+		Upp::EndianSwap(bfOffBits);
 #endif
 	}
 }
@@ -47,18 +44,17 @@ struct BMP_INFOHEADER
 	void    EndianSwap()
 	{
 #ifdef CPU_BIG_ENDIAN
-		EndianSwap(biSize);
-		EndianSwap(biWidth);
-		EndianSwap(biHeight);
-		EndianSwap(biPlanes);
-		EndianSwap(biBitCount);
-		EndianSwap(biCompression);
-		EndianSwap(biSizeImage);
-		EndianSwap(biXPelsPerMeter);
-		EndianSwap(biYPelsPerMeter);
-		EndianSwap(biClrUsed);
-		EndianSwap(biClrImportant);
-
+		Upp::EndianSwap(biSize);
+		Upp::EndianSwap(biWidth);
+		Upp::EndianSwap(biHeight);
+		Upp::EndianSwap(biPlanes);
+		Upp::EndianSwap(biBitCount);
+		Upp::EndianSwap(biCompression);
+		Upp::EndianSwap(biSizeImage);
+		Upp::EndianSwap(biXPelsPerMeter);
+		Upp::EndianSwap(biYPelsPerMeter);
+		Upp::EndianSwap(biClrUsed);
+		Upp::EndianSwap(biClrImportant);
 #endif
 	}
 }
@@ -84,9 +80,9 @@ struct ICONDIR
 	void    EndianSwap()
 	{
 #ifdef CPU_BIG_ENDIAN
-		EndianSwap(idReserved);
-		EndianSwap(idType);
-		EndianSwap(idCount);
+		Upp::EndianSwap(idReserved);
+		Upp::EndianSwap(idType);
+		Upp::EndianSwap(idCount);
 #endif
 	}
 }
@@ -109,11 +105,10 @@ struct ICONDIRENTRY
 	void    EndianSwap()
 	{
 #ifdef CPU_BIG_ENDIAN
-		EndianSwap(wHotSpotX);
-		EndianSwap(wHotSpotY);
-		EndianSwap(dwBytesInRes);
-		EndianSwap(dwImageOffset);
-
+		Upp::EndianSwap(wHotSpotX);
+		Upp::EndianSwap(wHotSpotY);
+		Upp::EndianSwap(dwBytesInRes);
+		Upp::EndianSwap(dwImageOffset);
 #endif
 	}
 }
diff --git a/uppsrc/plugin/bmp/bmphdr.h b/uppsrc/plugin/bmp/bmphdr.h
index 1a4cfaef6..c5e75c759 100644
--- a/uppsrc/plugin/bmp/bmphdr.h
+++ b/uppsrc/plugin/bmp/bmphdr.h
@@ -15,9 +15,15 @@ struct BMP_FILEHEADER {
 	void    SwapEndian()
 	{
 #ifdef CPU_BIG_ENDIAN
-		bfType = UPP::SwapEndian(bfType);
-		bfSize = UPP::SwapEndian(bfSize);
-		bfOffBits = UPP::SwapEndian(bfOffBits);
+		word tmp_bfType = bfType;
+		dword tmp_bfSize = bfSize;
+		dword tmp_bfOffBits = bfOffBits;
+		Upp::EndianSwap(tmp_bfType);
+		Upp::EndianSwap(tmp_bfSize);
+		Upp::EndianSwap(tmp_bfOffBits);
+		bfType = tmp_bfType;
+		bfSize = tmp_bfSize;
+		bfOffBits = tmp_bfOffBits;
 #endif
 	}
 }
@@ -43,17 +49,39 @@ struct BMP_INFOHEADER
 	void    SwapEndian()
 	{
 #ifdef CPU_BIG_ENDIAN
-		biSize = UPP::SwapEndian(biSize);
-		biWidth = UPP::SwapEndian(biWidth);
-		biHeight = UPP::SwapEndian(biHeight);
-		biPlanes = UPP::SwapEndian(biPlanes);
-		biBitCount = UPP::SwapEndian(biBitCount);
-		biCompression = UPP::SwapEndian(biCompression);
-		biSizeImage = UPP::SwapEndian(biSizeImage);
-		biXPelsPerMeter = UPP::SwapEndian(biXPelsPerMeter);
-		biYPelsPerMeter = UPP::SwapEndian(biYPelsPerMeter);
-		biClrUsed = UPP::SwapEndian(biClrUsed);
-		biClrImportant = UPP::SwapEndian(biClrImportant);
+		dword tmp_biSize = biSize;
+		int32 tmp_biWidth = biWidth;
+		int32 tmp_biHeight = biHeight;
+		word tmp_biPlanes = biPlanes;
+		word tmp_biBitCount = biBitCount;
+		dword tmp_biCompression = biCompression;
+		dword tmp_biSizeImage = biSizeImage;
+		int32 tmp_biXPelsPerMeter = biXPelsPerMeter;
+		int32 tmp_biYPelsPerMeter = biYPelsPerMeter;
+		dword tmp_biClrUsed = biClrUsed;
+		dword tmp_biClrImportant = biClrImportant;
+		Upp::EndianSwap(tmp_biSize);
+		Upp::EndianSwap(tmp_biWidth);
+		Upp::EndianSwap(tmp_biHeight);
+		Upp::EndianSwap(tmp_biPlanes);
+		Upp::EndianSwap(tmp_biBitCount);
+		Upp::EndianSwap(tmp_biCompression);
+		Upp::EndianSwap(tmp_biSizeImage);
+		Upp::EndianSwap(tmp_biXPelsPerMeter);
+		Upp::EndianSwap(tmp_biYPelsPerMeter);
+		Upp::EndianSwap(tmp_biClrUsed);
+		Upp::EndianSwap(tmp_biClrImportant);
+		biSize = tmp_biSize;
+		biWidth = tmp_biWidth;
+		biHeight = tmp_biHeight;
+		biPlanes = tmp_biPlanes;
+		biBitCount = tmp_biBitCount;
+		biCompression = tmp_biCompression;
+		biSizeImage = tmp_biSizeImage;
+		biXPelsPerMeter = tmp_biXPelsPerMeter;
+		biYPelsPerMeter = tmp_biYPelsPerMeter;
+		biClrUsed = tmp_biClrUsed;
+		biClrImportant = tmp_biClrImportant;
 #endif
 	}
 }
diff --git a/uppsrc/plugin/pcx/pcxhdr.h b/uppsrc/plugin/pcx/pcxhdr.h
index 90a51ea38..98156ad3a 100644
--- a/uppsrc/plugin/pcx/pcxhdr.h
+++ b/uppsrc/plugin/pcx/pcxhdr.h
@@ -40,17 +40,16 @@ struct PCXHeader {
 	void    SwapEndian()
 	{
 #ifdef CPU_BIG_ENDIAN
-		biSize = UPP::SwapEndian(biSize);
-		biWidth = UPP::SwapEndian(biWidth);
-		biHeight = UPP::SwapEndian(biHeight);
-		biPlanes = UPP::SwapEndian(biPlanes);
-		biBitCount = UPP::SwapEndian(biBitCount);
-		biCompression = UPP::SwapEndian(biCompression);
-		biSizeImage = UPP::SwapEndian(biSizeImage);
-		biXPelsPerMeter = UPP::SwapEndian(biXPelsPerMeter);
-		biYPelsPerMeter = UPP::SwapEndian(biYPelsPerMeter);
-		biClrUsed = UPP::SwapEndian(biClrUsed);
-		biClrImportant = UPP::SwapEndian(biClrImportant);
+		Upp::EndianSwap(minX);
+		Upp::EndianSwap(minY);
+		Upp::EndianSwap(maxX);
+		Upp::EndianSwap(maxY);
+		Upp::EndianSwap(horzDpi);
+		Upp::EndianSwap(vertDpi);
+		Upp::EndianSwap(bytesPerLine);
+		Upp::EndianSwap(paltype);
+		Upp::EndianSwap(hScreenSize);
+		Upp::EndianSwap(vScreenSize);
 #endif
 	}
 
diff --git a/uppsrc/plugin/tif/lib/tif_config.h b/uppsrc/plugin/tif/lib/tif_config.h
index 8734ffa9d..3690049e5 100644
--- a/uppsrc/plugin/tif/lib/tif_config.h
+++ b/uppsrc/plugin/tif/lib/tif_config.h
@@ -144,6 +144,8 @@
 # if defined __BIG_ENDIAN__
 #  define WORDS_BIGENDIAN 1
 # endif
+#elif defined(CPU_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(__ppc__) || defined(__ppc64__)
+# define WORDS_BIGENDIAN 1
 #else
 # ifndef WORDS_BIGENDIAN
 #  undef WORDS_BIGENDIAN
-- 
2.54.0

