changeset 63:a6801a2260af

Synched up with the latest dynamic windows, has new slider support and transparency, focus, and other bug fixes on various platforms.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Mon, 14 Jan 2002 00:48:08 +0000
parents 2be5174bdb5d
children c2a10ed13d1f
files dw.def dw.h dww.def gtk/dw.c os2/dw.c win/dw.c
diffstat 6 files changed, 633 insertions(+), 200 deletions(-) [+]
line wrap: on
line diff
--- a/dw.def	Sat Dec 08 04:47:43 2001 +0000
+++ b/dw.def	Mon Jan 14 00:48:08 2002 +0000
@@ -208,6 +208,11 @@
   dw_tree_collapse                       @376
   dw_tree_item_select                    @377
   dw_tree_set_data                       @378
+  dw_tree_insert_after                   @379
 
   dw_font_text_extents                   @380
 
+  dw_slider_new                          @390
+  dw_slider_query_pos                    @391
+  dw_slider_set_pos                      @392
+
--- a/dw.h	Sat Dec 08 04:47:43 2001 +0000
+++ b/dw.h	Mon Jan 14 00:48:08 2002 +0000
@@ -614,6 +614,7 @@
 HWND dw_spinbutton_new(char *text, unsigned long id);
 HWND dw_radiobutton_new(char *text, ULONG id);
 HWND dw_percent_new(unsigned long id);
+HWND dw_slider_new(int vertical, int increments, ULONG id);
 HWND dw_checkbox_new(char *text, unsigned long id);
 HWND dw_listbox_new(unsigned long id, int multi);
 void dw_listbox_append(HWND handle, char *text);
@@ -628,6 +629,8 @@
 int dw_listbox_selected_multi(HWND handle, int where);
 unsigned int dw_percent_query_range(HWND handle);
 void dw_percent_set_pos(HWND handle, unsigned int position);
+unsigned int dw_slider_query_pos(HWND handle);
+void dw_slider_set_pos(HWND handle, unsigned int position);
 void dw_window_set_pos(HWND handle, unsigned long x, unsigned long y);
 void dw_window_set_usize(HWND handle, unsigned long width, unsigned long height);
 void dw_window_set_pos_size(HWND handle, unsigned long x, unsigned long y, unsigned long width, unsigned long height);
--- a/dww.def	Sat Dec 08 04:47:43 2001 +0000
+++ b/dww.def	Mon Jan 14 00:48:08 2002 +0000
@@ -205,6 +205,11 @@
   dw_tree_collapse                       @376
   dw_tree_item_select                    @377
   dw_tree_set_data                       @378
+  dw_tree_insert_after                   @379
 
   dw_font_text_extents                   @380
 
+  dw_slider_new                          @390
+  dw_slider_query_pos                    @391
+  dw_slider_set_pos                      @392
+
--- a/gtk/dw.c	Sat Dec 08 04:47:43 2001 +0000
+++ b/gtk/dw.c	Mon Jan 14 00:48:08 2002 +0000
@@ -3,7 +3,7 @@
  *          A GTK like implementation of the PM GUI
  *          GTK forwarder module for portabilty.
  *
- * (C) 2000,2001 Brian Smith <dbsoft@technologist.com>
+ * (C) 2000-2002 Brian Smith <dbsoft@technologist.com>
  *
  */
 #include "dw.h"
@@ -91,6 +91,8 @@
 void _set_focus_event(GtkWindow *window, GtkWidget *widget, gpointer data);
 void _tree_select_event(GtkTree *tree, GtkWidget *child, gpointer data);
 void _tree_context_event(GtkWidget *widget, GdkEventButton *event, gpointer data);
+void _value_changed_event(GtkAdjustment *adjustment, gpointer user_data);
+
 
 void msleep(long period);
 
@@ -109,7 +111,7 @@
 
 } SignalHandler;
 
-#define SIGNALMAX 15
+#define SIGNALMAX 16
 
 /* A list of signal forwarders, to account for paramater differences. */
 SignalList SignalTranslate[SIGNALMAX] = {
@@ -127,7 +129,8 @@
 	{ _tree_context_event, "tree-context" },
 	{ _item_select_event, "item-select" },
 	{ _tree_select_event, "tree-select" },
-	{ _set_focus_event, "set-focus" }
+	{ _set_focus_event, "set-focus" },
+	{ _value_changed_event, "value_changed" }
 };
 
 /* Alignment flags */
@@ -464,6 +467,39 @@
 	}
 }
 
+int _round_value(gfloat val)
+{
+	int newval = (int)val;
+
+	if(val >= 0.5 + (gfloat)newval)
+		newval++;
+
+	return newval;
+}
+
+void _value_changed_event(GtkAdjustment *adjustment, gpointer data)
+{
+	GtkWidget *slider = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(adjustment), "slider");
+	SignalHandler *work = (SignalHandler *)data;
+
+	if(slider && work)
+	{
+		int (*valuechangedfunc)(HWND, int, void *) = work->func;
+		int max = _round_value(adjustment->upper) - 1;
+		int val = _round_value(adjustment->value);
+		static int lastval = -1;
+		static GtkWidget *lastwidget = 0;
+
+		if(lastval != val || lastwidget != slider)
+		{
+			if(GTK_IS_VSCALE(slider))
+				valuechangedfunc(work->window, max - val,  work->data);
+			else
+				valuechangedfunc(work->window, val,  work->data);
+		}
+	}
+}
+
 gint _default_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
 {
 	GtkWidget *next = (GtkWidget *)data;
@@ -633,17 +669,21 @@
 }
 
 /*
- * Runs a message loop for Dynamic Windows, for a period of seconds.
+ * Runs a message loop for Dynamic Windows, for a period of milliseconds.
  * Parameters:
- *           seconds: Number of seconds to run the loop for.
- */
-void dw_main_sleep(int seconds)
-{
-	time_t start = time(NULL);
+ *           milliseconds: Number of milliseconds to run the loop for.
+ */
+void dw_main_sleep(int milliseconds)
+{
+	struct timeval tv, start;
+
+	gettimeofday(&start, NULL);
 
 	if(_dw_thread == (pthread_t)-1 || _dw_thread == pthread_self())
 	{
-		while(time(NULL) - start <= seconds)
+		gettimeofday(&tv, NULL);
+
+		while(((tv.tv_sec - start.tv_sec)*1000) + ((tv.tv_usec - start.tv_usec)/1000) <= milliseconds)
 		{
 			gdk_threads_enter();
 			if(gtk_events_pending())
@@ -651,10 +691,11 @@
 			else
 				msleep(1);
 			gdk_threads_leave();
+			gettimeofday(&tv, NULL);
 		}
 	}
 	else
-		msleep(seconds * 1000);
+		msleep(milliseconds);
 }
 
 /*
@@ -2040,6 +2081,35 @@
 }
 
 /*
+ * Create a new slider window (widget) to be packed.
+ * Parameters:
+ *       vertical: TRUE or FALSE if slider is vertical.
+ *       increments: Number of increments available.
+ *       id: An ID to be used with WinWindowFromID() or 0L.
+ */
+HWND dw_slider_new(int vertical, int increments, ULONG id)
+{
+	GtkWidget *tmp;
+	GtkAdjustment *adjustment;
+	int _locked_by_me = FALSE;
+
+	DW_MUTEX_LOCK;
+	adjustment = (GtkAdjustment *)gtk_adjustment_new(0, 0, (gfloat)(increments + 1), 1, 1, 1);
+	if(vertical)
+		tmp = gtk_vscale_new(adjustment);
+	else
+		tmp = gtk_hscale_new(adjustment);
+	gtk_widget_show(tmp);
+	gtk_scale_set_draw_value(GTK_SCALE(tmp), 0);
+	gtk_scale_set_digits(GTK_SCALE(tmp), 0);
+	gtk_object_set_data(GTK_OBJECT(tmp), "adjustment", (gpointer)adjustment);
+	gtk_object_set_data(GTK_OBJECT(adjustment), "slider", (gpointer)tmp);
+	gtk_object_set_data(GTK_OBJECT(tmp), "id", (gpointer)id);
+	DW_MUTEX_UNLOCK;
+	return tmp;
+}
+
+/*
  * Create a new percent bar window (widget) to be packed.
  * Parameters:
  *       id: An ID to be used with WinWindowFromID() or 0L.
@@ -2628,7 +2698,7 @@
 /*
  * Returns the range of the percent bar.
  * Parameters:
- *          handle: Handle to the slider to be queried.
+ *          handle: Handle to the percent bar to be queried.
  */
 unsigned int dw_percent_query_range(HWND handle)
 {
@@ -2638,8 +2708,8 @@
 /*
  * Sets the percent bar position.
  * Parameters:
- *          handle: Handle to the slider to be set.
- *          position: Position of the slider withing the range.
+ *          handle: Handle to the percent bar to be set.
+ *          position: Position of the percent bar withing the range.
  */
 void dw_percent_set_pos(HWND handle, unsigned int position)
 {
@@ -2651,6 +2721,63 @@
 }
 
 /*
+ * Returns the position of the slider.
+ * Parameters:
+ *          handle: Handle to the slider to be queried.
+ */
+unsigned int dw_slider_query_pos(HWND handle)
+{
+	int val = 0, _locked_by_me = FALSE;
+	GtkAdjustment *adjustment;
+
+	if(!handle)
+		return 0;
+
+	DW_MUTEX_LOCK;
+	adjustment = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(handle), "adjustment");
+	if(adjustment)
+	{
+		int max = _round_value(adjustment->upper) - 1;
+		int thisval = _round_value(adjustment->value);
+
+		if(GTK_IS_VSCALE(handle))
+			val = max - thisval;
+        else
+			val = thisval;
+	}
+	DW_MUTEX_UNLOCK;
+	return val;
+}
+
+/*
+ * Sets the slider position.
+ * Parameters:
+ *          handle: Handle to the slider to be set.
+ *          position: Position of the slider withing the range.
+ */
+void dw_slider_set_pos(HWND handle, unsigned int position)
+{
+	int _locked_by_me = FALSE;
+	GtkAdjustment *adjustment;
+
+	if(!handle)
+		return;
+
+	DW_MUTEX_LOCK;
+	adjustment = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(handle), "adjustment");
+	if(adjustment)
+	{
+		int max = _round_value(adjustment->upper) - 1;
+
+		if(GTK_IS_VSCALE(handle))
+			gtk_adjustment_set_value(adjustment, (gfloat)(max - position));
+        else
+			gtk_adjustment_set_value(adjustment, (gfloat)position);
+	}
+	DW_MUTEX_UNLOCK;
+}
+
+/*
  * Sets the spinbutton value.
  * Parameters:
  *          handle: Handle to the spinbutton to be set.
@@ -5606,6 +5733,10 @@
 		}
 		thisname = "select-child";
 	}
+	else if(GTK_IS_VSCALE(thiswindow) || GTK_IS_HSCALE(thiswindow))
+	{
+		thiswindow = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(thiswindow), "adjustment");
+	}
 
 	if(!thisfunc || !thiswindow)
 	{
--- a/os2/dw.c	Sat Dec 08 04:47:43 2001 +0000
+++ b/os2/dw.c	Mon Jan 14 00:48:08 2002 +0000
@@ -2,7 +2,7 @@
  * Dynamic Windows:
  *          A GTK like implementation of the PM GUI
  *
- * (C) 2000,2001 Brian Smith <dbsoft@technologist.com>
+ * (C) 2000-2002 Brian Smith <dbsoft@technologist.com>
  * (C) 2000 Achim Hasenmueller <achimha@innotek.de>
  * (C) 2000 Peter Nielsen <peter@pmview.com>
  * (C) 1998 Sergey I. Yevtushenko (some code borrowed from cell toolkit)
@@ -93,7 +93,7 @@
 } SignalList;
 
 /* List of signals and their equivilent OS/2 message */
-#define SIGNALMAX 14
+#define SIGNALMAX 15
 
 SignalList SignalTranslate[SIGNALMAX] = {
 	{ WM_SIZE, "configure_event" },
@@ -109,7 +109,8 @@
 	{ LN_SELECT, "item-select" },
 	{ CN_EMPHASIS, "tree-select" },
 	{ WM_SETFOCUS, "set-focus" },
-	{ WM_USER+1, "lose-focus" }
+	{ WM_USER+1, "lose-focus" },
+	{ SLN_SLIDERTRACK, "value_changed" }
 };
 
 /* This function adds a signal handler callback into the linked list.
@@ -186,8 +187,6 @@
 
 		if(strncmp(tmpbuf, "#3", 3)==0 && dw)  /* Button */
 			WinSetOwner(child, dw);
-		if(strncmp(tmpbuf, "#38", 4)==0 && dw)  /* Slider */
-			WinSetOwner(child, 0);
 		else if(strncmp(tmpbuf, "dynamicwindows", 14) == 0)
 			dw = child;
 
@@ -262,9 +261,10 @@
 	   strncmp(tmpbuf, "#3", 3)==0 ||  /* Button */
 	   strncmp(tmpbuf, "#6", 3)==0 ||  /* Entryfield */
 	   strncmp(tmpbuf, "#7", 3)==0 ||  /* List box */
-	   strncmp(tmpbuf, "#10", 3)==0 || /* MLE */
-	   strncmp(tmpbuf, "#32", 3)==0 || /* Spinbutton */
-	   strncmp(tmpbuf, "#37", 3)== 0)  /* Container */
+	   strncmp(tmpbuf, "#10", 4)==0 || /* MLE */
+	   strncmp(tmpbuf, "#32", 4)==0 || /* Spinbutton */
+	   strncmp(tmpbuf, "#37", 4)==0 || /* Container */
+	   strncmp(tmpbuf, "#38", 4)== 0)  /* Slider */
 		return 1;
 	return 0;
 }
@@ -350,7 +350,7 @@
 					char tmpbuf[100] = "";
 
 					WinQueryClassName(box->items[z].hwnd, 99, tmpbuf);
-					if(strncmp(tmpbuf, "#40", 3)==0) /* Notebook */
+					if(strncmp(tmpbuf, "#40", 4)==0) /* Notebook */
 					{
 						Box *notebox;
 						HWND page = (HWND)WinSendMsg(box->items[z].hwnd, BKM_QUERYPAGEWINDOWHWND,
@@ -420,7 +420,7 @@
 					char tmpbuf[100] = "";
 
 					WinQueryClassName(box->items[z].hwnd, 99, tmpbuf);
-					if(strncmp(tmpbuf, "#40", 3)==0) /* Notebook */
+					if(strncmp(tmpbuf, "#40", 4)==0) /* Notebook */
 					{
 						Box *notebox;
 						HWND page = (HWND)WinSendMsg(box->items[z].hwnd, BKM_QUERYPAGEWINDOWHWND,
@@ -522,7 +522,7 @@
 					char tmpbuf[100] = "";
 
 					WinQueryClassName(box->items[z].hwnd, 99, tmpbuf);
-					if(strncmp(tmpbuf, "#40", 3)==0) /* Notebook */
+					if(strncmp(tmpbuf, "#40", 4)==0) /* Notebook */
 					{
 						Box *notebox;
 						HWND page = (HWND)WinSendMsg(box->items[z].hwnd, BKM_QUERYPAGEWINDOWHWND,
@@ -592,7 +592,7 @@
 					char tmpbuf[100] = "";
 
 					WinQueryClassName(box->items[z].hwnd, 99, tmpbuf);
-					if(strncmp(tmpbuf, "#40", 3)==0) /* Notebook */
+					if(strncmp(tmpbuf, "#40", 4)==0) /* Notebook */
 					{
 						Box *notebox;
 						HWND page = (HWND)WinSendMsg(box->items[z].hwnd, BKM_QUERYPAGEWINDOWHWND,
@@ -699,6 +699,22 @@
 	WinSetWindowPos(hwndFrame, HWND_TOP, 0, 0, swp.cx, swp.cy, SWP_SIZE);
 }
 
+/* Focus toplevel window */
+void _toplevel_focus(HWND handle)
+{
+	HWND box, lastbox = WinQueryWindow(handle, QW_PARENT);
+
+	/* Find the toplevel window */
+	while((box = WinQueryWindow(lastbox, QW_PARENT)) > 0x80000001)
+	{
+		lastbox = box;
+	}
+
+	box = WinWindowFromID(lastbox, FID_CLIENT);
+	if(box)
+		WinSetActiveWindow(HWND_DESKTOP, lastbox);
+}
+
 /* This function will recursively search a box and add up the total height of it */
 void _count_size(HWND box, int type, int *xsize, int *xorigsize)
 {
@@ -1238,27 +1254,37 @@
 MRESULT EXPENTRY _sizeproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
 {
 	PFNWP *blah = WinQueryWindowPtr(hWnd, QWP_USER);
-
-	switch(msg)
+	Box *thisbox = NULL;
+	HWND box;
+
+	box = WinWindowFromID(hWnd, FID_CLIENT);
+	if(box)
+		thisbox = WinQueryWindowPtr(box, QWP_USER);
+
+	if(thisbox && !thisbox->titlebar)
 	{
-	case WM_QUERYTRACKINFO:
+		switch(msg)
 		{
-			if(blah && *blah)
+		case WM_QUERYTRACKINFO:
 			{
-				PTRACKINFO ptInfo;
-				int res;
-				PFNWP myfunc = *blah;
-				res = (int)myfunc(hWnd, msg, mp1, mp2);
-
-				ptInfo = (PTRACKINFO)(mp2);
-
-				ptInfo->ptlMinTrackSize.y = 8;
-				ptInfo->ptlMinTrackSize.x = 8;
-
-				return (MRESULT)res;
+				if(blah && *blah)
+				{
+					PTRACKINFO ptInfo;
+					int res;
+					PFNWP myfunc = *blah;
+					res = (int)myfunc(hWnd, msg, mp1, mp2);
+
+					ptInfo = (PTRACKINFO)(mp2);
+
+					ptInfo->ptlMinTrackSize.y = 8;
+					ptInfo->ptlMinTrackSize.x = 8;
+
+					return (MRESULT)res;
+				}
 			}
 		}
 	}
+
 	if(blah && *blah)
 	{
 		PFNWP myfunc = *blah;
@@ -1362,17 +1388,6 @@
 	return WinDefWindowProc(hWnd, msg, mp1, mp2);
 }
 
-/* This procedure handles drawing of a percent bar */
-MRESULT EXPENTRY _percentproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
-{
-	WindowData *blah = (WindowData *)WinQueryWindowPtr(hWnd, QWP_USER);
-
-	if(blah)
-		return blah->oldproc(hWnd, msg, mp1, mp2);
-
-	return WinDefWindowProc(hWnd, msg, mp1, mp2);
-}
-
 void _click_default(HWND handle)
 {
 	char tmpbuf[100];
@@ -1416,6 +1431,7 @@
 	switch(msg)
 	{
 	case WM_SETFOCUS:
+		_toplevel_focus(hWnd);
 		_run_event(hWnd, msg, mp1, mp2);
 		break;
 	}
@@ -1447,11 +1463,22 @@
 
 			WinQueryClassName(hWnd, 99, tmpbuf);
 
-			if(strncmp(tmpbuf, "#32", 3)==0)
+			if(strncmp(tmpbuf, "#32", 4)==0)
 				_run_event(hWnd, WM_SETFOCUS, (MPARAM)FALSE, (MPARAM)TRUE);
 		}
 		break;
+	case WM_CONTROL:
+		{
+			char tmpbuf[100];
+
+			WinQueryClassName(hWnd, 99, tmpbuf);
+
+			if(strncmp(tmpbuf, "#38", 4)==0)
+				_run_event(hWnd, msg, mp1, mp2);
+		}
+		break;
 	case WM_SETFOCUS:
+		_toplevel_focus(hWnd);
 		_run_event(hWnd, msg, mp1, mp2);
 		break;
 	case WM_CHAR:
@@ -1506,6 +1533,7 @@
 		_run_event(hWnd, WM_SETFOCUS, (MPARAM)FALSE, (MPARAM)TRUE);
 		break;
 	case WM_SETFOCUS:
+		_toplevel_focus(hWnd);
 		_run_event(hWnd, msg, mp1, mp2);
 		break;
 	case WM_PAINT:
@@ -1760,7 +1788,7 @@
 				}
 				break;
 			case WM_CONTROL:
-				if(tmp->message == SHORT2FROMMP(mp1))
+				if(tmp->message == SHORT2FROMMP(mp1) || (tmp->message == SLN_SLIDERTRACK && SHORT2FROMMP(mp1) == SLN_CHANGE))
 				{
 					switch(SHORT2FROMMP(mp1))
 					{
@@ -1866,44 +1894,87 @@
 						break;
 					case LN_SELECT:
 						{
-							int (*listboxselectfunc)(HWND, int, void *) = (int (*)(HWND, int, void *))tmp->signalfunction;
-							int id = SHORT1FROMMP(mp1);
-							HWND conthwnd = dw_window_from_id(hWnd, id);
-							static int _recursing = 0;
-
-							if(_recursing == 0 && (tmp->window == conthwnd || (!id && tmp->window == (HWND)mp2)))
+							char classbuf[100];
+
+							WinQueryClassName(tmp->window, 99, classbuf);
+
+							if(strncmp(classbuf, "#38", 4) == 0)
 							{
-								char buf1[500], classbuf[100];
-								unsigned int index = dw_listbox_selected(tmp->window);
-
-								dw_listbox_query_text(tmp->window, index, buf1, 500);
-
-								WinQueryClassName(tmp->window, 99, classbuf);
-
-								_recursing = 1;
-
-								if(id && strncmp(classbuf, "#2", 3)==0)
+								int (*valuechangedfunc)(HWND, int, void *) = (int (*)(HWND, int, void *))tmp->signalfunction;
+
+								if(tmp->window == hWnd || WinQueryWindow(tmp->window, QW_PARENT) == hWnd)
+								{
+									static int lastvalue = -1;
+									static HWND lasthwnd = NULLHANDLE;
+									int ulValue = (int)WinSendMsg(tmp->window, SLM_QUERYSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), 0);
+									if(lastvalue != ulValue || lasthwnd != tmp->window)
+									{
+										result = valuechangedfunc(tmp->window, ulValue, tmp->data);
+										lastvalue = ulValue;
+										lasthwnd = tmp->window;
+									}
+									tmp = NULL;
+								}
+							}
+							else
+							{
+								int (*listboxselectfunc)(HWND, int, void *) = (int (*)(HWND, int, void *))tmp->signalfunction;
+								int id = SHORT1FROMMP(mp1);
+								HWND conthwnd = dw_window_from_id(hWnd, id);
+								static int _recursing = 0;
+
+								if(_recursing == 0 && (tmp->window == conthwnd || (!id && tmp->window == (HWND)mp2)))
 								{
-									char *buf2;
-
-									buf2 = dw_window_get_text(tmp->window);
-
-									/* This is to make sure the listboxselect function doesn't
-									 * get called if the user is modifying the entry text.
-									 */
-									if(buf2 && *buf2 && *buf1 && strncmp(buf1, buf2, 500) == 0)
+									char buf1[500];
+									unsigned int index = dw_listbox_selected(tmp->window);
+
+									dw_listbox_query_text(tmp->window, index, buf1, 500);
+
+									_recursing = 1;
+
+									if(id && strncmp(classbuf, "#2", 3)==0)
+									{
+										char *buf2;
+
+										buf2 = dw_window_get_text(tmp->window);
+
+										/* This is to make sure the listboxselect function doesn't
+										 * get called if the user is modifying the entry text.
+										 */
+										if(buf2 && *buf2 && *buf1 && strncmp(buf1, buf2, 500) == 0)
+											result = listboxselectfunc(tmp->window, index, tmp->data);
+
+										if(buf2)
+											free(buf2);
+									}
+									else
 										result = listboxselectfunc(tmp->window, index, tmp->data);
 
-									if(buf2)
-										free(buf2);
+									_recursing = 0;
+									tmp = NULL;
 								}
-								else
-									result = listboxselectfunc(tmp->window, index, tmp->data);
-
-								_recursing = 0;
+							}
+						}
+						break;
+					case SLN_SLIDERTRACK:
+						{
+							int (*valuechangedfunc)(HWND, int, void *) = (int (*)(HWND, int, void *))tmp->signalfunction;
+
+							if(tmp->window == hWnd || WinQueryWindow(tmp->window, QW_PARENT) == hWnd)
+							{
+								static int lastvalue = -1;
+								static HWND lasthwnd = NULLHANDLE;
+								int ulValue = (int)WinSendMsg(tmp->window, SLM_QUERYSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), 0);
+								if(lastvalue != ulValue || lasthwnd != tmp->window)
+								{
+									result = valuechangedfunc(tmp->window, ulValue, tmp->data);
+									lastvalue = ulValue;
+									lasthwnd = tmp->window;
+								}
 								tmp = NULL;
 							}
 						}
+
 						break;
 					}
 				}
@@ -1920,6 +1991,40 @@
 }
 #endif
 
+int _warp4_focus_fix(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	/* This is a hack to stop an infinite loop in the
+	 * Warp 4 default window procedure.  It seems that
+	 * under very rare circumstances, the same WM_FOCUSCHANGE
+	 * message will bounce between an entryfield and
+	 * the frame it sits on, this will stop duplicate
+	 * messages and thus prevent the infinite loop.
+	 */
+	if(msg == WM_FOCUSCHANGE && SHORT1FROMMP(mp2))
+	{
+		static HWND lastfocus = 0;
+		static time_t lasttime = 0;
+		static int count = 0;
+		time_t currtime = time(NULL);
+
+		if(lastfocus == (HWND)mp1 && currtime == lasttime)
+		{
+			if(count > 5)
+			{
+				count = 0;
+				return 1;
+			}
+			count++;
+			return 0;
+		}
+
+		count = 0;
+		lastfocus = (HWND)mp1;
+		lasttime = currtime;
+	}
+	return 0;
+}
+
 /* Handles control messages sent to the box (owner). */
 MRESULT EXPENTRY _controlproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
 {
@@ -1933,10 +2038,14 @@
 		break;
 	}
 #endif
+
+	if(_warp4_focus_fix(hWnd, msg, mp1, mp2))
+		return (MRESULT)0;
+	if(msg == WM_SETFOCUS)
+		_toplevel_focus(hWnd);
+
 	if(blah && blah->oldproc)
-	{
 		return blah->oldproc(hWnd, msg, mp1, mp2);
-	}
 
 	return WinDefWindowProc(hWnd, msg, mp1, mp2);
 }
@@ -2044,7 +2153,7 @@
 						WinQueryClassName(mybox->items[z].hwnd, 99, tmpbuf);
 
 						/* If we have a notebook we resize the page again. */
-						if(strncmp(tmpbuf, "#40", 3)==0)
+						if(strncmp(tmpbuf, "#40", 4)==0)
 						{
 							unsigned long x, y, width, height;
 							int page = dw_notebook_page_query(mybox->items[z].hwnd);
@@ -2131,6 +2240,10 @@
 		_free_window_memory(hWnd);
 		break;
 	}
+
+	if(_warp4_focus_fix(hWnd, msg, mp1, mp2))
+		return (MRESULT)0;
+
 	if(result != -1)
 		return (MRESULT)result;
 	else
@@ -2673,7 +2786,7 @@
 	case WM_BUTTON2DOWN:
 	case WM_BUTTON3DOWN:
 		if(!res)
-			WinSetFocus(HWND_DESKTOP, hwnd);
+			_toplevel_focus(hwnd);
 		return (MPARAM)TRUE;
 	}
 	return WinDefWindowProc(hwnd, msg, mp1, mp2);
@@ -2756,16 +2869,16 @@
 }
 
 /*
- * Runs a message loop for Dynamic Windows, for a period of seconds.
- * Parameters:
- *           seconds: Number of seconds to run the loop for.
- */
-void dw_main_sleep(int seconds)
+ * Runs a message loop for Dynamic Windows, for a period of milliseconds.
+ * Parameters:
+ *           milliseconds: Number of milliseconds to run the loop for.
+ */
+void dw_main_sleep(int milliseconds)
 {
 	QMSG qmsg;
-	time_t start = time(NULL);
-
-	while(time(NULL) - start <= seconds)
+	double start = (double)clock();
+
+	while(((clock() - start) / (CLOCKS_PER_SEC/1000)) <= milliseconds)
 	{
 		if(WinPeekMsg(dwhab, &qmsg, 0, 0, 0, PM_NOREMOVE))
 		{
@@ -3705,7 +3818,6 @@
 							   NULL,
 							   NULL);
 	dw_window_set_font(tmp, DefaultFont);
-	dw_window_set_font(tmp, DefaultFont);
 	blah->oldproc = WinSubclassWindow(tmp, _comboentryproc);
 	WinSetWindowPtr(tmp, QWP_USER, blah);
 	return tmp;
@@ -3952,13 +4064,40 @@
 }
 
 /*
+ * Create a new slider window (widget) to be packed.
+ * Parameters:
+ *       vertical: TRUE or FALSE if slider is vertical.
+ *       increments: Number of increments available.
+ *       id: An ID to be used with WinWindowFromID() or 0L.
+ */
+HWND dw_slider_new(int vertical, int increments, ULONG id)
+{
+	WindowData *blah = calloc(1, sizeof(WindowData));
+	SLDCDATA sldcData = { sizeof(SLDCDATA), increments, 0, 0, 0 };
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_SLIDER,
+							   "",
+							   WS_VISIBLE | SLS_SNAPTOINCREMENT |
+							   (vertical ? SLS_VERTICAL : SLS_HORIZONTAL),
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   &sldcData,
+							   NULL);
+
+	blah->oldproc = WinSubclassWindow(tmp, _entryproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	return tmp;
+}
+
+/*
  * Create a new percent bar window (widget) to be packed.
  * Parameters:
  *       id: An ID to be used with WinWindowFromID() or 0L.
  */
 HWND dw_percent_new(ULONG id)
 {
-	WindowData *blah = calloc(1, sizeof(WindowData));
 	HWND tmp = WinCreateWindow(HWND_OBJECT,
 							   WC_SLIDER,
 							   "",
@@ -3970,9 +4109,7 @@
 							   id,
 							   NULL,
 							   NULL);
-
-	blah->oldproc = WinSubclassWindow(tmp, _percentproc);
-	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_disable(tmp);
 	return tmp;
 }
 
@@ -4178,7 +4315,6 @@
 
 void dw_box_pack_end_stub(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad)
 {
-    HWND boxowner = NULLHANDLE;
 	Box *thisbox;
 
 	if(WinWindowFromID(box, FID_CLIENT))
@@ -4243,13 +4379,8 @@
 
         /* Don't set the ownership if it's an entryfield  or spinbutton */
 		WinQueryClassName(item, 99, tmpbuf);
-		if(strncmp(tmpbuf, "#6", 3)!=0 && strncmp(tmpbuf, "#32", 3)!=0)
-		{
-			if((boxowner = WinQueryWindow(box, QW_OWNER)) != 0)
-				WinSetOwner(item, boxowner);
-			else
-				WinSetOwner(item, box);
-		}
+		if(strncmp(tmpbuf, "#6", 3)!=0 && strncmp(tmpbuf, "#32", 4)!=0)
+			WinSetOwner(item, box);
 		WinSetParent(item, box, FALSE);
 	}
 }
@@ -4822,7 +4953,7 @@
 /*
  * Returns the range of the percent bar.
  * Parameters:
- *          handle: Handle to the slider to be queried.
+ *          handle: Handle to the percent bar to be queried.
  */
 unsigned int dw_percent_query_range(HWND handle)
 {
@@ -4832,8 +4963,8 @@
 /*
  * Sets the percent bar position.
  * Parameters:
- *          handle: Handle to the slider to be set.
- *          position: Position of the slider withing the range.
+ *          handle: Handle to the percent bar to be set.
+ *          position: Position of the percent bar withing the range.
  */
 void dw_percent_set_pos(HWND handle, unsigned int position)
 {
@@ -4841,6 +4972,27 @@
 }
 
 /*
+ * Returns the position of the slider.
+ * Parameters:
+ *          handle: Handle to the slider to be queried.
+ */
+unsigned int dw_slider_query_pos(HWND handle)
+{
+	return (unsigned int)WinSendMsg(handle, SLM_QUERYSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), 0);
+}
+
+/*
+ * Sets the slider position.
+ * Parameters:
+ *          handle: Handle to the slider to be set.
+ *          position: Position of the slider withing the range.
+ */
+void dw_slider_set_pos(HWND handle, unsigned int position)
+{
+	WinSendMsg(handle, SLM_SETSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), (MPARAM)position);
+}
+
+/*
  * Sets the spinbutton value.
  * Parameters:
  *          handle: Handle to the spinbutton to be set.
@@ -6160,12 +6312,25 @@
 
 /*
  * Tries to gain access to the semaphore, if it can't it blocks.
+ * If we are in a callback we must keep the message loop running
+ * while blocking.
  * Parameters:
  *       mutex: The handle to the mutex returned by dw_mutex_new().
  */
 void dw_mutex_lock(HMTX mutex)
 {
-	DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT);
+	if(_dwtid == dw_thread_id())
+	{
+		int rc = DosRequestMutexSem(mutex, SEM_IMMEDIATE_RETURN);
+
+		while(rc == ERROR_TIMEOUT)
+		{
+			dw_main_sleep(10);
+			rc = DosRequestMutexSem(mutex, SEM_IMMEDIATE_RETURN);
+		}
+	}
+    else
+		DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT);
 }
 
 /*
@@ -6421,7 +6586,6 @@
 
 void dw_box_pack_start_stub(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad)
 {
-	HWND boxowner = NULLHANDLE;
 	Box *thisbox;
 
 	if(WinWindowFromID(box, FID_CLIENT))
@@ -6476,13 +6640,8 @@
 
 		WinQueryClassName(item, 99, tmpbuf);
 		/* Don't set the ownership if it's an entryfield or spinbutton */
-		if(strncmp(tmpbuf, "#6", 3)!=0 && strncmp(tmpbuf, "#32", 3)!=0)
-		{
-			if((boxowner = WinQueryWindow(box, QW_OWNER)) != 0)
-				WinSetOwner(item, boxowner);
-			else
-				WinSetOwner(item, box);
-		}
+		if(strncmp(tmpbuf, "#6", 3)!=0 && strncmp(tmpbuf, "#32", 4)!=0)
+			WinSetOwner(item, box);
 		WinSetParent(item, box, FALSE);
 	}
 }
--- a/win/dw.c	Sat Dec 08 04:47:43 2001 +0000
+++ b/win/dw.c	Mon Jan 14 00:48:08 2002 +0000
@@ -2,7 +2,7 @@
  * Dynamic Windows:
  *          A GTK like implementation of the Win32 GUI
  *
- * (C) 2000,2001 Brian Smith <dbsoft@technologist.com>
+ * (C) 2000-2002 Brian Smith <dbsoft@technologist.com>
  *
  */
 #define _WIN32_IE 0x0500
@@ -26,6 +26,7 @@
 HINSTANCE DWInstance = NULL;
 
 DWORD dwVersion = 0;
+DWTID _dwtid = -1;
 
 /* I should probably check the actual file version, but this will do for now */
 #define IS_WIN98PLUS (LOBYTE(LOWORD(dwVersion)) > 4 || \
@@ -101,7 +102,7 @@
 static int in_checkbox_handler = 0;
 
 /* List of signals and their equivilent Win32 message */
-#define SIGNALMAX 14
+#define SIGNALMAX 15
 
 SignalList SignalTranslate[SIGNALMAX] = {
 	{ WM_SIZE, "configure_event" },
@@ -117,7 +118,8 @@
 	{ LBN_SELCHANGE, "item-select" },
 	{ TVN_SELCHANGED, "tree-select" },
 	{ WM_SETFOCUS, "set-focus" },
-	{ WM_USER+1, "lose-focus" }
+	{ WM_USER+1, "lose-focus" },
+	{ WM_VSCROLL, "value_changed" }
 };
 
 #ifdef BUILD_DLL
@@ -324,12 +326,13 @@
 	/* These are the window classes which can
 	 * obtain input focus.
 	 */
-	if(strnicmp(tmpbuf, EDITCLASSNAME, strlen(EDITCLASSNAME))==0 ||  /* Entryfield */
-	   strnicmp(tmpbuf, BUTTONCLASSNAME, strlen(BUTTONCLASSNAME))==0 ||  /* Button */
-	   strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME))==0 ||  /* Combobox */
-	   strnicmp(tmpbuf, LISTBOXCLASSNAME, strlen(LISTBOXCLASSNAME))==0 ||  /* List box */
-	   strnicmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS))==0 || /* Spinbutton */
-	   strnicmp(tmpbuf, WC_LISTVIEW, strlen(WC_LISTVIEW))== 0)  /* Container */
+	if(strnicmp(tmpbuf, EDITCLASSNAME, strlen(EDITCLASSNAME)+1)==0 ||          /* Entryfield */
+	   strnicmp(tmpbuf, BUTTONCLASSNAME, strlen(BUTTONCLASSNAME)+1)==0 ||      /* Button */
+	   strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0 ||  /* Combobox */
+	   strnicmp(tmpbuf, LISTBOXCLASSNAME, strlen(LISTBOXCLASSNAME)+1)==0 ||    /* List box */
+	   strnicmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS)+1)==0 ||            /* Spinbutton */
+	   strnicmp(tmpbuf, TRACKBAR_CLASS, strlen(TRACKBAR_CLASS)+1)==0 ||        /* Slider */
+	   strnicmp(tmpbuf, WC_LISTVIEW, strlen(WC_LISTVIEW)+1)== 0)               /* Container */
 		return 1;
 	return 0;
 }
@@ -1164,6 +1167,8 @@
 		msg = WM_LBUTTONDOWN;
 	if(msg == WM_RBUTTONUP || msg == WM_MBUTTONUP)
 		msg = WM_LBUTTONUP;
+	if(msg == WM_HSCROLL)
+		msg = WM_VSCROLL;
 
 	if(filterfunc)
 		result = filterfunc(hWnd, msg, mp1, mp2);
@@ -1412,6 +1417,33 @@
 						}
 					}
 					break;
+				case WM_HSCROLL:
+				case WM_VSCROLL:
+					{
+						char tmpbuf[100];
+                        HWND handle = (HWND)mp2;
+
+						GetClassName(handle, tmpbuf, 99);
+
+						if(strnicmp(tmpbuf, TRACKBAR_CLASS, strlen(TRACKBAR_CLASS)+1)==0)
+						{
+							int (*valuechangefunc)(HWND, int, void *) = tmp->signalfunction;
+
+							if(handle == tmp->window)
+							{
+								int value = (int)SendMessage(handle, TBM_GETPOS, 0, 0);
+								int max = (int)SendMessage(handle, TBM_GETRANGEMAX, 0, 0);
+								ULONG currentstyle = GetWindowLong(handle, GWL_STYLE);
+
+								if(currentstyle & TBS_VERT)
+									result = valuechangefunc(tmp->window, max - value, tmp->data);
+								else
+									result = valuechangefunc(tmp->window, value, tmp->data);
+								tmp = NULL;
+							}
+						}
+					}
+					break;
 				}
 			}
 			if(tmp)
@@ -1779,6 +1811,10 @@
 			else
 				_wndproc(hWnd, msg, mp1, mp2);
 			break;
+		case WM_VSCROLL:
+		case WM_HSCROLL:
+			_wndproc(hWnd, msg, mp1, mp2);
+			break;
 		case WM_CHAR:
 			if(LOWORD(mp1) == '\t')
 			{
@@ -2702,6 +2738,8 @@
 	/* Setup the filter function */
 	filterfunc = func;
 
+	_dwtid = dw_thread_id();
+
 	while (GetMessage(&msg, NULL, 0, 0))
 	{
 		TranslateMessage(&msg);
@@ -2714,16 +2752,16 @@
 }
 
 /*
- * Runs a message loop for Dynamic Windows, for a period of seconds.
- * Parameters:
- *           seconds: Number of seconds to run the loop for.
- */
-void dw_main_sleep(int seconds)
+ * Runs a message loop for Dynamic Windows, for a period of milliseconds.
+ * Parameters:
+ *           milliseconds: Number of milliseconds to run the loop for.
+ */
+void dw_main_sleep(int milliseconds)
 {
 	MSG msg;
-	time_t start = time(NULL);
-
-	while(time(NULL) - start <= seconds)
+	double start = (double)clock();
+
+	while(((clock() - start) / (CLOCKS_PER_SEC/1000)) <= milliseconds)
 	{
 		if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
 		{
@@ -3602,17 +3640,18 @@
 HWND dw_mle_new(ULONG id)
 {
     
-	HWND tmp = CreateWindow(EDITCLASSNAME,
-							"",
-							WS_BORDER |
-							WS_VSCROLL | ES_MULTILINE |
-							ES_WANTRETURN | WS_CHILD |
-							WS_CLIPCHILDREN,
-							0,0,2000,1000,
-							DW_HWND_OBJECT,
-							(HMENU)id,
-							NULL,
-							NULL);
+	HWND tmp = CreateWindowEx(WS_EX_CLIENTEDGE,
+							  EDITCLASSNAME,
+							  "",
+							  WS_BORDER |
+							  WS_VSCROLL | ES_MULTILINE |
+							  ES_WANTRETURN | WS_CHILD |
+							  WS_CLIPCHILDREN,
+							  0,0,2000,1000,
+							  DW_HWND_OBJECT,
+							  (HMENU)id,
+							  NULL,
+							  NULL);
 	dw_window_set_font(tmp, DefaultFont);
 	return tmp;
 }
@@ -3625,16 +3664,17 @@
  */
 HWND dw_entryfield_new(char *text, ULONG id)
 {
-	HWND tmp = CreateWindow(EDITCLASSNAME,
-							text,
-							ES_WANTRETURN | WS_CHILD |
-							WS_BORDER | ES_AUTOHSCROLL |
-							WS_CLIPCHILDREN,
-							0,0,2000,1000,
-							DW_HWND_OBJECT,
-							(HMENU)id,
-							NULL,
-							NULL);
+	HWND tmp = CreateWindowEx(WS_EX_CLIENTEDGE,
+							  EDITCLASSNAME,
+							  text,
+							  ES_WANTRETURN | WS_CHILD |
+							  WS_BORDER | ES_AUTOHSCROLL |
+							  WS_CLIPCHILDREN,
+							  0,0,2000,1000,
+							  DW_HWND_OBJECT,
+							  (HMENU)id,
+							  NULL,
+							  NULL);
 	ColorInfo *cinfo = calloc(1, sizeof(ColorInfo));
 
 	cinfo->back = cinfo->fore = -1;
@@ -3654,16 +3694,17 @@
  */
 HWND dw_entryfield_password_new(char *text, ULONG id)
 {
-	HWND tmp = CreateWindow(EDITCLASSNAME,
-							text,
-							ES_WANTRETURN | WS_CHILD |
-							ES_PASSWORD | WS_BORDER |
-							ES_AUTOHSCROLL | WS_CLIPCHILDREN,
-							0,0,2000,1000,
-							DW_HWND_OBJECT,
-							(HMENU)id,
-							NULL,
-							NULL);
+	HWND tmp = CreateWindowEx(WS_EX_CLIENTEDGE,
+							  EDITCLASSNAME,
+							  text,
+							  ES_WANTRETURN | WS_CHILD |
+							  ES_PASSWORD | WS_BORDER |
+							  ES_AUTOHSCROLL | WS_CLIPCHILDREN,
+							  0,0,2000,1000,
+							  DW_HWND_OBJECT,
+							  (HMENU)id,
+							  NULL,
+							  NULL);
 	ColorInfo *cinfo = calloc(1, sizeof(ColorInfo));
 
 	cinfo->back = cinfo->fore = -1;
@@ -3795,32 +3836,30 @@
 HWND dw_spinbutton_new(char *text, ULONG id)
 {
 	ULONG *data = malloc(sizeof(ULONG));
-	HWND buddy = CreateWindow(EDITCLASSNAME,
-							  text,
-							  WS_CHILD | WS_BORDER |
-							  ES_NUMBER | WS_CLIPCHILDREN,
+	HWND buddy = CreateWindowEx(WS_EX_CLIENTEDGE,
+								EDITCLASSNAME,
+								text,
+								WS_CHILD | WS_BORDER |
+								ES_NUMBER | WS_CLIPCHILDREN,
+								0,0,2000,1000,
+								DW_HWND_OBJECT,
+								NULL,
+								NULL,
+								NULL);
+	HWND tmp = CreateWindowEx(WS_EX_CLIENTEDGE,
+							  UPDOWN_CLASS,
+							  NULL,
+							  WS_CHILD | UDS_ALIGNRIGHT | WS_BORDER |
+							  UDS_ARROWKEYS | UDS_SETBUDDYINT |
+							  UDS_WRAP | UDS_NOTHOUSANDS,
 							  0,0,2000,1000,
 							  DW_HWND_OBJECT,
-							  NULL,
+							  (HMENU)id,
 							  NULL,
 							  NULL);
-	HWND tmp = CreateUpDownControl(
-								   WS_CHILD | UDS_ALIGNRIGHT |
-								   UDS_ARROWKEYS | UDS_SETBUDDYINT |
-								   UDS_WRAP | UDS_NOTHOUSANDS,
-								   0,
-								   0,
-								   2000,
-								   1000,
-								   DW_HWND_OBJECT,
-								   id,
-								   DWInstance,
-								   buddy,
-								   0,
-								   100,
-								   0);
 	ColorInfo *cinfo = calloc(1, sizeof(ColorInfo));
 
+	SendMessage(tmp, UDM_SETBUDDY, (WPARAM)buddy, 0);
 	cinfo->back = cinfo->fore = -1;
 	cinfo->buddy = tmp;
 
@@ -3853,7 +3892,35 @@
 							(HMENU)id,
 							NULL,
 							NULL);
-
+	BubbleButton *bubble = calloc(1, sizeof(BubbleButton));
+	bubble->id = id;
+	bubble->pOldProc = (WNDPROC)SubclassWindow(tmp, _BtProc);
+	bubble->cinfo.fore = -1;
+	bubble->cinfo.back = -1;
+	SetWindowLong(tmp, GWL_USERDATA, (ULONG)bubble);
+	dw_window_set_font(tmp, DefaultFont);
+	return tmp;
+}
+
+
+/*
+ * Create a new slider window (widget) to be packed.
+ * Parameters:
+ *       vertical: TRUE or FALSE if slider is vertical.
+ *       increments: Number of increments available.
+ *       id: An ID to be used with WinWindowFromID() or 0L.
+ */
+HWND dw_slider_new(int vertical, int increments, ULONG id)
+{
+	HWND tmp = CreateWindow(TRACKBAR_CLASS,
+							"",
+							WS_CHILD | WS_CLIPCHILDREN |
+							(vertical ? TBS_VERT : TBS_HORZ),
+							0,0,2000,1000,
+							DW_HWND_OBJECT,
+							NULL,
+							NULL,
+							NULL);
 	ColorInfo *cinfo = calloc(1, sizeof(ColorInfo));
 
 	cinfo->back = cinfo->fore = -1;
@@ -3862,11 +3929,10 @@
 
 	cinfo->pOldProc = SubclassWindow(tmp, _colorwndproc);
 	SetWindowLong(tmp, GWL_USERDATA, (ULONG)cinfo);
-	dw_window_set_font(tmp, DefaultFont);
+	SendMessage(tmp, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(0, increments-1));
 	return tmp;
 }
 
-
 /*
  * Create a new percent bar window (widget) to be packed.
  * Parameters:
@@ -4889,7 +4955,7 @@
 /*
  * Returns the range of the percent bar.
  * Parameters:
- *          handle: Handle to the slider to be queried.
+ *          handle: Handle to the percent bar to be queried.
  */
 unsigned int dw_percent_query_range(HWND handle)
 {
@@ -4899,8 +4965,8 @@
 /*
  * Sets the percent bar position.
  * Parameters:
- *          handle: Handle to the slider to be set.
- *          position: Position of the slider withing the range.
+ *          handle: Handle to the percent bar to be set.
+ *          position: Position of the percent bar withing the range.
  */
 void dw_percent_set_pos(HWND handle, unsigned int position)
 {
@@ -4908,6 +4974,38 @@
 }
 
 /*
+ * Returns the position of the slider.
+ * Parameters:
+ *          handle: Handle to the slider to be queried.
+ */
+unsigned int dw_slider_query_pos(HWND handle)
+{
+	int max = (int)SendMessage(handle, TBM_GETRANGEMAX, 0, 0);
+	ULONG currentstyle = GetWindowLong(handle, GWL_STYLE);
+
+	if(currentstyle & TBS_VERT)
+		return max - (unsigned int)SendMessage(handle, TBM_GETPOS, 0, 0);
+	return (unsigned int)SendMessage(handle, TBM_GETPOS, 0, 0);
+}
+
+/*
+ * Sets the slider position.
+ * Parameters:
+ *          handle: Handle to the slider to be set.
+ *          position: Position of the slider withing the range.
+ */
+void dw_slider_set_pos(HWND handle, unsigned int position)
+{
+	int max = (int)SendMessage(handle, TBM_GETRANGEMAX, 0, 0);
+	ULONG currentstyle = GetWindowLong(handle, GWL_STYLE);
+
+	if(currentstyle & TBS_VERT)
+		SendMessage(handle, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)max - position);
+	else
+		SendMessage(handle, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)position);
+}
+
+/*
  * Sets the spinbutton value.
  * Parameters:
  *          handle: Handle to the spinbutton to be set.
@@ -4981,6 +5079,22 @@
 	return (in_checkbox_handler ? TRUE : FALSE);
 }
 
+/* This function unchecks all radiobuttons on a box */
+BOOL CALLBACK _uncheck_radios(HWND handle, LPARAM lParam)
+{
+	char tmpbuf[100];
+
+	GetClassName(handle, tmpbuf, 99);
+
+	if(strnicmp(tmpbuf, BUTTONCLASSNAME, strlen(BUTTONCLASSNAME)+1)==0)
+	{
+		BubbleButton *bubble= (BubbleButton *)GetWindowLong(handle, GWL_USERDATA);
+
+		if(bubble && !bubble->checkbox)
+			SendMessage(handle, BM_SETCHECK, 0, 0);
+	}
+	return TRUE;
+}
 /*
  * Sets the state of the checkbox.
  * Parameters:
@@ -4989,10 +5103,15 @@
  */
 void dw_checkbox_set(HWND handle, int value)
 {
-	ColorInfo *cinfo = (ColorInfo *)GetWindowLong(handle, GWL_USERDATA);
-
-	if(cinfo && !cinfo->user)
-		SendMessage(handle, BM_CLICK, 0, 0);
+	BubbleButton *bubble= (BubbleButton *)GetWindowLong(handle, GWL_USERDATA);
+
+	if(bubble && !bubble->checkbox)
+	{
+		HWND parent = GetParent(handle);
+
+		if(parent)
+			EnumChildWindows(parent, _uncheck_radios, 0);
+	}
 	SendMessage(handle, BM_SETCHECK, (WPARAM)value, 0);
 }
 
@@ -6056,7 +6175,18 @@
  */
 void dw_mutex_lock(HMTX mutex)
 {
-	WaitForSingleObject((HANDLE)mutex, INFINITE);
+	if(_dwtid == dw_thread_id())
+	{
+		int rc = WaitForSingleObject((HANDLE)mutex, 0);
+
+		while(rc == WAIT_TIMEOUT)
+		{
+			dw_main_sleep(1);
+			rc = WaitForSingleObject((HANDLE)mutex, 0);
+		}
+	}
+    else
+		WaitForSingleObject((HANDLE)mutex, INFINITE);
 }
 
 /*