Merge pull request #5289 from RobLoach/libui

Updates for libui
This commit is contained in:
Twinaphex 2017-08-13 06:02:51 +02:00 committed by GitHub
commit 1666827ad4
121 changed files with 1484 additions and 1490 deletions

View File

@ -380,106 +380,62 @@ OBJ += $(OBJS_TLS_CRYPTO) $(OBJS_TLS_X509) $(OBJS_TLS)
endif endif
ifeq ($(HAVE_LIBUI), 1) ifeq ($(HAVE_LIBUI), 1)
ifeq ($(HAVE_GTKPLUS), 1) DEFINES += -DHAVE_LIBUI
CFLAGS += -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/atk-1.0
LIBS += -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0
OBJ += deps/libui/gtk/alloc.o \
deps/libui/gtk/area.o \
deps/libui/gtk/box.o \
deps/libui/gtk/button.o \
deps/libui/gtk/cellrendererbutton.o \
deps/libui/gtk/checkbox.o \
deps/libui/gtk/child.o \
deps/libui/gtk/colorbutton.o \
deps/libui/gtk/combobox.o \
deps/libui/gtk/control.o \
deps/libui/gtk/datetimepicker.o \
deps/libui/gtk/debug.o \
deps/libui/gtk/draw.o \
deps/libui/gtk/drawmatrix.o \
deps/libui/gtk/drawpath.o \
deps/libui/gtk/drawtext.o \
deps/libui/gtk/editablecombo.o \
deps/libui/gtk/entry.o \
deps/libui/gtk/fontbutton.o \
deps/libui/gtk/form.o \
deps/libui/gtk/future.o \
deps/libui/gtk/graphemes.o \
deps/libui/gtk/grid.o \
deps/libui/gtk/group.o \
deps/libui/gtk/image.o \
deps/libui/gtk/label.o \
deps/libui/gtk/main.o \
deps/libui/gtk/menu.o \
deps/libui/gtk/multilineentry.o \
deps/libui/gtk/progressbar.o \
deps/libui/gtk/radiobuttons.o \
deps/libui/gtk/separator.o \
deps/libui/gtk/slider.o \
deps/libui/gtk/spinbox.o \
deps/libui/gtk/stddialogs.o \
deps/libui/gtk/tab.o \
deps/libui/gtk/text.o \
deps/libui/gtk/util.o \
deps/libui/gtk/window.o
endif
ifneq ($(findstring Win32,$(OS)),) ifneq ($(findstring Win32,$(OS)),)
OBJ += deps/libui/win32/alloc.o \ OBJ += deps/libui/windows/alloc.o \
deps/libui/win32/area.o \ deps/libui/windows/area.o \
deps/libui/win32/areadraw.o \ deps/libui/windows/areadraw.o \
deps/libui/win32/areaevents.o \ deps/libui/windows/areaevents.o \
deps/libui/win32/areascroll.o \ deps/libui/windows/areascroll.o \
deps/libui/win32/areautil.o \ deps/libui/windows/areautil.o \
deps/libui/win32/box.o \ deps/libui/windows/box.o \
deps/libui/win32/button.o \ deps/libui/windows/button.o \
deps/libui/win32/checkbox.o \ deps/libui/windows/checkbox.o \
deps/libui/win32/colorbutton.o \ deps/libui/windows/colorbutton.o \
deps/libui/win32/colordialog.o \ deps/libui/windows/colordialog.o \
deps/libui/win32/combobox.o \ deps/libui/windows/combobox.o \
deps/libui/win32/container.o \ deps/libui/windows/container.o \
deps/libui/win32/control.o \ deps/libui/windows/control.o \
deps/libui/win32/d2dscratch.o \ deps/libui/windows/d2dscratch.o \
deps/libui/win32/datetimepicker.o \ deps/libui/windows/datetimepicker.o \
deps/libui/win32/debug.o \ deps/libui/windows/debug.o \
deps/libui/win32/draw.o \ deps/libui/windows/draw.o \
deps/libui/win32/drawmatrix.o \ deps/libui/windows/drawmatrix.o \
deps/libui/win32/drawpath.o \ deps/libui/windows/drawpath.o \
deps/libui/win32/drawtext.o \ deps/libui/windows/drawtext.o \
deps/libui/win32/dwrite.o \ deps/libui/windows/dwrite.o \
deps/libui/win32/editablecombo.o \ deps/libui/windows/editablecombo.o \
deps/libui/win32/entry.o \ deps/libui/windows/entry.o \
deps/libui/win32/events.o \ deps/libui/windows/events.o \
deps/libui/win32/fontbutton.o \ deps/libui/windows/fontbutton.o \
deps/libui/win32/fontdialog.o \ deps/libui/windows/fontdialog.o \
deps/libui/win32/form.o \ deps/libui/windows/form.o \
deps/libui/win32/graphemes.o \ deps/libui/windows/graphemes.o \
deps/libui/win32/grid.o \ deps/libui/windows/grid.o \
deps/libui/win32/group.o \ deps/libui/windows/group.o \
deps/libui/win32/init.o \ deps/libui/windows/init.o \
deps/libui/win32/label.o \ deps/libui/windows/label.o \
deps/libui/win32/main.o \ deps/libui/windows/main.o \
deps/libui/win32/menu.o \ deps/libui/windows/menu.o \
deps/libui/win32/multilineentry.o \ deps/libui/windows/multilineentry.o \
deps/libui/win32/parent.o \ deps/libui/windows/parent.o \
deps/libui/win32/progressbar.o \ deps/libui/windows/progressbar.o \
deps/libui/win32/radiobuttons.o \ deps/libui/windows/radiobuttons.o \
deps/libui/win32/separator.o \ deps/libui/windows/separator.o \
deps/libui/win32/sizing.o \ deps/libui/windows/sizing.o \
deps/libui/win32/slider.o \ deps/libui/windows/slider.o \
deps/libui/win32/spinbox.o \ deps/libui/windows/spinbox.o \
deps/libui/win32/stddialogs.o \ deps/libui/windows/stddialogs.o \
deps/libui/win32/tab.o \ deps/libui/windows/tab.o \
deps/libui/win32/tabpage.o \ deps/libui/windows/tabpage.o \
deps/libui/win32/text.o \ deps/libui/windows/text.o \
deps/libui/win32/utf16.o \ deps/libui/windows/utf16.o \
deps/libui/win32/utilwin.o \ deps/libui/windows/utilwin.o \
deps/libui/win32/window.o \ deps/libui/windows/window.o \
deps/libui/win32/winpublic.o \ deps/libui/windows/winpublic.o \
deps/libui/win32/winutil.o deps/libui/windows/winutil.o
LIBS += -luxtheme -ld2d1 -ldwrite -lusp10 LIBS += -luxtheme -ld2d1 -ldwrite -lusp10
endif else
ifneq ($(findstring Darwin,$(OS)),) ifneq ($(findstring Darwin,$(OS)),)
OBJ += deps/libui/darwin/alloc.o \ OBJ += deps/libui/darwin/alloc.o \
deps/libui/darwin/area.o \ deps/libui/darwin/area.o \
@ -519,6 +475,49 @@ OBJ += deps/libui/darwin/alloc.o \
deps/libui/darwin/util.o \ deps/libui/darwin/util.o \
deps/libui/darwin/window.o \ deps/libui/darwin/window.o \
deps/libui/darwin/winmoveresize.o deps/libui/darwin/winmoveresize.o
else
CFLAGS += -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/atk-1.0
LIBS += -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0
OBJ += deps/libui/unix/alloc.o \
deps/libui/unix/area.o \
deps/libui/unix/box.o \
deps/libui/unix/button.o \
deps/libui/unix/cellrendererbutton.o \
deps/libui/unix/checkbox.o \
deps/libui/unix/child.o \
deps/libui/unix/colorbutton.o \
deps/libui/unix/combobox.o \
deps/libui/unix/control.o \
deps/libui/unix/datetimepicker.o \
deps/libui/unix/debug.o \
deps/libui/unix/draw.o \
deps/libui/unix/drawmatrix.o \
deps/libui/unix/drawpath.o \
deps/libui/unix/drawtext.o \
deps/libui/unix/editablecombo.o \
deps/libui/unix/entry.o \
deps/libui/unix/fontbutton.o \
deps/libui/unix/form.o \
deps/libui/unix/future.o \
deps/libui/unix/graphemes.o \
deps/libui/unix/grid.o \
deps/libui/unix/group.o \
deps/libui/unix/image.o \
deps/libui/unix/label.o \
deps/libui/unix/main.o \
deps/libui/unix/menu.o \
deps/libui/unix/multilineentry.o \
deps/libui/unix/progressbar.o \
deps/libui/unix/radiobuttons.o \
deps/libui/unix/separator.o \
deps/libui/unix/slider.o \
deps/libui/unix/spinbox.o \
deps/libui/unix/stddialogs.o \
deps/libui/unix/tab.o \
deps/libui/unix/text.o \
deps/libui/unix/util.o \
deps/libui/unix/window.o
endif
endif endif
OBJ += deps/libui/common/areaevents.o \ OBJ += deps/libui/common/areaevents.o \

View File

@ -1868,7 +1868,7 @@ bool command_event(enum event_command cmd, void *data)
if (settings->bools.rewind_enable) if (settings->bools.rewind_enable)
{ {
#ifdef HAVE_NETWORKING #ifdef HAVE_NETWORKING
/* Only enable state manager if netplay is not underway /* Only enable state manager if netplay is not underway
TODO: Add a setting for these tweaks */ TODO: Add a setting for these tweaks */
if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)) if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
#endif #endif
@ -1899,7 +1899,7 @@ TODO: Add a setting for these tweaks */
#ifdef HAVE_THREADS #ifdef HAVE_THREADS
{ {
#ifdef HAVE_NETWORKING #ifdef HAVE_NETWORKING
/* Only enable state manager if netplay is not underway /* Only enable state manager if netplay is not underway
TODO: Add a setting for these tweaks */ TODO: Add a setting for these tweaks */
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
if (settings->uints.autosave_interval != 0 if (settings->uints.autosave_interval != 0
@ -2137,7 +2137,7 @@ TODO: Add a setting for these tweaks */
* need to make sure to keep a copy */ * need to make sure to keep a copy */
struct retro_hw_render_callback hwr_copy; struct retro_hw_render_callback hwr_copy;
struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); struct retro_hw_render_callback *hwr = video_driver_get_hw_context();
const struct retro_hw_render_context_negotiation_interface *iface = const struct retro_hw_render_context_negotiation_interface *iface =
video_driver_get_context_negotiation_interface(); video_driver_get_context_negotiation_interface();
memcpy(&hwr_copy, hwr, sizeof(hwr_copy)); memcpy(&hwr_copy, hwr, sizeof(hwr_copy));
@ -2210,7 +2210,7 @@ TODO: Add a setting for these tweaks */
RARCH_LOG("%s\n", msg_hash_to_str(MSG_PAUSED)); RARCH_LOG("%s\n", msg_hash_to_str(MSG_PAUSED));
command_event(CMD_EVENT_AUDIO_STOP, NULL); command_event(CMD_EVENT_AUDIO_STOP, NULL);
runloop_msg_queue_push(msg_hash_to_str(MSG_PAUSED), 1, runloop_msg_queue_push(msg_hash_to_str(MSG_PAUSED), 1,
1, true); 1, true);
if (!is_idle) if (!is_idle)
@ -2293,15 +2293,15 @@ TODO: Add a setting for these tweaks */
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
if (!init_netplay(NULL, hostname ? hostname : if (!init_netplay(NULL, hostname ? hostname :
settings->paths.netplay_server, settings->paths.netplay_server,
settings->uints.netplay_port)) settings->uints.netplay_port))
{ {
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
return false; return false;
} }
/* Disable rewind & sram autosave if it was enabled /* Disable rewind & sram autosave if it was enabled
TODO: Add a setting for these tweaks */ TODO: Add a setting for these tweaks */
state_manager_event_deinit(); state_manager_event_deinit();
#ifdef HAVE_THREADS #ifdef HAVE_THREADS
@ -2319,12 +2319,12 @@ TODO: Add a setting for these tweaks */
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
RARCH_LOG("[netplay] connecting to %s:%d\n", RARCH_LOG("[netplay] connecting to %s:%d\n",
hostname->elems[0].data, !string_is_empty(hostname->elems[1].data) hostname->elems[0].data, !string_is_empty(hostname->elems[1].data)
? atoi(hostname->elems[1].data) : 55435); ? atoi(hostname->elems[1].data) : 55435);
if (!init_netplay(NULL, hostname->elems[0].data, if (!init_netplay(NULL, hostname->elems[0].data,
!string_is_empty(hostname->elems[1].data) !string_is_empty(hostname->elems[1].data)
? atoi(hostname->elems[1].data) : 55435)) ? atoi(hostname->elems[1].data) : 55435))
{ {
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
@ -2334,7 +2334,7 @@ TODO: Add a setting for these tweaks */
string_list_free(hostname); string_list_free(hostname);
/* Disable rewind if it was enabled /* Disable rewind if it was enabled
TODO: Add a setting for these tweaks */ TODO: Add a setting for these tweaks */
state_manager_event_deinit(); state_manager_event_deinit();
#ifdef HAVE_THREADS #ifdef HAVE_THREADS
@ -2352,12 +2352,12 @@ TODO: Add a setting for these tweaks */
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
RARCH_LOG("[netplay] connecting to %s:%d\n", RARCH_LOG("[netplay] connecting to %s:%d\n",
hostname->elems[0].data, !string_is_empty(hostname->elems[1].data) hostname->elems[0].data, !string_is_empty(hostname->elems[1].data)
? atoi(hostname->elems[1].data) : 55435); ? atoi(hostname->elems[1].data) : 55435);
if (!init_netplay_deferred(hostname->elems[0].data, if (!init_netplay_deferred(hostname->elems[0].data,
!string_is_empty(hostname->elems[1].data) !string_is_empty(hostname->elems[1].data)
? atoi(hostname->elems[1].data) : 55435)) ? atoi(hostname->elems[1].data) : 55435))
{ {
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL); command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
@ -2367,7 +2367,7 @@ TODO: Add a setting for these tweaks */
string_list_free(hostname); string_list_free(hostname);
/* Disable rewind if it was enabled /* Disable rewind if it was enabled
TODO: Add a setting for these tweaks */ TODO: Add a setting for these tweaks */
state_manager_event_deinit(); state_manager_event_deinit();
#ifdef HAVE_THREADS #ifdef HAVE_THREADS
@ -2544,7 +2544,7 @@ TODO: Add a setting for these tweaks */
{ {
static bool game_focus_state = false; static bool game_focus_state = false;
intptr_t mode = (intptr_t)data; intptr_t mode = (intptr_t)data;
/* mode = -1: restores current game focus state /* mode = -1: restores current game focus state
* mode = 1: force set game focus, instead of toggling * mode = 1: force set game focus, instead of toggling
* any other: toggle * any other: toggle
@ -2609,7 +2609,7 @@ TODO: Add a setting for these tweaks */
command_event_restore_default_shader_preset(); command_event_restore_default_shader_preset();
break; break;
case CMD_EVENT_LIBUI_TEST: case CMD_EVENT_LIBUI_TEST:
#if 0 #if HAVE_LIBUI
libui_main(); libui_main();
#endif #endif
break; break;

9
deps/libui/LICENSE vendored Normal file
View File

@ -0,0 +1,9 @@
Copyright (c) 2014 Pietro Gagliardi
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(this is called the MIT License or Expat License; see http://www.opensource.org/licenses/MIT)

16
deps/libui/common/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,16 @@
# 3 june 2016
list(APPEND _LIBUI_SOURCES
common/areaevents.c
common/control.c
common/debug.c
common/matrix.c
common/shouldquit.c
common/userbugs.c
)
set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE)
list(APPEND _LIBUI_INCLUDEDIRS
common
)
set(_LIBUI_INCLUDEDIRS ${_LIBUI_INCLUDEDIRS} PARENT_SCOPE)

View File

@ -61,9 +61,11 @@ void uiControlDisable(uiControl *c)
uiControl *uiAllocControl(size_t size, uint32_t OSsig, uint32_t typesig, const char *typenamestr) uiControl *uiAllocControl(size_t size, uint32_t OSsig, uint32_t typesig, const char *typenamestr)
{ {
uiControl *c = (uiControl *) uiAlloc(size, typenamestr); uiControl *c;
c->Signature = uiControlSignature;
c->OSSignature = OSsig; c = (uiControl *) uiAlloc(size, typenamestr);
c->Signature = uiControlSignature;
c->OSSignature = OSsig;
c->TypeSignature = typesig; c->TypeSignature = typesig;
return c; return c;
} }
@ -90,11 +92,10 @@ void uiControlVerifySetParent(uiControl *c, uiControl *parent)
int uiControlEnabledToUser(uiControl *c) int uiControlEnabledToUser(uiControl *c)
{ {
while (c != NULL) while (c != NULL) {
{ if (!uiControlEnabled(c))
if (!uiControlEnabled(c)) return 0;
return 0; c = uiControlParent(c);
c = uiControlParent(c); }
}
return 1; return 1;
} }

View File

@ -1,4 +1,4 @@
/* 24 april 2016 */ // 24 april 2016
#define uiAreaSignature 0x41726561 #define uiAreaSignature 0x41726561
#define uiBoxSignature 0x426F784C #define uiBoxSignature 0x426F784C

View File

@ -1,4 +1,4 @@
/* 11 october 2015 */ // 11 october 2015
#include <math.h> #include <math.h>
#include "../ui.h" #include "../ui.h"
#include "uipriv.h" #include "uipriv.h"
@ -13,17 +13,17 @@ void uiDrawMatrixSetIdentity(uiDrawMatrix *m)
m->M32 = 0; m->M32 = 0;
} }
/* The rest of this file provides basic utilities in case the platform doesn't provide any of its own for these tasks. // The rest of this file provides basic utilities in case the platform doesn't provide any of its own for these tasks.
* Keep these as minimal as possible. They should generally not call other fallbacks. // Keep these as minimal as possible. They should generally not call other fallbacks.
* see https://msdn.microsoft.com/en-us/library/windows/desktop/ff684171%28v=vs.85%29.aspx#skew_transform // see https://msdn.microsoft.com/en-us/library/windows/desktop/ff684171%28v=vs.85%29.aspx#skew_transform
* TODO see if there's a way we can avoid the multiplication */ // TODO see if there's a way we can avoid the multiplication
void fallbackSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount) void fallbackSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount)
{ {
uiDrawMatrix n; uiDrawMatrix n;
uiDrawMatrixSetIdentity(&n); uiDrawMatrixSetIdentity(&n);
/* TODO explain this */ // TODO explain this
n.M12 = tan(yamount); n.M12 = tan(yamount);
n.M21 = tan(xamount); n.M21 = tan(xamount);
n.M31 = -y * tan(xamount); n.M31 = -y * tan(xamount);
@ -37,13 +37,13 @@ void scaleCenter(double xCenter, double yCenter, double *x, double *y)
*y = yCenter - (*y * yCenter); *y = yCenter - (*y * yCenter);
} }
/* the basic algorithm is from cairo // the basic algorithm is from cairo
* but it's the same algorithm as the transform point, // but it's the same algorithm as the transform point, just without M31 and M32 taken into account, so let's just do that instead
* just without M31 and M32 taken into account, so let's just do that instead */
void fallbackTransformSize(uiDrawMatrix *m, double *x, double *y) void fallbackTransformSize(uiDrawMatrix *m, double *x, double *y)
{ {
uiDrawMatrix m2 = *m; uiDrawMatrix m2;
m2 = *m;
m2.M31 = 0; m2.M31 = 0;
m2.M32 = 0; m2.M32 = 0;
uiDrawMatrixTransformPoint(&m2, x, y); uiDrawMatrixTransformPoint(&m2, x, y);

View File

@ -1,4 +1,4 @@
/* 6 april 2015 */ // 6 april 2015
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -13,7 +13,7 @@ extern void *uiAlloc(size_t, const char *);
extern void *uiRealloc(void *, size_t, const char *); extern void *uiRealloc(void *, size_t, const char *);
extern void uiFree(void *); extern void uiFree(void *);
/* ugh, this was only introduced in MSVC 2015... */ // ugh, this was only introduced in MSVC 2015...
#ifdef _MSC_VER #ifdef _MSC_VER
#define __func__ __FUNCTION__ #define __func__ __FUNCTION__
#endif #endif
@ -25,17 +25,16 @@ extern void _implbug(const char *file, const char *line, const char *func, const
extern void _userbug(const char *file, const char *line, const char *func, const char *format, ...); extern void _userbug(const char *file, const char *line, const char *func, const char *format, ...);
#define userbug(...) _userbug(__FILE__, _ns(__LINE__), __func__, __VA_ARGS__) #define userbug(...) _userbug(__FILE__, _ns(__LINE__), __func__, __VA_ARGS__)
/* control.c */ // control.c
extern uiControl *newControl(size_t size, uint32_t OSsig, uint32_t typesig, const char *typenamestr); extern uiControl *newControl(size_t size, uint32_t OSsig, uint32_t typesig, const char *typenamestr);
/* shouldquit.c */ // shouldquit.c
extern int shouldQuit(void); extern int shouldQuit(void);
/* areaevents.c */ // areaevents.c
typedef struct clickCounter clickCounter; typedef struct clickCounter clickCounter;
// you should call Reset() to zero-initialize a new instance
/* you should call Reset() to zero-initialize a new instance // it doesn't matter that all the non-count fields are zero: the first click will fail the curButton test straightaway, so it'll return 1 and set the rest of the structure accordingly
* it doesn't matter that all the non-count fields are zero: the first click will fail the curButton test straightaway, so it'll return 1 and set the rest of the structure accordingly */
struct clickCounter { struct clickCounter {
int curButton; int curButton;
int rectX0; int rectX0;
@ -49,7 +48,7 @@ int clickCounterClick(clickCounter *c, int button, int x, int y, uintptr_t time,
extern void clickCounterReset(clickCounter *); extern void clickCounterReset(clickCounter *);
extern int fromScancode(uintptr_t, uiAreaKeyEvent *); extern int fromScancode(uintptr_t, uiAreaKeyEvent *);
/* matrix.c */ // matrix.c
extern void fallbackSkew(uiDrawMatrix *, double, double, double, double); extern void fallbackSkew(uiDrawMatrix *, double, double, double, double);
extern void scaleCenter(double, double, double *, double *); extern void scaleCenter(double, double, double *, double *);
extern void fallbackTransformSize(uiDrawMatrix *, double *, double *); extern void fallbackTransformSize(uiDrawMatrix *, double *, double *);

79
deps/libui/darwin/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,79 @@
# 3 june 2016
list(APPEND _LIBUI_SOURCES
darwin/alloc.m
darwin/area.m
darwin/areaevents.m
darwin/autolayout.m
darwin/box.m
darwin/button.m
darwin/checkbox.m
darwin/colorbutton.m
darwin/combobox.m
darwin/control.m
darwin/datetimepicker.m
darwin/debug.m
darwin/draw.m
darwin/drawtext.m
darwin/editablecombo.m
darwin/entry.m
darwin/fontbutton.m
darwin/form.m
darwin/grid.m
darwin/group.m
darwin/image.m
darwin/label.m
darwin/main.m
darwin/map.m
darwin/menu.m
darwin/multilineentry.m
darwin/progressbar.m
darwin/radiobuttons.m
darwin/scrollview.m
darwin/separator.m
darwin/slider.m
darwin/spinbox.m
darwin/stddialogs.m
darwin/tab.m
darwin/text.m
darwin/util.m
darwin/window.m
darwin/winmoveresize.m
)
set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE)
list(APPEND _LIBUI_INCLUDEDIRS
darwin
)
set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE)
set(_LIBUINAME libui PARENT_SCOPE)
if(NOT BUILD_SHARED_LIBS)
set(_LIBUINAME libui-temporary PARENT_SCOPE)
endif()
# thanks to Mr-Hide in irc.freenode.net/#cmake
macro(_handle_static)
set_target_properties(${_LIBUINAME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(_aname $<TARGET_FILE:${_LIBUINAME}>)
set(_lname libui-combined.list)
set(_oname libui-combined.o)
add_custom_command(
OUTPUT ${_oname}
COMMAND
nm -m ${_aname} | sed -E -n "'s/^[0-9a-f]* \\([A-Z_]+,[a-z_]+\\) external //p'" > ${_lname}
COMMAND
ld -exported_symbols_list ${_lname} -r -all_load ${_aname} -o ${_oname}
COMMENT "Removing hidden symbols")
add_library(libui STATIC ${_oname})
# otherwise cmake won't know which linker to use
set_target_properties(libui PROPERTIES
LINKER_LANGUAGE C)
set(_aname)
set(_lname)
set(_oname)
endmacro()
set(_LIBUI_LIBS
objc "-framework Foundation" "-framework AppKit"
PARENT_SCOPE)

86
deps/libui/ui.h vendored
View File

@ -1,6 +1,6 @@
/* 6 april 2015 */ // 6 april 2015
/* TODO add a uiVerifyControlType() function that can be used by control implementations to verify controls */ // TODO add a uiVerifyControlType() function that can be used by control implementations to verify controls
#ifndef __LIBUI_UI_H__ #ifndef __LIBUI_UI_H__
#define __LIBUI_UI_H__ #define __LIBUI_UI_H__
@ -12,7 +12,7 @@
extern "C" { extern "C" {
#endif #endif
/* this macro is generated by cmake */ // this macro is generated by cmake
#ifdef libui_EXPORTS #ifdef libui_EXPORTS
#ifdef _WIN32 #ifdef _WIN32
#define _UI_EXTERN __declspec(dllexport) extern #define _UI_EXTERN __declspec(dllexport) extern
@ -20,19 +20,19 @@ extern "C" {
#define _UI_EXTERN __attribute__((visibility("default"))) extern #define _UI_EXTERN __attribute__((visibility("default"))) extern
#endif #endif
#else #else
/* TODO add __declspec(dllimport) on windows, but only if not static */ // TODO add __declspec(dllimport) on windows, but only if not static
#define _UI_EXTERN extern #define _UI_EXTERN extern
#endif #endif
/* C++ is really really really really really really dumb about enums, so screw that and just make them anonymous // C++ is really really really really really really dumb about enums, so screw that and just make them anonymous
* This has the advantage of being ABI-able should we ever need an ABI... */ // This has the advantage of being ABI-able should we ever need an ABI...
#define _UI_ENUM(s) typedef unsigned int s; enum #define _UI_ENUM(s) typedef unsigned int s; enum
/* This constant is provided because M_PI is nonstandard. // This constant is provided because M_PI is nonstandard.
* This comes from Go's math.Pi, which in turn comes from http://oeis.org/A000796. */ // This comes from Go's math.Pi, which in turn comes from http://oeis.org/A000796.
#define uiPi 3.14159265358979323846264338327950288419716939937510582097494459 #define uiPi 3.14159265358979323846264338327950288419716939937510582097494459
/* TODO uiBool? */ // TODO uiBool?
typedef struct uiInitOptions uiInitOptions; typedef struct uiInitOptions uiInitOptions;
@ -73,7 +73,7 @@ struct uiControl {
void (*Enable)(uiControl *); void (*Enable)(uiControl *);
void (*Disable)(uiControl *); void (*Disable)(uiControl *);
}; };
/* TOOD add argument names to all arguments */ // TOOD add argument names to all arguments
#define uiControl(this) ((uiControl *) (this)) #define uiControl(this) ((uiControl *) (this))
_UI_EXTERN void uiControlDestroy(uiControl *); _UI_EXTERN void uiControlDestroy(uiControl *);
_UI_EXTERN uintptr_t uiControlHandle(uiControl *); _UI_EXTERN uintptr_t uiControlHandle(uiControl *);
@ -90,7 +90,7 @@ _UI_EXTERN void uiControlDisable(uiControl *);
_UI_EXTERN uiControl *uiAllocControl(size_t n, uint32_t OSsig, uint32_t typesig, const char *typenamestr); _UI_EXTERN uiControl *uiAllocControl(size_t n, uint32_t OSsig, uint32_t typesig, const char *typenamestr);
_UI_EXTERN void uiFreeControl(uiControl *); _UI_EXTERN void uiFreeControl(uiControl *);
/* TODO make sure all controls have these */ // TODO make sure all controls have these
_UI_EXTERN void uiControlVerifySetParent(uiControl *, uiControl *); _UI_EXTERN void uiControlVerifySetParent(uiControl *, uiControl *);
_UI_EXTERN int uiControlEnabledToUser(uiControl *); _UI_EXTERN int uiControlEnabledToUser(uiControl *);
@ -174,11 +174,10 @@ _UI_EXTERN int uiGroupMargined(uiGroup *g);
_UI_EXTERN void uiGroupSetMargined(uiGroup *g, int margined); _UI_EXTERN void uiGroupSetMargined(uiGroup *g, int margined);
_UI_EXTERN uiGroup *uiNewGroup(const char *title); _UI_EXTERN uiGroup *uiNewGroup(const char *title);
/* spinbox/slider rules: // spinbox/slider rules:
* setting value outside of range will automatically clamp // setting value outside of range will automatically clamp
* initial value is minimum // initial value is minimum
* complaint if min >= max? // complaint if min >= max?
*/
typedef struct uiSpinbox uiSpinbox; typedef struct uiSpinbox uiSpinbox;
#define uiSpinbox(this) ((uiSpinbox *) (this)) #define uiSpinbox(this) ((uiSpinbox *) (this))
@ -218,7 +217,7 @@ typedef struct uiEditableCombobox uiEditableCombobox;
_UI_EXTERN void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text); _UI_EXTERN void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text);
_UI_EXTERN char *uiEditableComboboxText(uiEditableCombobox *c); _UI_EXTERN char *uiEditableComboboxText(uiEditableCombobox *c);
_UI_EXTERN void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text); _UI_EXTERN void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text);
/* TODO what do we call a function that sets the currently selected item and fills the text field with it? editable comboboxes have no consistent concept of selected item */ // TODO what do we call a function that sets the currently selected item and fills the text field with it? editable comboboxes have no consistent concept of selected item
_UI_EXTERN void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data); _UI_EXTERN void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data);
_UI_EXTERN uiEditableCombobox *uiNewEditableCombobox(void); _UI_EXTERN uiEditableCombobox *uiNewEditableCombobox(void);
@ -236,7 +235,7 @@ _UI_EXTERN uiDateTimePicker *uiNewDateTimePicker(void);
_UI_EXTERN uiDateTimePicker *uiNewDatePicker(void); _UI_EXTERN uiDateTimePicker *uiNewDatePicker(void);
_UI_EXTERN uiDateTimePicker *uiNewTimePicker(void); _UI_EXTERN uiDateTimePicker *uiNewTimePicker(void);
/* TODO provide a facility for entering tab stops? */ // TODO provide a facility for entering tab stops?
typedef struct uiMultilineEntry uiMultilineEntry; typedef struct uiMultilineEntry uiMultilineEntry;
#define uiMultilineEntry(this) ((uiMultilineEntry *) (this)) #define uiMultilineEntry(this) ((uiMultilineEntry *) (this))
_UI_EXTERN char *uiMultilineEntryText(uiMultilineEntry *e); _UI_EXTERN char *uiMultilineEntryText(uiMultilineEntry *e);
@ -292,8 +291,7 @@ struct uiAreaHandler {
// TODO RTL layouts? // TODO RTL layouts?
// TODO reconcile edge and corner naming // TODO reconcile edge and corner naming
_UI_ENUM(uiWindowResizeEdge) _UI_ENUM(uiWindowResizeEdge) {
{
uiWindowResizeEdgeLeft, uiWindowResizeEdgeLeft,
uiWindowResizeEdgeTop, uiWindowResizeEdgeTop,
uiWindowResizeEdgeRight, uiWindowResizeEdgeRight,
@ -301,10 +299,10 @@ _UI_ENUM(uiWindowResizeEdge)
uiWindowResizeEdgeTopLeft, uiWindowResizeEdgeTopLeft,
uiWindowResizeEdgeTopRight, uiWindowResizeEdgeTopRight,
uiWindowResizeEdgeBottomLeft, uiWindowResizeEdgeBottomLeft,
uiWindowResizeEdgeBottomRight uiWindowResizeEdgeBottomRight,
/* TODO have one for keyboard resizes? // TODO have one for keyboard resizes?
* TODO GDK doesn't seem to have any others, including for keyboards... // TODO GDK doesn't seem to have any others, including for keyboards...
* TODO way to bring up the system menu instead? */ // TODO way to bring up the system menu instead?
}; };
#define uiArea(this) ((uiArea *) (this)) #define uiArea(this) ((uiArea *) (this))
@ -348,29 +346,29 @@ _UI_ENUM(uiDrawBrushType) {
uiDrawBrushTypeSolid, uiDrawBrushTypeSolid,
uiDrawBrushTypeLinearGradient, uiDrawBrushTypeLinearGradient,
uiDrawBrushTypeRadialGradient, uiDrawBrushTypeRadialGradient,
uiDrawBrushTypeImage uiDrawBrushTypeImage,
}; };
_UI_ENUM(uiDrawLineCap) { _UI_ENUM(uiDrawLineCap) {
uiDrawLineCapFlat, uiDrawLineCapFlat,
uiDrawLineCapRound, uiDrawLineCapRound,
uiDrawLineCapSquare uiDrawLineCapSquare,
}; };
_UI_ENUM(uiDrawLineJoin) { _UI_ENUM(uiDrawLineJoin) {
uiDrawLineJoinMiter, uiDrawLineJoinMiter,
uiDrawLineJoinRound, uiDrawLineJoinRound,
uiDrawLineJoinBevel uiDrawLineJoinBevel,
}; };
/* this is the default for botoh cairo and Direct2D (in the latter case, from the C++ helper functions) // this is the default for botoh cairo and Direct2D (in the latter case, from the C++ helper functions)
* Core Graphics doesn't explicitly specify a default, but NSBezierPath allows you to choose one, and this is the initial value // Core Graphics doesn't explicitly specify a default, but NSBezierPath allows you to choose one, and this is the initial value
* so we're good to use it too! */ // so we're good to use it too!
#define uiDrawDefaultMiterLimit 10.0 #define uiDrawDefaultMiterLimit 10.0
_UI_ENUM(uiDrawFillMode) { _UI_ENUM(uiDrawFillMode) {
uiDrawFillModeWinding, uiDrawFillModeWinding,
uiDrawFillModeAlternate uiDrawFillModeAlternate,
}; };
struct uiDrawMatrix { struct uiDrawMatrix {
@ -385,13 +383,13 @@ struct uiDrawMatrix {
struct uiDrawBrush { struct uiDrawBrush {
uiDrawBrushType Type; uiDrawBrushType Type;
/* solid brushes */ // solid brushes
double R; double R;
double G; double G;
double B; double B;
double A; double A;
/* gradient brushes */ // gradient brushes
double X0; // linear: start X, radial: start X double X0; // linear: start X, radial: start X
double Y0; // linear: start Y, radial: start Y double Y0; // linear: start Y, radial: start Y
double X1; // linear: end X, radial: outer circle center X double X1; // linear: end X, radial: outer circle center X
@ -504,13 +502,13 @@ _UI_ENUM(uiDrawTextWeight) {
uiDrawTextWeightBold, uiDrawTextWeightBold,
uiDrawTextWeightUltraBold, uiDrawTextWeightUltraBold,
uiDrawTextWeightHeavy, uiDrawTextWeightHeavy,
uiDrawTextWeightUltraHeavy uiDrawTextWeightUltraHeavy,
}; };
_UI_ENUM(uiDrawTextItalic) { _UI_ENUM(uiDrawTextItalic) {
uiDrawTextItalicNormal, uiDrawTextItalicNormal,
uiDrawTextItalicOblique, uiDrawTextItalicOblique,
uiDrawTextItalicItalic uiDrawTextItalicItalic,
}; };
_UI_ENUM(uiDrawTextStretch) { _UI_ENUM(uiDrawTextStretch) {
@ -522,7 +520,7 @@ _UI_ENUM(uiDrawTextStretch) {
uiDrawTextStretchSemiExpanded, uiDrawTextStretchSemiExpanded,
uiDrawTextStretchExpanded, uiDrawTextStretchExpanded,
uiDrawTextStretchExtraExpanded, uiDrawTextStretchExtraExpanded,
uiDrawTextStretchUltraExpanded uiDrawTextStretchUltraExpanded,
}; };
struct uiDrawTextFontDescriptor { struct uiDrawTextFontDescriptor {
@ -563,10 +561,10 @@ _UI_EXTERN void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar
_UI_EXTERN void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout); _UI_EXTERN void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout);
_UI_ENUM(uiModifiers) { _UI_ENUM(uiModifiers) {
uiModifierCtrl = 1 << 0, uiModifierCtrl = 1 << 0,
uiModifierAlt = 1 << 1, uiModifierAlt = 1 << 1,
uiModifierShift = 1 << 2, uiModifierShift = 1 << 2,
uiModifierSuper = 1 << 3 uiModifierSuper = 1 << 3,
}; };
// TODO document drag captures // TODO document drag captures
@ -628,7 +626,7 @@ _UI_ENUM(uiExtKey) {
uiExtKeyNAdd, uiExtKeyNAdd,
uiExtKeyNSubtract, uiExtKeyNSubtract,
uiExtKeyNMultiply, uiExtKeyNMultiply,
uiExtKeyNDivide uiExtKeyNDivide,
}; };
struct uiAreaKeyEvent { struct uiAreaKeyEvent {
@ -643,9 +641,9 @@ struct uiAreaKeyEvent {
typedef struct uiFontButton uiFontButton; typedef struct uiFontButton uiFontButton;
#define uiFontButton(this) ((uiFontButton *) (this)) #define uiFontButton(this) ((uiFontButton *) (this))
/* TODO document this returns a new font */ // TODO document this returns a new font
_UI_EXTERN uiDrawTextFont *uiFontButtonFont(uiFontButton *b); _UI_EXTERN uiDrawTextFont *uiFontButtonFont(uiFontButton *b);
/* TOOD SetFont, mechanics */ // TOOD SetFont, mechanics
_UI_EXTERN void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data); _UI_EXTERN void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data);
_UI_EXTERN uiFontButton *uiNewFontButton(void); _UI_EXTERN uiFontButton *uiNewFontButton(void);
@ -668,14 +666,14 @@ _UI_ENUM(uiAlign) {
uiAlignFill, uiAlignFill,
uiAlignStart, uiAlignStart,
uiAlignCenter, uiAlignCenter,
uiAlignEnd uiAlignEnd,
}; };
_UI_ENUM(uiAt) { _UI_ENUM(uiAt) {
uiAtLeading, uiAtLeading,
uiAtTop, uiAtTop,
uiAtTrailing, uiAtTrailing,
uiAtBottom uiAtBottom,
}; };
typedef struct uiGrid uiGrid; typedef struct uiGrid uiGrid;

12
deps/libui/ui_unix.h vendored
View File

@ -1,4 +1,4 @@
/* 7 april 2015 */ // 7 april 2015
/* /*
This file assumes that you have included <gtk/gtk.h> and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls on Unix systems that use GTK+ to provide their UI (currently all except Mac OS X). This file assumes that you have included <gtk/gtk.h> and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls on Unix systems that use GTK+ to provide their UI (currently all except Mac OS X).
@ -19,7 +19,7 @@ struct uiUnixControl {
void (*SetContainer)(uiUnixControl *, GtkContainer *, gboolean); void (*SetContainer)(uiUnixControl *, GtkContainer *, gboolean);
}; };
#define uiUnixControl(this) ((uiUnixControl *) (this)) #define uiUnixControl(this) ((uiUnixControl *) (this))
/* TODO document */ // TODO document
_UI_EXTERN void uiUnixControlSetContainer(uiUnixControl *, GtkContainer *, gboolean); _UI_EXTERN void uiUnixControlSetContainer(uiUnixControl *, GtkContainer *, gboolean);
#define uiUnixControlDefaultDestroy(type) \ #define uiUnixControlDefaultDestroy(type) \
@ -80,7 +80,7 @@ _UI_EXTERN void uiUnixControlSetContainer(uiUnixControl *, GtkContainer *, gbool
{ \ { \
gtk_widget_set_sensitive(type(c)->widget, FALSE); \ gtk_widget_set_sensitive(type(c)->widget, FALSE); \
} }
/* TODO this whole addedBefore stuff is a MASSIVE HACK. */ // TODO this whole addedBefore stuff is a MASSIVE HACK.
#define uiUnixControlDefaultSetContainer(type) \ #define uiUnixControlDefaultSetContainer(type) \
static void type ## SetContainer(uiUnixControl *c, GtkContainer *container, gboolean remove) \ static void type ## SetContainer(uiUnixControl *c, GtkContainer *container, gboolean remove) \
{ \ { \
@ -112,7 +112,7 @@ _UI_EXTERN void uiUnixControlSetContainer(uiUnixControl *, GtkContainer *, gbool
uiUnixControlDefaultDestroy(type) \ uiUnixControlDefaultDestroy(type) \
uiUnixControlAllDefaultsExceptDestroy(type) uiUnixControlAllDefaultsExceptDestroy(type)
/* TODO document */ // TODO document
#define uiUnixNewControl(type, var) \ #define uiUnixNewControl(type, var) \
var = type(uiUnixAllocControl(sizeof (type), type ## Signature, #type)); \ var = type(uiUnixAllocControl(sizeof (type), type ## Signature, #type)); \
uiControl(var)->Destroy = type ## Destroy; \ uiControl(var)->Destroy = type ## Destroy; \
@ -127,10 +127,10 @@ _UI_EXTERN void uiUnixControlSetContainer(uiUnixControl *, GtkContainer *, gbool
uiControl(var)->Enable = type ## Enable; \ uiControl(var)->Enable = type ## Enable; \
uiControl(var)->Disable = type ## Disable; \ uiControl(var)->Disable = type ## Disable; \
uiUnixControl(var)->SetContainer = type ## SetContainer; uiUnixControl(var)->SetContainer = type ## SetContainer;
/* TODO document */ // TODO document
_UI_EXTERN uiUnixControl *uiUnixAllocControl(size_t n, uint32_t typesig, const char *typenamestr); _UI_EXTERN uiUnixControl *uiUnixAllocControl(size_t n, uint32_t typesig, const char *typenamestr);
/* uiUnixStrdupText() takes the given string and produces a copy of it suitable for being freed by uiFreeText(). */ // uiUnixStrdupText() takes the given string and produces a copy of it suitable for being freed by uiFreeText().
_UI_EXTERN char *uiUnixStrdupText(const char *); _UI_EXTERN char *uiUnixStrdupText(const char *);
#ifdef __cplusplus #ifdef __cplusplus

85
deps/libui/unix/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,85 @@
# 3 june 2016
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED gtk+-3.0)
list(APPEND _LIBUI_SOURCES
unix/alloc.c
unix/area.c
unix/box.c
unix/button.c
unix/cellrendererbutton.c
unix/checkbox.c
unix/child.c
unix/colorbutton.c
unix/combobox.c
unix/control.c
unix/datetimepicker.c
unix/debug.c
unix/draw.c
unix/drawmatrix.c
unix/drawpath.c
unix/drawtext.c
unix/editablecombo.c
unix/entry.c
unix/fontbutton.c
unix/form.c
unix/future.c
unix/graphemes.c
unix/grid.c
unix/group.c
unix/image.c
unix/label.c
unix/main.c
unix/menu.c
unix/multilineentry.c
unix/progressbar.c
unix/radiobuttons.c
unix/separator.c
unix/slider.c
unix/spinbox.c
unix/stddialogs.c
unix/tab.c
unix/text.c
unix/util.c
unix/window.c
)
set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE)
list(APPEND _LIBUI_INCLUDEDIRS
unix
)
set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE)
set(_LIBUINAME libui PARENT_SCOPE)
if(NOT BUILD_SHARED_LIBS)
set(_LIBUINAME libui-temporary PARENT_SCOPE)
endif()
macro(_handle_static)
set_target_properties(${_LIBUINAME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(_aname $<TARGET_FILE:${_LIBUINAME}>)
set(_oname libui-combined.o)
add_custom_command(
OUTPUT ${_oname}
COMMAND
ld -r --whole-archive ${_aname} -o ${_oname}
COMMAND
objcopy --localize-hidden ${_oname}
COMMENT "Removing hidden symbols")
add_library(libui STATIC ${_oname})
# otherwise cmake won't know which linker to use
set_target_properties(libui PROPERTIES
LINKER_LANGUAGE C)
set(_aname)
set(_oname)
endmacro()
# TODO the other variables don't work?
set(_LIBUI_CFLAGS
${GTK_CFLAGS}
PARENT_SCOPE)
set(_LIBUI_LIBS
${GTK_LDFLAGS} m ${CMAKE_DL_LIBS}
PARENT_SCOPE)

View File

@ -1,4 +1,4 @@
/* 7 april 2015 */ // 7 april 2015
#include <string.h> #include <string.h>
#include "uipriv_unix.h" #include "uipriv_unix.h"
@ -20,8 +20,8 @@ void initAlloc(void)
static void uninitComplain(gpointer ptr, gpointer data) static void uninitComplain(gpointer ptr, gpointer data)
{ {
char *str2 = NULL; char **str = (char **) data;
char **str = (char **)data; char *str2;
if (*str == NULL) if (*str == NULL)
*str = g_strdup_printf(""); *str = g_strdup_printf("");
@ -34,12 +34,10 @@ void uninitAlloc(void)
{ {
char *str = NULL; char *str = NULL;
if (allocations->len == 0) if (allocations->len == 0) {
{ g_ptr_array_free(allocations, TRUE);
g_ptr_array_free(allocations, TRUE); return;
return; }
}
g_ptr_array_foreach(allocations, uninitComplain, &str); g_ptr_array_foreach(allocations, uninitComplain, &str);
userbug("Some data was leaked; either you left a uiControl lying around or there's a bug in libui itself. Leaked data:\n%s", str); userbug("Some data was leaked; either you left a uiControl lying around or there's a bug in libui itself. Leaked data:\n%s", str);
g_free(str); g_free(str);
@ -47,8 +45,9 @@ void uninitAlloc(void)
void *uiAlloc(size_t size, const char *type) void *uiAlloc(size_t size, const char *type)
{ {
void *out = g_malloc0(EXTRA + size); void *out;
out = g_malloc0(EXTRA + size);
*SIZE(out) = size; *SIZE(out) = size;
*TYPE(out) = type; *TYPE(out) = type;
g_ptr_array_add(allocations, out); g_ptr_array_add(allocations, out);

View File

@ -114,10 +114,10 @@ static void loadAreaSize(uiArea *a, double *width, double *height)
static gboolean areaWidget_draw(GtkWidget *w, cairo_t *cr) static gboolean areaWidget_draw(GtkWidget *w, cairo_t *cr)
{ {
areaWidget *aw = areaWidget(w);
uiArea *a = aw->a;
uiAreaDrawParams dp; uiAreaDrawParams dp;
double clipX0, clipY0, clipX1, clipY1; double clipX0, clipY0, clipX1, clipY1;
areaWidget *aw = areaWidget(w);
uiArea *a = aw->a;
dp.Context = newContext(cr); dp.Context = newContext(cr);
@ -129,30 +129,25 @@ static gboolean areaWidget_draw(GtkWidget *w, cairo_t *cr)
dp.ClipWidth = clipX1 - clipX0; dp.ClipWidth = clipX1 - clipX0;
dp.ClipHeight = clipY1 - clipY0; dp.ClipHeight = clipY1 - clipY0;
/* no need to save or restore the graphics state // no need to save or restore the graphics state to reset transformations; GTK+ does that for us
* to reset transformations; GTK+ does that for us */
(*(a->ah->Draw))(a->ah, a, &dp); (*(a->ah->Draw))(a->ah, a, &dp);
freeContext(dp.Context); freeContext(dp.Context);
return FALSE; return FALSE;
} }
/* to do this properly for scrolling areas, we need to // to do this properly for scrolling areas, we need to
* - return the same value for min and nat // - return the same value for min and nat
* - call gtk_widget_queue_resize() when the size changes // - call gtk_widget_queue_resize() when the size changes
* thanks to Company in irc.gimp.net/#gtk+ */ // thanks to Company in irc.gimp.net/#gtk+
static void areaWidget_get_preferred_height(GtkWidget *w, static void areaWidget_get_preferred_height(GtkWidget *w, gint *min, gint *nat)
gint *min, gint *nat)
{ {
areaWidget *aw = areaWidget(w); areaWidget *aw = areaWidget(w);
uiArea *a = aw->a; uiArea *a = aw->a;
// always chain up just in case // always chain up just in case
GTK_WIDGET_CLASS(areaWidget_parent_class)-> GTK_WIDGET_CLASS(areaWidget_parent_class)->get_preferred_height(w, min, nat);
get_preferred_height(w, min, nat); if (a->scrolling) {
if (a->scrolling)
{
*min = a->scrollHeight; *min = a->scrollHeight;
*nat = a->scrollHeight; *nat = a->scrollHeight;
} }
@ -163,54 +158,51 @@ static void areaWidget_get_preferred_width(GtkWidget *w, gint *min, gint *nat)
areaWidget *aw = areaWidget(w); areaWidget *aw = areaWidget(w);
uiArea *a = aw->a; uiArea *a = aw->a;
/* always chain up just in case */ // always chain up just in case
GTK_WIDGET_CLASS(areaWidget_parent_class)->get_preferred_width(w, min, nat); GTK_WIDGET_CLASS(areaWidget_parent_class)->get_preferred_width(w, min, nat);
if (a->scrolling) if (a->scrolling) {
{ *min = a->scrollWidth;
*min = a->scrollWidth; *nat = a->scrollWidth;
*nat = a->scrollWidth; }
}
} }
static guint translateModifiers(guint state, GdkWindow *window) static guint translateModifiers(guint state, GdkWindow *window)
{ {
GdkModifierType statetype; GdkModifierType statetype;
/* GDK doesn't initialize the modifier flags fully; we have to // GDK doesn't initialize the modifier flags fully; we have to explicitly tell it to (thanks to Daniel_S and daniels (two different people) in irc.gimp.net/#gtk+)
* explicitly tell it to (thanks to Daniel_S and daniels statetype = state;
* (two different people) in irc.gimp.net/#gtk+) */ gdk_keymap_add_virtual_modifiers(
statetype = state; gdk_keymap_get_for_display(gdk_window_get_display(window)),
gdk_keymap_add_virtual_modifiers( &statetype);
gdk_keymap_get_for_display(gdk_window_get_display(window)), return statetype;
&statetype);
return statetype;
} }
static uiModifiers toModifiers(guint state) static uiModifiers toModifiers(guint state)
{ {
uiModifiers m = 0; uiModifiers m;
if ((state & GDK_CONTROL_MASK) != 0) m = 0;
m |= uiModifierCtrl; if ((state & GDK_CONTROL_MASK) != 0)
if ((state & GDK_META_MASK) != 0) m |= uiModifierCtrl;
m |= uiModifierAlt; if ((state & GDK_META_MASK) != 0)
/* GTK+ itself requires this to be Alt (just read through gtkaccelgroup.c) */ m |= uiModifierAlt;
if ((state & GDK_MOD1_MASK) != 0) if ((state & GDK_MOD1_MASK) != 0) // GTK+ itself requires this to be Alt (just read through gtkaccelgroup.c)
m |= uiModifierAlt; m |= uiModifierAlt;
if ((state & GDK_SHIFT_MASK) != 0) if ((state & GDK_SHIFT_MASK) != 0)
m |= uiModifierShift; m |= uiModifierShift;
if ((state & GDK_SUPER_MASK) != 0) if ((state & GDK_SUPER_MASK) != 0)
m |= uiModifierSuper; m |= uiModifierSuper;
return m; return m;
} }
/* capture on drag is done automatically on GTK+ */ // capture on drag is done automatically on GTK+
static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble x, gdouble y, guint state, GdkWindow *window) static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble x, gdouble y, guint state, GdkWindow *window)
{ {
/* on GTK+, mouse buttons 4-7 are for scrolling; if we got here, that's a mistake */ // on GTK+, mouse buttons 4-7 are for scrolling; if we got here, that's a mistake
if (mb >= 4 && mb <= 7) if (mb >= 4 && mb <= 7)
return; return;
/* if the button ID >= 8, continue counting from 4, as in the MouseEvent spec */ // if the button ID >= 8, continue counting from 4, as in the MouseEvent spec
if (me->Down >= 8) if (me->Down >= 8)
me->Down -= 4; me->Down -= 4;
if (me->Up >= 8) if (me->Up >= 8)
@ -219,7 +211,7 @@ static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble
state = translateModifiers(state, window); state = translateModifiers(state, window);
me->Modifiers = toModifiers(state); me->Modifiers = toModifiers(state);
/* the mb != # checks exclude the Up/Down button from Held */ // the mb != # checks exclude the Up/Down button from Held
me->Held1To64 = 0; me->Held1To64 = 0;
if (mb != 1 && (state & GDK_BUTTON1_MASK) != 0) if (mb != 1 && (state & GDK_BUTTON1_MASK) != 0)
me->Held1To64 |= 1 << 0; me->Held1To64 |= 1 << 0;
@ -227,19 +219,12 @@ static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble
me->Held1To64 |= 1 << 1; me->Held1To64 |= 1 << 1;
if (mb != 3 && (state & GDK_BUTTON3_MASK) != 0) if (mb != 3 && (state & GDK_BUTTON3_MASK) != 0)
me->Held1To64 |= 1 << 2; me->Held1To64 |= 1 << 2;
// don't check GDK_BUTTON4_MASK or GDK_BUTTON5_MASK because those are for the scrolling buttons mentioned above
// GDK expressly does not support any more buttons in the GdkModifierType; see https://git.gnome.org/browse/gtk+/tree/gdk/x11/gdkdevice-xi2.c#n763 (thanks mclasen in irc.gimp.net/#gtk+)
/* don't check GDK_BUTTON4_MASK or GDK_BUTTON5_MASK because those // these are already in drawing space coordinates
* are for the scrolling buttons mentioned above // the size of drawing space has the same value as the widget allocation
* // thanks to tristan in irc.gimp.net/#gtk+
* GDK expressly does not support any more buttons in the
* GdkModifierType; see
* https://git.gnome.org/browse/gtk+/tree/gdk/x11/gdkdevice-xi2.c#n763
* (thanks mclasen in irc.gimp.net/#gtk+)
*/
/* these are already in drawing space coordinates
* the size of drawing space has the same value as the widget allocation
* thanks to tristan in irc.gimp.net/#gtk+ */
me->X = x; me->X = x;
me->Y = y; me->Y = y;
@ -250,43 +235,37 @@ static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble
static gboolean areaWidget_button_press_event(GtkWidget *w, GdkEventButton *e) static gboolean areaWidget_button_press_event(GtkWidget *w, GdkEventButton *e)
{ {
areaWidget *aw = areaWidget(w);
uiArea *a = aw->a;
gint maxTime, maxDistance; gint maxTime, maxDistance;
GtkSettings *settings;
uiAreaMouseEvent me; uiAreaMouseEvent me;
areaWidget *aw = areaWidget(w);
uiArea *a = aw->a;
GtkSettings *settings = NULL;
/* clicking doesn't automatically transfer keyboard focus; // clicking doesn't automatically transfer keyboard focus; we must do so manually (thanks tristan in irc.gimp.net/#gtk+)
* we must do so manually (thanks tristan in irc.gimp.net/#gtk+) */
gtk_widget_grab_focus(w); gtk_widget_grab_focus(w);
/* we handle multiple clicks ourselves here, // we handle multiple clicks ourselves here, in the same way as we do on Windows
* in the same way as we do on Windows */
/* ignore GDK's generated double-clicks and beyond */
if (e->type != GDK_BUTTON_PRESS) if (e->type != GDK_BUTTON_PRESS)
// ignore GDK's generated double-clicks and beyond
return GDK_EVENT_PROPAGATE; return GDK_EVENT_PROPAGATE;
settings = gtk_widget_get_settings(w); settings = gtk_widget_get_settings(w);
g_object_get(settings, g_object_get(settings,
"gtk-double-click-time", &maxTime, "gtk-double-click-time", &maxTime,
"gtk-double-click-distance", &maxDistance, "gtk-double-click-distance", &maxDistance,
NULL); NULL);
// don't unref settings; it's transfer-none (thanks gregier in irc.gimp.net/#gtk+)
/* don't unref settings; it's transfer-none (thanks gregier in irc.gimp.net/#gtk+) // e->time is guint32
* e->time is guint32 // e->x and e->y are floating-point; just make them 32-bit integers
* e->x and e->y are floating-point; just make them 32-bit integers // maxTime and maxDistance... are gint, which *should* fit, hopefully...
* maxTime and maxDistance... are gint, which *should* fit, hopefully... */
me.Count = clickCounterClick(a->cc, me.Down, me.Count = clickCounterClick(a->cc, me.Down,
e->x, e->y, e->x, e->y,
e->time, maxTime, e->time, maxTime,
maxDistance, maxDistance); maxDistance, maxDistance);
me.Down = e->button; me.Down = e->button;
me.Up = 0; me.Up = 0;
/* and set things up for window drags */ // and set things up for window drags
a->dragevent = e; a->dragevent = e;
finishMouseEvent(a, &me, e->button, e->x, e->y, e->state, e->window); finishMouseEvent(a, &me, e->button, e->x, e->y, e->state, e->window);
a->dragevent = NULL; a->dragevent = NULL;
@ -295,37 +274,32 @@ static gboolean areaWidget_button_press_event(GtkWidget *w, GdkEventButton *e)
static gboolean areaWidget_button_release_event(GtkWidget *w, GdkEventButton *e) static gboolean areaWidget_button_release_event(GtkWidget *w, GdkEventButton *e)
{ {
uiAreaMouseEvent me; areaWidget *aw = areaWidget(w);
areaWidget *aw = areaWidget(w); uiArea *a = aw->a;
uiArea *a = aw->a; uiAreaMouseEvent me;
me.Down = 0; me.Down = 0;
me.Up = e->button; me.Up = e->button;
me.Count = 0; me.Count = 0;
finishMouseEvent(a, &me, e->button, e->x, e->y, e->state, e->window); finishMouseEvent(a, &me, e->button, e->x, e->y, e->state, e->window);
return GDK_EVENT_PROPAGATE; return GDK_EVENT_PROPAGATE;
} }
static gboolean areaWidget_motion_notify_event(GtkWidget *w, GdkEventMotion *e) static gboolean areaWidget_motion_notify_event(GtkWidget *w, GdkEventMotion *e)
{ {
uiAreaMouseEvent me;
areaWidget *aw = areaWidget(w); areaWidget *aw = areaWidget(w);
uiArea *a = aw->a; uiArea *a = aw->a;
uiAreaMouseEvent me;
me.Down = 0; me.Down = 0;
me.Up = 0; me.Up = 0;
me.Count = 0; me.Count = 0;
finishMouseEvent(a, &me, 0, e->x, e->y, e->state, e->window); finishMouseEvent(a, &me, 0, e->x, e->y, e->state, e->window);
return GDK_EVENT_PROPAGATE; return GDK_EVENT_PROPAGATE;
} }
/* we want switching away from the control to reset the double-click counter, // we want switching away from the control to reset the double-click counter, like with WM_ACTIVATE on Windows
* like with WM_ACTIVATE on Windows // according to tristan in irc.gimp.net/#gtk+, doing this on both enter-notify-event and leave-notify-event is correct (and it seems to be true in my own tests; plus the events DO get sent when switching programs with the keyboard (just pointing that out))
*
* according to tristan in irc.gimp.net/#gtk+, doing this on both
* enter-notify-event and leave-notify-event is correct (and it seems to be
* true in my own tests; plus the events DO get sent when switching programs
* with the keyboard (just pointing that out)) */
static gboolean onCrossing(areaWidget *aw, int left) static gboolean onCrossing(areaWidget *aw, int left)
{ {
uiArea *a = aw->a; uiArea *a = aw->a;
@ -345,15 +319,11 @@ static gboolean areaWidget_leave_notify_event(GtkWidget *w, GdkEventCrossing *e)
return onCrossing(areaWidget(w), 1); return onCrossing(areaWidget(w), 1);
} }
/* note: there is no equivalent to WM_CAPTURECHANGED on GTK+; there literally // note: there is no equivalent to WM_CAPTURECHANGED on GTK+; there literally is no way to break a grab like that (at least not on X11 and Wayland)
* is no way to break a grab like that (at least not on X11 and Wayland) // even if I invoke the task switcher and switch processes, the mouse grab will still be held until I let go of all buttons
* // therefore, no DragBroken()
* even if I invoke the task switcher and switch processes, the mouse grab will
* still be held until I let go of all buttons // we use GDK_KEY_Print as a sentinel because libui will never support the print screen key; that key belongs to the user
* therefore, no DragBroken()
*
* we use GDK_KEY_Print as a sentinel because libui will never support the print screen key; that key belongs to the user
*/
static const struct { static const struct {
guint keyval; guint keyval;
@ -382,7 +352,7 @@ static const struct {
{ GDK_KEY_F10, uiExtKeyF10 }, { GDK_KEY_F10, uiExtKeyF10 },
{ GDK_KEY_F11, uiExtKeyF11 }, { GDK_KEY_F11, uiExtKeyF11 },
{ GDK_KEY_F12, uiExtKeyF12 }, { GDK_KEY_F12, uiExtKeyF12 },
/* numpad numeric keys and . are handled in events.c */ // numpad numeric keys and . are handled in events.c
{ GDK_KEY_KP_Enter, uiExtKeyNEnter }, { GDK_KEY_KP_Enter, uiExtKeyNEnter },
{ GDK_KEY_KP_Add, uiExtKeyNAdd }, { GDK_KEY_KP_Add, uiExtKeyNAdd },
{ GDK_KEY_KP_Subtract, uiExtKeyNSubtract }, { GDK_KEY_KP_Subtract, uiExtKeyNSubtract },
@ -424,25 +394,23 @@ static int areaKeyEvent(uiArea *a, int up, GdkEventKey *e)
ke.Up = up; ke.Up = up;
for (i = 0; extKeys[i].keyval != GDK_KEY_Print; i++) for (i = 0; extKeys[i].keyval != GDK_KEY_Print; i++)
if (extKeys[i].keyval == e->keyval) if (extKeys[i].keyval == e->keyval) {
{
ke.ExtKey = extKeys[i].extkey; ke.ExtKey = extKeys[i].extkey;
goto keyFound; goto keyFound;
} }
for (i = 0; modKeys[i].keyval != GDK_KEY_Print; i++) for (i = 0; modKeys[i].keyval != GDK_KEY_Print; i++)
if (modKeys[i].keyval == e->keyval) if (modKeys[i].keyval == e->keyval) {
{ ke.Modifier = modKeys[i].mod;
ke.Modifier = modKeys[i].mod; // don't include the modifier in ke.Modifiers
/* don't include the modifier in ke.Modifiers */ ke.Modifiers &= ~ke.Modifier;
ke.Modifiers &= ~ke.Modifier; goto keyFound;
goto keyFound; }
}
if (fromScancode(e->hardware_keycode - 8, &ke)) if (fromScancode(e->hardware_keycode - 8, &ke))
goto keyFound; goto keyFound;
/* no supported key found; treat as unhandled */ // no supported key found; treat as unhandled
return 0; return 0;
keyFound: keyFound:
@ -452,7 +420,7 @@ keyFound:
static gboolean areaWidget_key_press_event(GtkWidget *w, GdkEventKey *e) static gboolean areaWidget_key_press_event(GtkWidget *w, GdkEventKey *e)
{ {
areaWidget *aw = areaWidget(w); areaWidget *aw = areaWidget(w);
uiArea *a = aw->a; uiArea *a = aw->a;
if (areaKeyEvent(a, 0, e)) if (areaKeyEvent(a, 0, e))
return GDK_EVENT_STOP; return GDK_EVENT_STOP;
@ -478,16 +446,15 @@ static GParamSpec *pspecArea;
static void areaWidget_set_property(GObject *obj, guint prop, const GValue *value, GParamSpec *pspec) static void areaWidget_set_property(GObject *obj, guint prop, const GValue *value, GParamSpec *pspec)
{ {
areaWidget *aw = areaWidget(obj); areaWidget *aw = areaWidget(obj);
switch (prop) switch (prop) {
{ case pArea:
case pArea: aw->a = (uiArea *) g_value_get_pointer(value);
aw->a = (uiArea *) g_value_get_pointer(value); aw->a->cc = &(aw->cc);
aw->a->cc = &(aw->cc); return;
return; }
} G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec);
} }
static void areaWidget_get_property(GObject *obj, guint prop, GValue *value, GParamSpec *pspec) static void areaWidget_get_property(GObject *obj, guint prop, GValue *value, GParamSpec *pspec)
@ -541,8 +508,8 @@ void uiAreaQueueRedrawAll(uiArea *a)
void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height) void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height)
{ {
/* TODO // TODO
* TODO adjust adjustments and find source for that */ // TODO adjust adjustments and find source for that
} }
void uiAreaBeginUserWindowMove(uiArea *a) void uiAreaBeginUserWindowMove(uiArea *a)
@ -551,23 +518,25 @@ void uiAreaBeginUserWindowMove(uiArea *a)
if (a->dragevent == NULL) if (a->dragevent == NULL)
userbug("cannot call uiAreaBeginUserWindowMove() outside of a Mouse() with Down != 0"); userbug("cannot call uiAreaBeginUserWindowMove() outside of a Mouse() with Down != 0");
/* TODO don't we have a libui function for this? did I scrap it? // TODO don't we have a libui function for this? did I scrap it?
* TODO widget or areaWidget? */ // TODO widget or areaWidget?
toplevel = gtk_widget_get_toplevel(a->widget); toplevel = gtk_widget_get_toplevel(a->widget);
// TODO if (toplevel == NULL) {
if (toplevel == NULL) // TODO
return; return;
/* the docs say to do this */ }
// the docs say to do this
/* TODO */ if (!gtk_widget_is_toplevel(toplevel)) {
if (!gtk_widget_is_toplevel(toplevel)) // TODO
return; return;
/* TODO */ }
if (!GTK_IS_WINDOW(toplevel)) if (!GTK_IS_WINDOW(toplevel)) {
// TODO
return; return;
}
gtk_window_begin_move_drag(GTK_WINDOW(toplevel), gtk_window_begin_move_drag(GTK_WINDOW(toplevel),
a->dragevent->button, a->dragevent->button,
a->dragevent->x_root, /* TODO are these correct? */ a->dragevent->x_root, // TODO are these correct?
a->dragevent->y_root, a->dragevent->y_root,
a->dragevent->time); a->dragevent->time);
} }
@ -589,25 +558,26 @@ void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge)
if (a->dragevent == NULL) if (a->dragevent == NULL)
userbug("cannot call uiAreaBeginUserWindowResize() outside of a Mouse() with Down != 0"); userbug("cannot call uiAreaBeginUserWindowResize() outside of a Mouse() with Down != 0");
/* TODO don't we have a libui function for this? did I scrap it? // TODO don't we have a libui function for this? did I scrap it?
* TODO widget or areaWidget? */ // TODO widget or areaWidget?
toplevel = gtk_widget_get_toplevel(a->widget); toplevel = gtk_widget_get_toplevel(a->widget);
if (toplevel == NULL) {
/* TODO */ // TODO
if (toplevel == NULL)
return; return;
/* the docs say to do this */ }
// the docs say to do this
/* TODO */ if (!gtk_widget_is_toplevel(toplevel)) {
if (!gtk_widget_is_toplevel(toplevel)) // TODO
return; return;
/* TODO */ }
if (!GTK_IS_WINDOW(toplevel)) if (!GTK_IS_WINDOW(toplevel)) {
// TODO
return; return;
}
gtk_window_begin_resize_drag(GTK_WINDOW(toplevel), gtk_window_begin_resize_drag(GTK_WINDOW(toplevel),
edges[edge], edges[edge],
a->dragevent->button, a->dragevent->button,
a->dragevent->x_root, /* TODO are these correct? */ a->dragevent->x_root, // TODO are these correct?
a->dragevent->y_root, a->dragevent->y_root,
a->dragevent->time); a->dragevent->time);
} }
@ -656,8 +626,7 @@ uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height)
a->widget = a->swidget; a->widget = a->swidget;
gtk_container_add(a->scontainer, a->areaWidget); gtk_container_add(a->scontainer, a->areaWidget);
/* and make the area visible; only the scrolled // and make the area visible; only the scrolled window's visibility is controlled by libui
* window's visibility is controlled by libui */
gtk_widget_show(a->areaWidget); gtk_widget_show(a->areaWidget);
return a; return a;

View File

@ -1,26 +1,24 @@
// 7 april 2015 // 7 april 2015
#include "uipriv_unix.h" #include "uipriv_unix.h"
struct boxChild struct boxChild {
{ uiControl *c;
uiControl *c; int stretchy;
int stretchy; gboolean oldhexpand;
gboolean oldhexpand; GtkAlign oldhalign;
GtkAlign oldhalign; gboolean oldvexpand;
gboolean oldvexpand; GtkAlign oldvalign;
GtkAlign oldvalign;
}; };
struct uiBox struct uiBox {
{ uiUnixControl c;
uiUnixControl c; GtkWidget *widget;
GtkWidget *widget; GtkContainer *container;
GtkContainer *container; GtkBox *box;
GtkBox *box; GArray *controls;
GArray *controls; int vertical;
int vertical; int padded;
int padded; GtkSizeGroup *stretchygroup; // ensures all stretchy controls have the same size
GtkSizeGroup *stretchygroup; /* ensures all stretchy controls have the same size */
}; };
uiUnixControlAllDefaultsExceptDestroy(uiBox) uiUnixControlAllDefaultsExceptDestroy(uiBox)
@ -33,19 +31,18 @@ static void uiBoxDestroy(uiControl *c)
struct boxChild *bc; struct boxChild *bc;
guint i; guint i;
/* kill the size group */ // kill the size group
g_object_unref(b->stretchygroup); g_object_unref(b->stretchygroup);
/* free all controls */ // free all controls
for (i = 0; i < b->controls->len; i++) for (i = 0; i < b->controls->len; i++) {
{ bc = ctrl(b, i);
bc = ctrl(b, i); uiControlSetParent(bc->c, NULL);
uiControlSetParent(bc->c, NULL); // and make sure the widget itself stays alive
/* and make sure the widget itself stays alive */ uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE);
uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE); uiControlDestroy(bc->c);
uiControlDestroy(bc->c); }
}
g_array_free(b->controls, TRUE); g_array_free(b->controls, TRUE);
/* and then ourselves */ // and then ourselves
g_object_unref(b->widget); g_object_unref(b->widget);
uiFreeControl(uiControl(b)); uiFreeControl(uiControl(b));
} }
@ -53,7 +50,7 @@ static void uiBoxDestroy(uiControl *c)
void uiBoxAppend(uiBox *b, uiControl *c, int stretchy) void uiBoxAppend(uiBox *b, uiControl *c, int stretchy)
{ {
struct boxChild bc; struct boxChild bc;
GtkWidget *widget = NULL; GtkWidget *widget;
bc.c = c; bc.c = c;
bc.stretchy = stretchy; bc.stretchy = stretchy;
@ -77,7 +74,7 @@ void uiBoxAppend(uiBox *b, uiControl *c, int stretchy)
gtk_widget_set_vexpand(widget, FALSE); gtk_widget_set_vexpand(widget, FALSE);
else else
gtk_widget_set_hexpand(widget, FALSE); gtk_widget_set_hexpand(widget, FALSE);
/* and make them fill the opposite direction */ // and make them fill the opposite direction
if (b->vertical) { if (b->vertical) {
gtk_widget_set_hexpand(widget, TRUE); gtk_widget_set_hexpand(widget, TRUE);
gtk_widget_set_halign(widget, GTK_ALIGN_FILL); gtk_widget_set_halign(widget, GTK_ALIGN_FILL);
@ -93,8 +90,11 @@ void uiBoxAppend(uiBox *b, uiControl *c, int stretchy)
void uiBoxDelete(uiBox *b, int index) void uiBoxDelete(uiBox *b, int index)
{ {
struct boxChild *bc = ctrl(b, index); struct boxChild *bc;
GtkWidget *widget = GTK_WIDGET(uiControlHandle(bc->c)); GtkWidget *widget;
bc = ctrl(b, index);
widget = GTK_WIDGET(uiControlHandle(bc->c));
uiControlSetParent(bc->c, NULL); uiControlSetParent(bc->c, NULL);
uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE); uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE);

View File

@ -1,8 +1,7 @@
// 10 june 2015 // 10 june 2015
#include "uipriv_unix.h" #include "uipriv_unix.h"
struct uiButton struct uiButton {
{
uiUnixControl c; uiUnixControl c;
GtkWidget *widget; GtkWidget *widget;
GtkButton *button; GtkButton *button;
@ -21,7 +20,7 @@ static void onClicked(GtkButton *button, gpointer data)
static void defaultOnClicked(uiButton *b, void *data) static void defaultOnClicked(uiButton *b, void *data)
{ {
/* do nothing */ // do nothing
} }
char *uiButtonText(uiButton *b) char *uiButtonText(uiButton *b)
@ -36,7 +35,7 @@ void uiButtonSetText(uiButton *b, const char *text)
void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *, void *), void *data) void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *, void *), void *data)
{ {
b->onClicked = f; b->onClicked = f;
b->onClickedData = data; b->onClickedData = data;
} }

View File

@ -28,7 +28,7 @@ struct child {
struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parentContainer) struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parentContainer)
{ {
struct child *c = NULL; struct child *c;
if (child == NULL) if (child == NULL)
return NULL; return NULL;
@ -51,8 +51,8 @@ struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parent
struct child *newChildWithBox(uiControl *child, uiControl *parent, GtkContainer *parentContainer, int margined) struct child *newChildWithBox(uiControl *child, uiControl *parent, GtkContainer *parentContainer, int margined)
{ {
struct child *c = NULL; struct child *c;
GtkWidget *box = NULL; GtkWidget *box;
if (child == NULL) if (child == NULL)
return NULL; return NULL;
@ -87,11 +87,11 @@ void childRemove(struct child *c)
void childDestroy(struct child *c) void childDestroy(struct child *c)
{ {
uiControl *child = NULL; uiControl *child;
child = c->c; child = c->c;
childRemove(c); childRemove(c);
uiControlDestroy(child); uiControlDestroy(child);
} }
GtkWidget *childWidget(struct child *c) GtkWidget *childWidget(struct child *c)

View File

@ -14,31 +14,30 @@
typedef struct dateTimePickerWidget dateTimePickerWidget; typedef struct dateTimePickerWidget dateTimePickerWidget;
typedef struct dateTimePickerWidgetClass dateTimePickerWidgetClass; typedef struct dateTimePickerWidgetClass dateTimePickerWidgetClass;
struct dateTimePickerWidget struct dateTimePickerWidget {
{ GtkToggleButton parent_instance;
GtkToggleButton parent_instance;
gulong toggledSignal; gulong toggledSignal;
gboolean hasTime; gboolean hasTime;
gboolean hasDate; gboolean hasDate;
GtkWidget *window; GtkWidget *window;
GtkWidget *box; GtkWidget *box;
GtkWidget *calendar; GtkWidget *calendar;
GtkWidget *timebox; GtkWidget *timebox;
GtkWidget *hours; GtkWidget *hours;
GtkWidget *minutes; GtkWidget *minutes;
GtkWidget *seconds; GtkWidget *seconds;
GtkWidget *ampm; GtkWidget *ampm;
gulong hoursBlock; gulong hoursBlock;
gulong minutesBlock; gulong minutesBlock;
gulong secondsBlock; gulong secondsBlock;
gulong ampmBlock; gulong ampmBlock;
GdkDevice *keyboard; GdkDevice *keyboard;
GdkDevice *mouse; GdkDevice *mouse;
}; };
struct dateTimePickerWidgetClass { struct dateTimePickerWidgetClass {
@ -49,7 +48,9 @@ G_DEFINE_TYPE(dateTimePickerWidget, dateTimePickerWidget, GTK_TYPE_TOGGLE_BUTTON
static int realSpinValue(GtkSpinButton *spinButton) static int realSpinValue(GtkSpinButton *spinButton)
{ {
GtkAdjustment *adj = gtk_spin_button_get_adjustment(spinButton); GtkAdjustment *adj;
adj = gtk_spin_button_get_adjustment(spinButton);
return (int) gtk_adjustment_get_value(adj); return (int) gtk_adjustment_get_value(adj);
} }
@ -69,14 +70,11 @@ static GDateTime *selected(dateTimePickerWidget *d)
guint year = 1970, month = 1, day = 1; guint year = 1970, month = 1, day = 1;
guint hour = 0, minute = 0, second = 0; guint hour = 0, minute = 0, second = 0;
if (d->hasDate) if (d->hasDate) {
{
gtk_calendar_get_date(GTK_CALENDAR(d->calendar), &year, &month, &day); gtk_calendar_get_date(GTK_CALENDAR(d->calendar), &year, &month, &day);
month++; /* GtkCalendar/GDateTime differences */ month++; // GtkCalendar/GDateTime differences
} }
if (d->hasTime) {
if (d->hasTime)
{
hour = realSpinValue(GTK_SPIN_BUTTON(d->hours)); hour = realSpinValue(GTK_SPIN_BUTTON(d->hours));
if (realSpinValue(GTK_SPIN_BUTTON(d->ampm)) != 0) if (realSpinValue(GTK_SPIN_BUTTON(d->ampm)) != 0)
hour += 12; hour += 12;
@ -88,22 +86,21 @@ static GDateTime *selected(dateTimePickerWidget *d)
static void setLabel(dateTimePickerWidget *d) static void setLabel(dateTimePickerWidget *d)
{ {
char *fmt = NULL; GDateTime *dt;
char *msg = NULL; char *fmt;
GDateTime *dt = selected(d); char *msg;
gboolean free = FALSE; gboolean free;
if (d->hasDate && d->hasTime) dt = selected(d);
{ free = FALSE;
/* don't use D_T_FMT; that's too verbose */ if (d->hasDate && d->hasTime) {
fmt = g_strdup_printf("%s %s", nl_langinfo(D_FMT), nl_langinfo(T_FMT)); // don't use D_T_FMT; that's too verbose
fmt = g_strdup_printf("%s %s", nl_langinfo(D_FMT), nl_langinfo(T_FMT));
free = TRUE; free = TRUE;
} } else if (d->hasDate)
else if (d->hasDate) fmt = nl_langinfo(D_FMT);
fmt = nl_langinfo(D_FMT);
else else
fmt = nl_langinfo(T_FMT); fmt = nl_langinfo(T_FMT);
msg = g_date_time_format(dt, fmt); msg = g_date_time_format(dt, fmt);
gtk_button_set_label(GTK_BUTTON(d), msg); gtk_button_set_label(GTK_BUTTON(d), msg);
g_free(msg); g_free(msg);
@ -147,31 +144,32 @@ static void hidePopup(dateTimePickerWidget *d)
// this consolidates a good chunk of what GtkComboBox does // this consolidates a good chunk of what GtkComboBox does
static gboolean startGrab(dateTimePickerWidget *d) static gboolean startGrab(dateTimePickerWidget *d)
{ {
GdkDevice *dev;
guint32 time; guint32 time;
GdkWindow *window = NULL; GdkWindow *window;
GdkDevice *keyboard = NULL; GdkDevice *keyboard, *mouse;
GdkDevice *mouse = NULL;
GdkDevice *dev = gtk_get_current_event_device();
if (dev == NULL) dev = gtk_get_current_event_device();
{ if (dev == NULL) {
// this is what GtkComboBox does // this is what GtkComboBox does
// since no device was set, just use the first available "master device" // since no device was set, just use the first available "master device"
GdkDisplay *disp = gtk_widget_get_display(GTK_WIDGET(d)); GdkDisplay *disp;
GdkDeviceManager *dm = gdk_display_get_device_manager(disp); GdkDeviceManager *dm;
GList *list = gdk_device_manager_list_devices(dm, GDK_DEVICE_TYPE_MASTER); GList *list;
disp = gtk_widget_get_display(GTK_WIDGET(d));
dm = gdk_display_get_device_manager(disp);
list = gdk_device_manager_list_devices(dm, GDK_DEVICE_TYPE_MASTER);
dev = (GdkDevice *) (list->data); dev = (GdkDevice *) (list->data);
g_list_free(list); g_list_free(list);
} }
time = gtk_get_current_event_time(); time = gtk_get_current_event_time();
keyboard = dev; keyboard = dev;
mouse = gdk_device_get_associated_device(dev); mouse = gdk_device_get_associated_device(dev);
if (gdk_device_get_source(dev) != GDK_SOURCE_KEYBOARD) {
if (gdk_device_get_source(dev) != GDK_SOURCE_KEYBOARD) dev = mouse;
{ mouse = keyboard;
dev = mouse;
mouse = keyboard;
keyboard = dev; keyboard = dev;
} }
@ -198,7 +196,7 @@ static gboolean startGrab(dateTimePickerWidget *d)
return TRUE; return TRUE;
} }
/* based on gtk_combo_box_list_position() in the GTK+ source code */ // based on gtk_combo_box_list_position() in the GTK+ source code
static void allocationToScreen(dateTimePickerWidget *d, gint *x, gint *y) static void allocationToScreen(dateTimePickerWidget *d, gint *x, gint *y)
{ {
GdkWindow *window; GdkWindow *window;
@ -279,17 +277,15 @@ static gboolean grabBroken(GtkWidget *w, GdkEventGrabBroken *e, gpointer data)
static gboolean buttonReleased(GtkWidget *w, GdkEventButton *e, gpointer data) static gboolean buttonReleased(GtkWidget *w, GdkEventButton *e, gpointer data)
{ {
dateTimePickerWidget *d = dateTimePickerWidget(data);
int winx, winy; int winx, winy;
GtkAllocation wina; GtkAllocation wina;
gboolean in; gboolean in;
dateTimePickerWidget *d = dateTimePickerWidget(data);
gtk_widget_get_allocation(d->window, &wina); gtk_widget_get_allocation(d->window, &wina);
winx = 0; winx = 0;
winy = 0; winy = 0;
if (!gtk_widget_get_has_window(d->window)) {
if (!gtk_widget_get_has_window(d->window))
{
winx = wina.x; winx = wina.x;
winy = wina.y; winy = wina.y;
} }
@ -311,9 +307,11 @@ static gboolean buttonReleased(GtkWidget *w, GdkEventButton *e, gpointer data)
static gint hoursSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data) static gint hoursSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data)
{ {
double *out = (double *) ptr; double *out = (double *) ptr;
const gchar *text = gtk_entry_get_text(GTK_ENTRY(sb)); const gchar *text;
int value = (int) g_strtod(text, NULL); int value;
text = gtk_entry_get_text(GTK_ENTRY(sb));
value = (int) g_strtod(text, NULL);
if (value < 0 || value > 12) if (value < 0 || value > 12)
return GTK_INPUT_ERROR; return GTK_INPUT_ERROR;
if (value == 12) // 12 to the user is 0 internally if (value == 12) // 12 to the user is 0 internally
@ -324,9 +322,10 @@ static gint hoursSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data)
static gboolean hoursSpinboxOutput(GtkSpinButton *sb, gpointer data) static gboolean hoursSpinboxOutput(GtkSpinButton *sb, gpointer data)
{ {
gchar *text = NULL; gchar *text;
int value = realSpinValue(sb); int value;
value = realSpinValue(sb);
if (value == 0) // 0 internally is 12 to the user if (value == 0) // 0 internally is 12 to the user
value = 12; value = 12;
text = g_strdup_printf("%d", value); text = g_strdup_printf("%d", value);
@ -337,9 +336,11 @@ static gboolean hoursSpinboxOutput(GtkSpinButton *sb, gpointer data)
static gboolean zeroPadSpinbox(GtkSpinButton *sb, gpointer data) static gboolean zeroPadSpinbox(GtkSpinButton *sb, gpointer data)
{ {
int value = realSpinValue(sb); gchar *text;
gchar *text = g_strdup_printf("%02d", value); int value;
value = realSpinValue(sb);
text = g_strdup_printf("%02d", value);
gtk_entry_set_text(GTK_ENTRY(sb), text); gtk_entry_set_text(GTK_ENTRY(sb), text);
g_free(text); g_free(text);
return TRUE; return TRUE;
@ -348,20 +349,19 @@ static gboolean zeroPadSpinbox(GtkSpinButton *sb, gpointer data)
// this is really hacky but we can't use GtkCombobox here :( // this is really hacky but we can't use GtkCombobox here :(
static gint ampmSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data) static gint ampmSpinboxInput(GtkSpinButton *sb, gpointer ptr, gpointer data)
{ {
double *out = (double *) ptr; double *out = (double *) ptr;
const gchar *text = gtk_entry_get_text(GTK_ENTRY(sb)); const gchar *text;
// LONGTERM don't use ASCII here for case insensitivity char firstAM, firstPM;
char firstAM = g_ascii_tolower(nl_langinfo(AM_STR)[0]);
char firstPM = g_ascii_tolower(nl_langinfo(PM_STR)[0]);
text = gtk_entry_get_text(GTK_ENTRY(sb));
// LONGTERM don't use ASCII here for case insensitivity
firstAM = g_ascii_tolower(nl_langinfo(AM_STR)[0]);
firstPM = g_ascii_tolower(nl_langinfo(PM_STR)[0]);
for (; *text != '\0'; text++) for (; *text != '\0'; text++)
if (g_ascii_tolower(*text) == firstAM) if (g_ascii_tolower(*text) == firstAM) {
{
*out = 0; *out = 0;
return TRUE; return TRUE;
} } else if (g_ascii_tolower(*text) == firstPM) {
else if (g_ascii_tolower(*text) == firstPM)
{
*out = 1; *out = 1;
return TRUE; return TRUE;
} }
@ -387,21 +387,20 @@ static void spinboxChanged(GtkSpinButton *sb, gpointer data)
dateTimeChanged(d); dateTimeChanged(d);
} }
static GtkWidget *newSpinbox(dateTimePickerWidget *d, int min, int max, static GtkWidget *newSpinbox(dateTimePickerWidget *d, int min, int max, gint (*input)(GtkSpinButton *, gpointer, gpointer), gboolean (*output)(GtkSpinButton *, gpointer), gulong *block)
gint (*input)(GtkSpinButton *, gpointer, gpointer),
gboolean (*output)(GtkSpinButton *, gpointer), gulong *block)
{ {
GtkWidget *sb = gtk_spin_button_new_with_range(min, max, 1); GtkWidget *sb;
gtk_spin_button_set_digits(GTK_SPIN_BUTTON(sb), 0); sb = gtk_spin_button_new_with_range(min, max, 1);
gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(sb), TRUE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(sb), 0);
gtk_orientable_set_orientation(GTK_ORIENTABLE(sb), GTK_ORIENTATION_VERTICAL); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(sb), TRUE);
*block = g_signal_connect(sb, "value-changed", G_CALLBACK(spinboxChanged), d); gtk_orientable_set_orientation(GTK_ORIENTABLE(sb), GTK_ORIENTATION_VERTICAL);
if (input != NULL) *block = g_signal_connect(sb, "value-changed", G_CALLBACK(spinboxChanged), d);
g_signal_connect(sb, "input", G_CALLBACK(input), NULL); if (input != NULL)
if (output != NULL) g_signal_connect(sb, "input", G_CALLBACK(input), NULL);
g_signal_connect(sb, "output", G_CALLBACK(output), NULL); if (output != NULL)
return sb; g_signal_connect(sb, "output", G_CALLBACK(output), NULL);
return sb;
} }
static void dateChanged(GtkCalendar *c, gpointer data) static void dateChanged(GtkCalendar *c, gpointer data)
@ -537,14 +536,18 @@ static void dateTimePickerWidget_class_init(dateTimePickerWidgetClass *class)
static GtkWidget *newDTP(void) static GtkWidget *newDTP(void)
{ {
GtkWidget *w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); GtkWidget *w;
w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL));
setLabel(dateTimePickerWidget(w)); setLabel(dateTimePickerWidget(w));
return w; return w;
} }
static GtkWidget *newDP(void) static GtkWidget *newDP(void)
{ {
GtkWidget *w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); GtkWidget *w;
w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL));
setDateOnly(dateTimePickerWidget(w)); setDateOnly(dateTimePickerWidget(w));
setLabel(dateTimePickerWidget(w)); setLabel(dateTimePickerWidget(w));
return w; return w;
@ -552,17 +555,18 @@ static GtkWidget *newDP(void)
static GtkWidget *newTP(void) static GtkWidget *newTP(void)
{ {
GtkWidget *w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL)); GtkWidget *w;
w = GTK_WIDGET(g_object_new(dateTimePickerWidgetType, "label", "", NULL));
setTimeOnly(dateTimePickerWidget(w)); setTimeOnly(dateTimePickerWidget(w));
setLabel(dateTimePickerWidget(w)); setLabel(dateTimePickerWidget(w));
return w; return w;
} }
struct uiDateTimePicker struct uiDateTimePicker {
{ uiUnixControl c;
uiUnixControl c; GtkWidget *widget;
GtkWidget *widget; dateTimePickerWidget *d;
dateTimePickerWidget *d;
}; };
uiUnixControlAllDefaults(uiDateTimePicker) uiUnixControlAllDefaults(uiDateTimePicker)
@ -574,7 +578,7 @@ uiDateTimePicker *finishNewDateTimePicker(GtkWidget *(*fn)(void))
uiUnixNewControl(uiDateTimePicker, d); uiUnixNewControl(uiDateTimePicker, d);
d->widget = (*fn)(); d->widget = (*fn)();
d->d = dateTimePickerWidget(d->widget); d->d = dateTimePickerWidget(d->widget);
return d; return d;
} }

View File

@ -1,27 +1,25 @@
// 8 june 2016 // 8 june 2016
#include "uipriv_unix.h" #include "uipriv_unix.h"
struct formChild struct formChild {
{ uiControl *c;
uiControl *c; int stretchy;
int stretchy; GtkWidget *label;
GtkWidget *label; gboolean oldhexpand;
gboolean oldhexpand; GtkAlign oldhalign;
GtkAlign oldhalign; gboolean oldvexpand;
gboolean oldvexpand; GtkAlign oldvalign;
GtkAlign oldvalign; GBinding *labelBinding;
GBinding *labelBinding;
}; };
struct uiForm struct uiForm {
{ uiUnixControl c;
uiUnixControl c; GtkWidget *widget;
GtkWidget *widget; GtkContainer *container;
GtkContainer *container; GtkGrid *grid;
GtkGrid *grid; GArray *children;
GArray *children; int padded;
int padded; GtkSizeGroup *stretchygroup; // ensures all stretchy controls have the same size
GtkSizeGroup *stretchygroup; /* ensures all stretchy controls have the same size */
}; };
uiUnixControlAllDefaultsExceptDestroy(uiForm) uiUnixControlAllDefaultsExceptDestroy(uiForm)
@ -34,19 +32,18 @@ static void uiFormDestroy(uiControl *c)
struct formChild *fc; struct formChild *fc;
guint i; guint i;
/* kill the size group */ // kill the size group
g_object_unref(f->stretchygroup); g_object_unref(f->stretchygroup);
/* free all controls */ // free all controls
for (i = 0; i < f->children->len; i++) for (i = 0; i < f->children->len; i++) {
{ fc = ctrl(f, i);
fc = ctrl(f, i); uiControlSetParent(fc->c, NULL);
uiControlSetParent(fc->c, NULL); uiUnixControlSetContainer(uiUnixControl(fc->c), f->container, TRUE);
uiUnixControlSetContainer(uiUnixControl(fc->c), f->container, TRUE); uiControlDestroy(fc->c);
uiControlDestroy(fc->c); gtk_widget_destroy(fc->label);
gtk_widget_destroy(fc->label); }
}
g_array_free(f->children, TRUE); g_array_free(f->children, TRUE);
/* and then ourselves */ // and then ourselves
g_object_unref(f->widget); g_object_unref(f->widget);
uiFreeControl(uiControl(f)); uiFreeControl(uiControl(f));
} }
@ -71,7 +68,7 @@ void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy)
gtk_size_group_add_widget(f->stretchygroup, widget); gtk_size_group_add_widget(f->stretchygroup, widget);
} else } else
gtk_widget_set_vexpand(widget, FALSE); gtk_widget_set_vexpand(widget, FALSE);
/* and make them fill horizontally */ // and make them fill horizontally
gtk_widget_set_hexpand(widget, TRUE); gtk_widget_set_hexpand(widget, TRUE);
gtk_widget_set_halign(widget, GTK_ALIGN_FILL); gtk_widget_set_halign(widget, GTK_ALIGN_FILL);
@ -88,7 +85,7 @@ void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy)
gtk_grid_attach(f->grid, fc.label, gtk_grid_attach(f->grid, fc.label,
0, row, 0, row,
1, 1); 1, 1);
/* and make them share visibility so if the control is hidden, so is its label */ // and make them share visibility so if the control is hidden, so is its label
fc.labelBinding = g_object_bind_property(GTK_WIDGET(uiControlHandle(fc.c)), "visible", fc.labelBinding = g_object_bind_property(GTK_WIDGET(uiControlHandle(fc.c)), "visible",
fc.label, "visible", fc.label, "visible",
G_BINDING_SYNC_CREATE); G_BINDING_SYNC_CREATE);
@ -97,7 +94,7 @@ void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy)
uiUnixControlSetContainer(uiUnixControl(fc.c), f->container, FALSE); uiUnixControlSetContainer(uiUnixControl(fc.c), f->container, FALSE);
g_array_append_val(f->children, fc); g_array_append_val(f->children, fc);
/* move the widget to the correct place */ // move the widget to the correct place
gtk_container_child_set(f->container, widget, gtk_container_child_set(f->container, widget,
"left-attach", 1, "left-attach", 1,
"top-attach", row, "top-attach", row,

View File

@ -52,10 +52,8 @@ void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, in
cs = cairo_image_surface_create_for_data(buf, CAIRO_FORMAT_ARGB32, cs = cairo_image_surface_create_for_data(buf, CAIRO_FORMAT_ARGB32,
pixelWidth, pixelHeight, pixelWidth, pixelHeight,
cstride); cstride);
if (cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS)
/* TODO */ /* TODO */;
if (cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) { }
cairo_surface_flush(cs); cairo_surface_flush(cs);
g_ptr_array_add(i->images, cs); g_ptr_array_add(i->images, cs);
} }
@ -69,7 +67,7 @@ struct matcher {
gboolean foundLarger; gboolean foundLarger;
}; };
/* TODO is this the right algorithm? */ // TODO is this the right algorithm?
static void match(gpointer surface, gpointer data) static void match(gpointer surface, gpointer data)
{ {
cairo_surface_t *cs = (cairo_surface_t *) surface; cairo_surface_t *cs = (cairo_surface_t *) surface;
@ -83,11 +81,11 @@ static void match(gpointer surface, gpointer data)
goto writeMatch; goto writeMatch;
if (x < m->targetX && y < m->targetY) if (x < m->targetX && y < m->targetY)
if (m->foundLarger) /* always prefer larger ones */ if (m->foundLarger)
// always prefer larger ones
return; return;
/* we set foundLarger below */
if (x >= m->targetX && y >= m->targetY && !m->foundLarger) if (x >= m->targetX && y >= m->targetY && !m->foundLarger)
// we set foundLarger below
goto writeMatch; goto writeMatch;
x2 = abs(m->targetX - x); x2 = abs(m->targetX - x);
@ -95,11 +93,11 @@ static void match(gpointer surface, gpointer data)
if (x2 < m->distX && y2 < m->distY) if (x2 < m->distX && y2 < m->distY)
goto writeMatch; goto writeMatch;
/* TODO weight one dimension? threshhold? */ // TODO weight one dimension? threshhold?
return; return;
writeMatch: writeMatch:
/* must set this here too; otherwise the first image will never have ths set */ // must set this here too; otherwise the first image will never have ths set
if (x >= m->targetX && y >= m->targetY && !m->foundLarger) if (x >= m->targetX && y >= m->targetY && !m->foundLarger)
m->foundLarger = TRUE; m->foundLarger = TRUE;
m->best = cs; m->best = cs;

View File

@ -6,15 +6,14 @@ uiInitOptions options;
const char *uiInit(uiInitOptions *o) const char *uiInit(uiInitOptions *o)
{ {
GError *err = NULL; GError *err = NULL;
const char *msg;
options = *o; options = *o;
if (gtk_init_with_args(NULL, NULL, NULL, NULL, NULL, &err) == FALSE) {
if (gtk_init_with_args(NULL, NULL, NULL, NULL, NULL, &err) == FALSE) msg = g_strdup(err->message);
{ g_error_free(err);
const char *msg = g_strdup(err->message); return msg;
g_error_free(err); }
return msg;
}
initAlloc(); initAlloc();
loadFutures(); loadFutures();
return NULL; return NULL;
@ -41,9 +40,8 @@ void uiMain(void)
static gboolean stepsQuit = FALSE; static gboolean stepsQuit = FALSE;
/* the only difference is we ignore the return value from gtk_main_iteration_do(), // the only difference is we ignore the return value from gtk_main_iteration_do(), since it will always be TRUE if gtk_main() was never called
* since it will always be TRUE if gtk_main() was never called // gtk_main_iteration_do() will still run the main loop regardless
* gtk_main_iteration_do() will still run the main loop regardless */
static gboolean stepsIteration(gboolean block) static gboolean stepsIteration(gboolean block)
{ {
gtk_main_iteration_do(block); gtk_main_iteration_do(block);
@ -57,7 +55,9 @@ void uiMainSteps(void)
int uiMainStep(int wait) int uiMainStep(int wait)
{ {
gboolean block = FALSE; gboolean block;
block = FALSE;
if (wait) if (wait)
block = TRUE; block = TRUE;
return (*iteration)(block) == FALSE; return (*iteration)(block) == FALSE;
@ -70,8 +70,7 @@ static gboolean quit(gpointer data)
{ {
if (iteration == stepsIteration) if (iteration == stepsIteration)
stepsQuit = TRUE; stepsQuit = TRUE;
/* TODO run a gtk_main() here just to do the cleanup steps of // TODO run a gtk_main() here just to do the cleanup steps of syncing the clipboard and other stuff gtk_main() does before it returns
* syncing the clipboard and other stuff gtk_main() does before it returns */
else else
gtk_main_quit(); gtk_main_quit();
return FALSE; return FALSE;
@ -98,12 +97,12 @@ static gboolean doqueued(gpointer data)
void uiQueueMain(void (*f)(void *data), void *data) void uiQueueMain(void (*f)(void *data), void *data)
{ {
struct queued *q = g_new0(struct queued, 1); struct queued *q;
/* we have to use g_new0()/g_free() because uiAlloc() // we have to use g_new0()/g_free() because uiAlloc() is only safe to call on the main thread
* is only safe to call on the main thread // for some reason it didn't affect me, but it did affect krakjoe
* for some reason it didn't affect me, but it did affect krakjoe */ q = g_new0(struct queued, 1);
q->f = f; q->f = f;
q->data = data; q->data = data;
gdk_threads_add_idle(doqueued, q); gdk_threads_add_idle(doqueued, q);
} }

View File

@ -121,8 +121,10 @@ int uiMenuItemChecked(uiMenuItem *item)
void uiMenuItemSetChecked(uiMenuItem *item, int checked) void uiMenuItemSetChecked(uiMenuItem *item, int checked)
{ {
/* use explicit values */ gboolean c;
gboolean c = FALSE;
// use explicit values
c = FALSE;
if (checked) if (checked)
c = TRUE; c = TRUE;
setChecked(item, c); setChecked(item, c);
@ -130,55 +132,55 @@ void uiMenuItemSetChecked(uiMenuItem *item, int checked)
static uiMenuItem *newItem(uiMenu *m, int type, const char *name) static uiMenuItem *newItem(uiMenu *m, int type, const char *name)
{ {
uiMenuItem *item; uiMenuItem *item;
if (menusFinalized) if (menusFinalized)
userbug("You cannot create a new menu item after menus have been finalized."); userbug("You cannot create a new menu item after menus have been finalized.");
item = uiNew(uiMenuItem); item = uiNew(uiMenuItem);
g_array_append_val(m->items, item); g_array_append_val(m->items, item);
item->type = type; item->type = type;
switch (item->type) { switch (item->type) {
case typeQuit: case typeQuit:
item->name = g_strdup("Quit"); item->name = g_strdup("Quit");
break; break;
case typePreferences: case typePreferences:
item->name = g_strdup("Preferences..."); item->name = g_strdup("Preferences...");
break; break;
case typeAbout: case typeAbout:
item->name = g_strdup("About"); item->name = g_strdup("About");
break; break;
case typeSeparator: case typeSeparator:
break; break;
default: default:
item->name = g_strdup(name); item->name = g_strdup(name);
break; break;
} }
if (item->type == typeQuit) { if (item->type == typeQuit) {
// can't call uiMenuItemOnClicked() here // can't call uiMenuItemOnClicked() here
item->onClicked = onQuitClicked; item->onClicked = onQuitClicked;
item->onClickedData = NULL; item->onClickedData = NULL;
} else } else
uiMenuItemOnClicked(item, defaultOnClicked, NULL); uiMenuItemOnClicked(item, defaultOnClicked, NULL);
switch (item->type) { switch (item->type) {
case typeCheckbox: case typeCheckbox:
item->gtype = GTK_TYPE_CHECK_MENU_ITEM; item->gtype = GTK_TYPE_CHECK_MENU_ITEM;
break; break;
case typeSeparator: case typeSeparator:
item->gtype = GTK_TYPE_SEPARATOR_MENU_ITEM; item->gtype = GTK_TYPE_SEPARATOR_MENU_ITEM;
break; break;
default: default:
item->gtype = GTK_TYPE_MENU_ITEM; item->gtype = GTK_TYPE_MENU_ITEM;
break; break;
} }
item->windows = g_hash_table_new(g_direct_hash, g_direct_equal); item->windows = g_hash_table_new(g_direct_hash, g_direct_equal);
return item; return item;
} }
uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name) uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name)

View File

@ -32,10 +32,9 @@ int uiSpinboxValue(uiSpinbox *s)
void uiSpinboxSetValue(uiSpinbox *s, int value) void uiSpinboxSetValue(uiSpinbox *s, int value)
{ {
/* we need to inhibit sending of ::value-changed // we need to inhibit sending of ::value-changed because this WILL send a ::value-changed otherwise
* because this WILL send a ::value-changed otherwise */
g_signal_handler_block(s->spinButton, s->onChangedSignal); g_signal_handler_block(s->spinButton, s->onChangedSignal);
/* this clamps for us */ // this clamps for us
gtk_spin_button_set_value(s->spinButton, (gdouble) value); gtk_spin_button_set_value(s->spinButton, (gdouble) value);
g_signal_handler_unblock(s->spinButton, s->onChangedSignal); g_signal_handler_unblock(s->spinButton, s->onChangedSignal);
} }
@ -48,23 +47,22 @@ void uiSpinboxOnChanged(uiSpinbox *s, void (*f)(uiSpinbox *, void *), void *data
uiSpinbox *uiNewSpinbox(int min, int max) uiSpinbox *uiNewSpinbox(int min, int max)
{ {
uiSpinbox *s;
int temp; int temp;
uiSpinbox *s = NULL;
if (min >= max) if (min >= max) {
{ temp = min;
temp = min; min = max;
min = max; max = temp;
max = temp; }
}
uiUnixNewControl(uiSpinbox, s); uiUnixNewControl(uiSpinbox, s);
s->widget = gtk_spin_button_new_with_range(min, max, 1); s->widget = gtk_spin_button_new_with_range(min, max, 1);
s->entry = GTK_ENTRY(s->widget); s->entry = GTK_ENTRY(s->widget);
s->spinButton = GTK_SPIN_BUTTON(s->widget); s->spinButton = GTK_SPIN_BUTTON(s->widget);
/* ensure integers, just to be safe */ // ensure integers, just to be safe
gtk_spin_button_set_digits(s->spinButton, 0); gtk_spin_button_set_digits(s->spinButton, 0);
s->onChangedSignal = g_signal_connect(s->spinButton, "value-changed", G_CALLBACK(onChanged), s); s->onChangedSignal = g_signal_connect(s->spinButton, "value-changed", G_CALLBACK(onChanged), s);

View File

@ -15,18 +15,16 @@ uiUnixControlAllDefaultsExceptDestroy(uiTab)
static void uiTabDestroy(uiControl *c) static void uiTabDestroy(uiControl *c)
{ {
uiTab *t = uiTab(c);
guint i; guint i;
uiTab *t = uiTab(c); struct child *page;
struct child *page = NULL;
for (i = 0; i < t->pages->len; i++) for (i = 0; i < t->pages->len; i++) {
{
page = g_array_index(t->pages, struct child *, i); page = g_array_index(t->pages, struct child *, i);
childDestroy(page); childDestroy(page);
} }
g_array_free(t->pages, TRUE); g_array_free(t->pages, TRUE);
/* and free ourselves */ // and free ourselves
g_object_unref(t->widget); g_object_unref(t->widget);
uiFreeControl(uiControl(t)); uiFreeControl(uiControl(t));
} }
@ -38,8 +36,10 @@ void uiTabAppend(uiTab *t, const char *name, uiControl *child)
void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child) void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child)
{ {
/* this will create a tab, because of gtk_container_add() */ struct child *page;
struct child *page = newChildWithBox(child, uiControl(t), t->container, 0);
// this will create a tab, because of gtk_container_add()
page = newChildWithBox(child, uiControl(t), t->container, 0);
gtk_notebook_set_tab_label_text(t->notebook, childBox(page), name); gtk_notebook_set_tab_label_text(t->notebook, childBox(page), name);
gtk_notebook_reorder_child(t->notebook, childBox(page), n); gtk_notebook_reorder_child(t->notebook, childBox(page), n);
@ -49,10 +49,10 @@ void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child)
void uiTabDelete(uiTab *t, int n) void uiTabDelete(uiTab *t, int n)
{ {
struct child *page = g_array_index(t->pages, struct child *, n); struct child *page;
/* this will remove the tab,
* because gtk_widget_destroy() calls gtk_container_remove() */
page = g_array_index(t->pages, struct child *, n);
// this will remove the tab, because gtk_widget_destroy() calls gtk_container_remove()
childRemove(page); childRemove(page);
g_array_remove_index(t->pages, n); g_array_remove_index(t->pages, n);
} }
@ -64,28 +64,30 @@ int uiTabNumPages(uiTab *t)
int uiTabMargined(uiTab *t, int n) int uiTabMargined(uiTab *t, int n)
{ {
struct child *page = g_array_index(t->pages, struct child *, n); struct child *page;
page = g_array_index(t->pages, struct child *, n);
return childFlag(page); return childFlag(page);
} }
void uiTabSetMargined(uiTab *t, int n, int margined) void uiTabSetMargined(uiTab *t, int n, int margined)
{ {
struct child *page = g_array_index(t->pages, struct child *, n); struct child *page;
page = g_array_index(t->pages, struct child *, n);
childSetFlag(page, margined); childSetFlag(page, margined);
childSetMargined(page, childFlag(page)); childSetMargined(page, childFlag(page));
} }
uiTab *uiNewTab(void) uiTab *uiNewTab(void)
{ {
uiTab *t = NULL;; uiTab *t;
uiUnixNewControl(uiTab, t); uiUnixNewControl(uiTab, t);
t->widget = gtk_notebook_new(); t->widget = gtk_notebook_new();
t->container = GTK_CONTAINER(t->widget); t->container = GTK_CONTAINER(t->widget);
t->notebook = GTK_NOTEBOOK(t->widget); t->notebook = GTK_NOTEBOOK(t->widget);
gtk_notebook_set_scrollable(t->notebook, TRUE); gtk_notebook_set_scrollable(t->notebook, TRUE);

View File

@ -1,11 +1,11 @@
/* 22 april 2015 */ // 22 april 2015
#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_40 #define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_40
#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_40 #define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_40
#define GDK_VERSION_MIN_REQUIRED GDK_VERSION_3_10 #define GDK_VERSION_MIN_REQUIRED GDK_VERSION_3_10
#define GDK_VERSION_MAX_ALLOWED GDK_VERSION_3_10 #define GDK_VERSION_MAX_ALLOWED GDK_VERSION_3_10
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <math.h> #include <math.h>
#include <dlfcn.h> /* see drawtext.c */ #include <dlfcn.h> // see drawtext.c
#include <langinfo.h> #include <langinfo.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -18,19 +18,19 @@
#define gtkXPadding 12 #define gtkXPadding 12
#define gtkYPadding 6 #define gtkYPadding 6
/* menu.c */ // menu.c
extern GtkWidget *makeMenubar(uiWindow *); extern GtkWidget *makeMenubar(uiWindow *);
extern void freeMenubar(GtkWidget *); extern void freeMenubar(GtkWidget *);
extern void uninitMenus(void); extern void uninitMenus(void);
/* alloc.c */ // alloc.c
extern void initAlloc(void); extern void initAlloc(void);
extern void uninitAlloc(void); extern void uninitAlloc(void);
/* util.c */ // util.c
extern void setMargined(GtkContainer *, int); extern void setMargined(GtkContainer *, int);
/* child.c */ // child.c
extern struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parentContainer); extern struct child *newChild(uiControl *child, uiControl *parent, GtkContainer *parentContainer);
extern struct child *newChildWithBox(uiControl *child, uiControl *parent, GtkContainer *parentContainer, int margined); extern struct child *newChildWithBox(uiControl *child, uiControl *parent, GtkContainer *parentContainer, int margined);
extern void childRemove(struct child *c); extern void childRemove(struct child *c);
@ -41,25 +41,25 @@ extern void childSetFlag(struct child *c, int flag);
extern GtkWidget *childBox(struct child *c); extern GtkWidget *childBox(struct child *c);
extern void childSetMargined(struct child *c, int margined); extern void childSetMargined(struct child *c, int margined);
/* draw.c */ // draw.c
extern uiDrawContext *newContext(cairo_t *); extern uiDrawContext *newContext(cairo_t *);
extern void freeContext(uiDrawContext *); extern void freeContext(uiDrawContext *);
/* drawtext.c */ // drawtext.c
extern uiDrawTextFont *mkTextFont(PangoFont *f, gboolean add); extern uiDrawTextFont *mkTextFont(PangoFont *f, gboolean add);
extern PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc); extern PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc);
/* graphemes.c */ // graphemes.c
extern ptrdiff_t *graphemes(const char *text, PangoContext *context); extern ptrdiff_t *graphemes(const char *text, PangoContext *context);
/* image.c */ // image.c
/*TODO remove this*/typedef struct uiImage uiImage; /*TODO remove this*/typedef struct uiImage uiImage;
extern cairo_surface_t *imageAppropriateSurface(uiImage *i, GtkWidget *w); extern cairo_surface_t *imageAppropriateSurface(uiImage *i, GtkWidget *w);
/* cellrendererbutton.c */ // cellrendererbutton.c
extern GtkCellRenderer *newCellRendererButton(void); extern GtkCellRenderer *newCellRendererButton(void);
/* future.c */ // future.c
extern void loadFutures(void); extern void loadFutures(void);
extern PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha); extern PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha);
extern gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name); extern gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name);

View File

@ -1,43 +1,40 @@
// 11 june 2015 // 11 june 2015
#include "uipriv_unix.h" #include "uipriv_unix.h"
struct uiWindow struct uiWindow {
{ uiUnixControl c;
uiUnixControl c;
GtkWidget *widget; GtkWidget *widget;
GtkContainer *container; GtkContainer *container;
GtkWindow *window; GtkWindow *window;
GtkWidget *vboxWidget; GtkWidget *vboxWidget;
GtkContainer *vboxContainer; GtkContainer *vboxContainer;
GtkBox *vbox; GtkBox *vbox;
GtkWidget *childHolderWidget; GtkWidget *childHolderWidget;
GtkContainer *childHolderContainer; GtkContainer *childHolderContainer;
GtkWidget *menubar; GtkWidget *menubar;
uiControl *child; uiControl *child;
int margined; int margined;
int (*onClosing)(uiWindow *, void *); int (*onClosing)(uiWindow *, void *);
void *onClosingData; void *onClosingData;
void (*onContentSizeChanged)(uiWindow *, void *); void (*onContentSizeChanged)(uiWindow *, void *);
void *onContentSizeChangedData; void *onContentSizeChangedData;
gboolean fullscreen; gboolean fullscreen;
}; };
static gboolean onClosing(GtkWidget *win, GdkEvent *e, gpointer data) static gboolean onClosing(GtkWidget *win, GdkEvent *e, gpointer data)
{ {
uiWindow *w = uiWindow(data); uiWindow *w = uiWindow(data);
/* manually destroy the window ourselves; don't let // manually destroy the window ourselves; don't let the delete-event handler do it
* the delete-event handler do it */
if ((*(w->onClosing))(w, w->onClosingData)) if ((*(w->onClosing))(w, w->onClosingData))
uiControlDestroy(uiControl(w)); uiControlDestroy(uiControl(w));
/* don't continue to the default delete-event handler; // don't continue to the default delete-event handler; we destroyed the window by now
* we destroyed the window by now */
return TRUE; return TRUE;
} }
@ -45,7 +42,7 @@ static void onSizeAllocate(GtkWidget *widget, GdkRectangle *allocation, gpointer
{ {
uiWindow *w = uiWindow(data); uiWindow *w = uiWindow(data);
/* TODO deal with spurious size-allocates */ // TODO deal with spurious size-allocates
(*(w->onContentSizeChanged))(w, w->onContentSizeChangedData); (*(w->onContentSizeChanged))(w, w->onContentSizeChangedData);
} }
@ -56,30 +53,28 @@ static int defaultOnClosing(uiWindow *w, void *data)
static void defaultOnPositionContentSizeChanged(uiWindow *w, void *data) static void defaultOnPositionContentSizeChanged(uiWindow *w, void *data)
{ {
/* do nothing */ // do nothing
} }
static void uiWindowDestroy(uiControl *c) static void uiWindowDestroy(uiControl *c)
{ {
uiWindow *w = uiWindow(c); uiWindow *w = uiWindow(c);
/* first hide ourselves */ // first hide ourselves
gtk_widget_hide(w->widget); gtk_widget_hide(w->widget);
/* now destroy the child */ // now destroy the child
if (w->child != NULL) if (w->child != NULL) {
{ uiControlSetParent(w->child, NULL);
uiControlSetParent(w->child, NULL); uiUnixControlSetContainer(uiUnixControl(w->child), w->childHolderContainer, TRUE);
uiUnixControlSetContainer(uiUnixControl(w->child), w->childHolderContainer, TRUE); uiControlDestroy(w->child);
uiControlDestroy(w->child); }
} // now destroy the menus, if any
/* now destroy the menus, if any */
if (w->menubar != NULL) if (w->menubar != NULL)
freeMenubar(w->menubar); freeMenubar(w->menubar);
gtk_widget_destroy(w->childHolderWidget); gtk_widget_destroy(w->childHolderWidget);
gtk_widget_destroy(w->vboxWidget); gtk_widget_destroy(w->vboxWidget);
/* and finally free ourselves // and finally free ourselves
* use gtk_widget_destroy() instead of g_object_unref() // use gtk_widget_destroy() instead of g_object_unref() because GTK+ has internal references (see #165)
* because GTK+ has internal references (see #165) */
gtk_widget_destroy(w->widget); gtk_widget_destroy(w->widget);
uiFreeControl(uiControl(w)); uiFreeControl(uiControl(w));
} }
@ -107,11 +102,9 @@ static void uiWindowShow(uiControl *c)
{ {
uiWindow *w = uiWindow(c); uiWindow *w = uiWindow(c);
/* don't use gtk_widget_show_all() as that // don't use gtk_widget_show_all() as that will show all children, regardless of user settings
* will show all children, regardless of user settings // don't use gtk_widget_show(); that doesn't bring to front or give keyboard focus
* don't use gtk_widget_show(); that doesn't bring to // (gtk_window_present() does call gtk_widget_show() though)
* front or give keyboard focus
* (gtk_window_present() does call gtk_widget_show() though) */
gtk_window_present(w->window); gtk_window_present(w->window);
} }
@ -119,8 +112,7 @@ uiUnixControlDefaultHide(uiWindow)
uiUnixControlDefaultEnabled(uiWindow) uiUnixControlDefaultEnabled(uiWindow)
uiUnixControlDefaultEnable(uiWindow) uiUnixControlDefaultEnable(uiWindow)
uiUnixControlDefaultDisable(uiWindow) uiUnixControlDefaultDisable(uiWindow)
// TODO?
/* TODO? */
uiUnixControlDefaultSetContainer(uiWindow) uiUnixControlDefaultSetContainer(uiWindow)
char *uiWindowTitle(uiWindow *w) char *uiWindowTitle(uiWindow *w)

View File

@ -1,198 +0,0 @@
/* 22 may 2015 */
#include "uipriv_windows.hpp"
struct uiDateTimePicker {
uiWindowsControl c;
HWND hwnd;
};
#ifndef DTM_GETIDEALSIZE
#define DTM_GETIDEALSIZE 0x100f
#endif
/* utility functions */
#define GLI(what, buf, n) GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, what, buf, n)
/* The real date/time picker does a manual replacement of "yy" with "yyyy" for DTS_SHORTDATECENTURYFORMAT.
* Because we're also duplicating its functionality (see below), we have to do it too. */
static WCHAR *expandYear(WCHAR *dts, int n)
{
WCHAR *p = NULL;
int ny = 0;
/* allocate more than we need to be safe */
WCHAR *out = (WCHAR *) uiAlloc((n * 3) * sizeof (WCHAR), "WCHAR[]");
WCHAR *q = out;
for (p = dts; *p != L'\0'; p++)
{
/* first, if the current character is a y, increment the number of consecutive ys
* otherwise, stop counting, and if there were only two, add two more to make four */
if (*p != L'y') {
if (ny == 2) {
*q++ = L'y';
*q++ = L'y';
}
ny = 0;
} else
ny++;
/* next, handle quoted blocks
* we do this AFTER the above so yy'abc' becomes yyyy'abc' and not yy'abc'yy
* this handles the case of 'a''b' elegantly as well */
if (*p == L'\'') {
/* copy the opening quote */
*q++ = *p;
/* copy the contents */
for (;;) {
p++;
if (*p == L'\'')
break;
if (*p == L'\0')
implbug("unterminated quote in system-provided locale date string in expandYear()");
*q++ = *p;
}
/* and fall through to copy the closing quote */
}
/* copy the current character */
*q++ = *p;
}
/* handle trailing yy */
if (ny == 2) {
*q++ = L'y';
*q++ = L'y';
}
*q++ = L'\0';
return out;
}
/* Windows has no combined date/time prebuilt constant;
* we have to build the format string ourselves
* TODO use a default format if one fails */
static void setDateTimeFormat(HWND hwnd)
{
WCHAR *unexpandedDate, *date;
WCHAR *time;
WCHAR *datetime;
int ntime;
int ndate = GLI(LOCALE_SSHORTDATE, NULL, 0);
if (ndate == 0)
logLastError(L"error getting date string length");
date = (WCHAR *) uiAlloc(ndate * sizeof (WCHAR), "WCHAR[]");
if (GLI(LOCALE_SSHORTDATE, date, ndate) == 0)
logLastError(L"error geting date string");
unexpandedDate = date; /* so we can free it */
date = expandYear(unexpandedDate, ndate);
uiFree(unexpandedDate);
ntime = GLI(LOCALE_STIMEFORMAT, NULL, 0);
if (ndate == 0)
logLastError(L"error getting time string length");
time = (WCHAR *) uiAlloc(ntime * sizeof (WCHAR), "WCHAR[]");
if (GLI(LOCALE_STIMEFORMAT, time, ntime) == 0)
logLastError(L"error geting time string");
datetime = strf(L"%s %s", date, time);
if (SendMessageW(hwnd, DTM_SETFORMAT, 0, (LPARAM) datetime) == 0)
logLastError(L"error applying format string to date/time picker");
uiFree(datetime);
uiFree(time);
uiFree(date);
}
/* control implementation */
static void uiDateTimePickerDestroy(uiControl *c)
{
uiDateTimePicker *d = uiDateTimePicker(c);
uiWindowsUnregisterReceiveWM_WININICHANGE(d->hwnd);
uiWindowsEnsureDestroyWindow(d->hwnd);
uiFreeControl(uiControl(d));
}
uiWindowsControlAllDefaultsExceptDestroy(uiDateTimePicker)
/* the height returned from DTM_GETIDEALSIZE is unreliable; see http://stackoverflow.com/questions/30626549/what-is-the-proper-use-of-dtm-getidealsize-treating-the-returned-size-as-pixels
* from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing */
#define entryHeight 14
static void uiDateTimePickerMinimumSize(uiWindowsControl *c, int *width, int *height)
{
SIZE s;
uiWindowsSizing sizing;
uiDateTimePicker *d = uiDateTimePicker(c);
int y;
s.cx = 0;
s.cy = 0;
SendMessageW(d->hwnd, DTM_GETIDEALSIZE, 0, (LPARAM) (&s));
*width = s.cx;
y = entryHeight;
uiWindowsGetSizing(d->hwnd, &sizing);
uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &y);
*height = y;
}
static uiDateTimePicker *finishNewDateTimePicker(DWORD style)
{
uiDateTimePicker *d;
uiWindowsNewControl(uiDateTimePicker, d);
d->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE,
DATETIMEPICK_CLASSW, L"",
style | WS_TABSTOP,
hInstance, NULL,
TRUE);
/* automatically update date/time format when user changes locale settings
* for the standard styles, this is in the date-time picker itself
* for our date/time mode, we do it in a subclass assigned in uiNewDateTimePicker() */
uiWindowsRegisterReceiveWM_WININICHANGE(d->hwnd);
return d;
}
static LRESULT CALLBACK datetimepickerSubProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_WININICHANGE:
// we can optimize this by only doing it when the real date/time picker does it
// unfortunately, I don't know when that is :/
// hopefully this won't hurt
setDateTimeFormat(hwnd);
return 0;
case WM_NCDESTROY:
if (RemoveWindowSubclass(hwnd, datetimepickerSubProc, uIdSubclass) == FALSE)
logLastError(L"error removing date-time picker locale change handling subclass");
break;
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
uiDateTimePicker *uiNewDateTimePicker(void)
{
uiDateTimePicker *d = finishNewDateTimePicker(0);
setDateTimeFormat(d->hwnd);
if (SetWindowSubclass(d->hwnd, datetimepickerSubProc, 0, (DWORD_PTR) d) == FALSE)
logLastError(L"error subclassing date-time-picker to assist in locale change handling");
/* TODO set a suitable default in this case */
return d;
}
uiDateTimePicker *uiNewDatePicker(void)
{
return finishNewDateTimePicker(DTS_SHORTDATECENTURYFORMAT);
}
uiDateTimePicker *uiNewTimePicker(void)
{
return finishNewDateTimePicker(DTS_TIMEFORMAT);
}

View File

@ -1,105 +0,0 @@
/* 9 april 2015 */
#include "uipriv_windows.hpp"
WCHAR *windowTextAndLen(HWND hwnd, LRESULT *len)
{
WCHAR *text = NULL;
LRESULT n = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
if (len != NULL)
*len = n;
/* WM_GETTEXTLENGTH does not include the null terminator */
text = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]");
/* note the comparison: the size includes the
* null terminator, but the return does not */
if (GetWindowTextW(hwnd, text, n + 1) != n)
{
logLastError(L"error getting window text");
/* on error, return an empty string to be safe */
*text = L'\0';
if (len != NULL)
*len = 0;
}
return text;
}
WCHAR *windowText(HWND hwnd)
{
return windowTextAndLen(hwnd, NULL);
}
void setWindowText(HWND hwnd, WCHAR *wtext)
{
if (SetWindowTextW(hwnd, wtext) == 0)
logLastError(L"error setting window text");
}
void uiFreeText(char *text)
{
uiFree(text);
}
int uiWindowsWindowTextWidth(HWND hwnd)
{
LRESULT len;
HDC dc;
HFONT prevfont;
SIZE size;
WCHAR *text = windowTextAndLen(hwnd, &len);
size.cx = 0;
size.cy = 0;
if (len == 0) /* no text; nothing to do */
goto noTextOrError;
/* now we can do the calculations */
dc = GetDC(hwnd);
if (dc == NULL)
{
logLastError(L"error getting DC");
/* on any error, assume no text */
goto noTextOrError;
}
prevfont = (HFONT) SelectObject(dc, hMessageFont);
if (prevfont == NULL)
{
logLastError(L"error loading control font into device context");
ReleaseDC(hwnd, dc);
goto noTextOrError;
}
if (GetTextExtentPoint32W(dc, text, len, &size) == 0)
{
logLastError(L"error getting text extent point");
/* continue anyway, assuming size is 0 */
size.cx = 0;
size.cy = 0;
}
/* continue on errors; we got what we want */
if (SelectObject(dc, prevfont) != hMessageFont)
logLastError(L"error restoring previous font into device context");
if (ReleaseDC(hwnd, dc) == 0)
logLastError(L"error releasing DC");
uiFree(text);
return size.cx;
noTextOrError:
uiFree(text);
return 0;
}
char *uiWindowsWindowText(HWND hwnd)
{
WCHAR *wtext = windowText(hwnd);
char *text = toUTF8(wtext);
uiFree(wtext);
return text;
}
void uiWindowsSetWindowText(HWND hwnd, const char *text)
{
WCHAR *wtext = toUTF16(text);
setWindowText(hwnd, wtext);
uiFree(wtext);
}

View File

@ -1,87 +0,0 @@
/* 14 may 2015 */
#include "uipriv_windows.hpp"
#include "../../verbosity.h"
/* The utility window is a special window that performs certain tasks internal to libui.
* It is not a message-only window, and it is always hidden and disabled.
* Its roles:
* - It is the initial parent of all controls. When a control loses its parent, it also becomes that control's parent.
* - It handles WM_QUERYENDSESSION and console end session requests.
* - It handles WM_WININICHANGE and forwards the message to any child windows that request it.
* - It handles executing functions queued to run by uiQueueMain().
*/
#define utilWindowClass L"libui_utilWindowClass"
HWND utilWindow;
static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
void (*qf)(void *);
LRESULT lResult;
if (handleParentMessages(hwnd, uMsg, wParam, lParam, &lResult) != FALSE)
return lResult;
switch (uMsg)
{
case WM_QUERYENDSESSION:
/* TODO block handler */
if (shouldQuit())
{
uiQuit();
return TRUE;
}
return FALSE;
case WM_WININICHANGE:
issueWM_WININICHANGE(wParam, lParam);
return 0;
case msgQueued:
qf = (void (*)(void *)) wParam;
(*qf)((void *) lParam);
return 0;
}
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
const char *initUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor)
{
WNDCLASSW wc;
ZeroMemory(&wc, sizeof (WNDCLASSW));
wc.lpszClassName = utilWindowClass;
wc.lpfnWndProc = utilWindowWndProc;
wc.hInstance = hInstance;
wc.hIcon = hDefaultIcon;
wc.hCursor = hDefaultCursor;
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
if (RegisterClass(&wc) == 0)
{
RARCH_ERR("Cannot register class.\n");
/* see init.cpp for an explanation of the =s */
return "=registering utility window class";
}
utilWindow = CreateWindowExW(0,
utilWindowClass, L"libui utility window",
WS_OVERLAPPEDWINDOW,
0, 0, 100, 100,
NULL, NULL, hInstance, NULL);
if (utilWindow == NULL)
{
RARCH_ERR("Cannot create window.\n");
return "=creating utility window";
}
/* and just to be safe */
EnableWindow(utilWindow, FALSE);
return NULL;
}
void uninitUtilWindow(void)
{
if (DestroyWindow(utilWindow) == 0)
logLastError(L"error destroying utility window");
if (UnregisterClass(utilWindowClass, hInstance) == 0)
logLastError(L"error unregistering utility window class");
}

View File

@ -1,150 +0,0 @@
/* This file contains some Vista SDK stuff that is missing from the current
mingw-w64 headers */
#ifndef WINEXTRA_H
#define WINEXTRA_H
/* winuser.h */
#if (_WIN32_WINNT >= 0x0600)
WINUSERAPI WINBOOL WINAPI SetProcessDPIAware(VOID);
WINUSERAPI WINBOOL WINAPI IsProcessDPIAware(VOID);
#endif
/* commctrl.h */
#ifndef NOTASKDIALOG
#if (NTDDI_VERSION >= NTDDI_VISTA)
#include <pshpack1.h>
#define TD_WARNING_ICON MAKEINTRESOURCEW(-1)
#define TD_ERROR_ICON MAKEINTRESOURCEW(-2)
#define TD_INFORMATION_ICON MAKEINTRESOURCEW(-3)
#define TD_SHIELD_ICON MAKEINTRESOURCEW(-4)
typedef HRESULT (CALLBACK *PFTASKDIALOGCALLBACK)(HWND hwnd,UINT uNotification,WPARAM wParam,LPARAM lParam,LONG_PTR dwRefData);
enum _TASKDIALOG_FLAGS {
TDF_ENABLE_HYPERLINKS = 0x0001,
TDF_USE_HICON_MAIN = 0x0002,
TDF_USE_HICON_FOOTER = 0x0004,
TDF_ALLOW_DIALOG_CANCELLATION = 0x0008,
TDF_USE_COMMAND_LINKS = 0x0010,
TDF_USE_COMMAND_LINKS_NO_ICON = 0x0020,
TDF_EXPAND_FOOTER_AREA = 0x0040,
TDF_EXPANDED_BY_DEFAULT = 0x0080,
TDF_VERIFICATION_FLAG_CHECKED = 0x0100,
TDF_SHOW_PROGRESS_BAR = 0x0200,
TDF_SHOW_MARQUEE_PROGRESS_BAR = 0x0400,
TDF_CALLBACK_TIMER = 0x0800,
TDF_POSITION_RELATIVE_TO_WINDOW = 0x1000,
TDF_RTL_LAYOUT = 0x2000,
TDF_NO_DEFAULT_RADIO_BUTTON = 0x4000,
TDF_CAN_BE_MINIMIZED = 0x8000,
TDIF_SIZE_TO_CONTENT = 0x1000000,
TDF_SIZE_TO_CONTENT = 0x1000000
};
typedef int TASKDIALOG_FLAGS;
enum _TASKDIALOG_COMMON_BUTTON_FLAGS {
TDCBF_OK_BUTTON = 0x01,
TDCBF_YES_BUTTON = 0x02,
TDCBF_NO_BUTTON = 0x04,
TDCBF_CANCEL_BUTTON = 0x08,
TDCBF_RETRY_BUTTON = 0x10,
TDCBF_CLOSE_BUTTON = 0x20
};
typedef int TASKDIALOG_COMMON_BUTTON_FLAGS;
typedef enum _TASKDIALOG_NOTIFICATIONS {
TDN_CREATED = 0,
TDN_NAVIGATED = 1,
TDN_BUTTON_CLICKED = 2,
TDN_HYPERLINK_CLICKED = 3,
TDN_TIMER = 4,
TDN_DESTROYED = 5,
TDN_RADIO_BUTTON_CLICKED = 6,
TDN_DIALOG_CONSTRUCTED = 7,
TDN_VERIFICATION_CLICKED = 8,
TDN_HELP = 9,
TDN_EXPANDO_BUTTON_CLICKED = 10
} TASKDIALOG_NOTIFICATIONS;
typedef enum _TASKDIALOG_MESSAGES {
TDM_NAVIGATE_PAGE = WM_USER + 101,
TDM_CLICK_BUTTON = WM_USER + 102,
TDM_SET_MARQUEE_PROGRESS_BAR = WM_USER + 103,
TDM_SET_PROGRESS_BAR_STATE = WM_USER + 104,
TDM_SET_PROGRESS_BAR_RANGE = WM_USER + 105,
TDM_SET_PROGRESS_BAR_POS = WM_USER + 106,
TDM_SET_PROGRESS_BAR_MARQUEE = WM_USER + 107,
TDM_SET_ELEMENT_TEXT = WM_USER + 108,
TDM_CLICK_RADIO_BUTTON = WM_USER + 110,
TDM_ENABLE_BUTTON = WM_USER + 111,
TDM_ENABLE_RADIO_BUTTON = WM_USER + 112,
TDM_CLICK_VERIFICATION = WM_USER + 113,
TDM_UPDATE_ELEMENT_TEXT = WM_USER + 114,
TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = WM_USER + 115,
TDM_UPDATE_ICON = WM_USER + 116
} TASKDIALOG_MESSAGES;
typedef enum _TASKDIALOG_ELEMENTS {
TDE_CONTENT,
TDE_EXPANDED_INFORMATION,
TDE_FOOTER,
TDE_MAIN_INSTRUCTION
} TASKDIALOG_ELEMENTS;
typedef enum _TASKDIALOG_ICON_ELEMENTS {
TDIE_ICON_MAIN,
TDIE_ICON_FOOTER
} TASKDIALOG_ICON_ELEMENTS;
typedef struct _TASKDIALOG_BUTTON {
int nButtonID;
PCWSTR pszButtonText;
} TASKDIALOG_BUTTON;
typedef struct _TASKDIALOGCONFIG {
UINT cbSize;
HWND hwndParent;
HINSTANCE hInstance;
TASKDIALOG_FLAGS dwFlags;
TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons;
PCWSTR pszWindowTitle;
__C89_NAMELESS union {
HICON hMainIcon;
PCWSTR pszMainIcon;
} DUMMYUNIONNAME;
PCWSTR pszMainInstruction;
PCWSTR pszContent;
UINT cButtons;
const TASKDIALOG_BUTTON *pButtons;
int nDefaultButton;
UINT cRadioButtons;
const TASKDIALOG_BUTTON *pRadioButtons;
int nDefaultRadioButton;
PCWSTR pszVerificationText;
PCWSTR pszExpandedInformation;
PCWSTR pszExpandedControlText;
PCWSTR pszCollapsedControlText;
__C89_NAMELESS union {
HICON hFooterIcon;
PCWSTR pszFooterIcon;
} DUMMYUNIONNAME2;
PCWSTR pszFooter;
PFTASKDIALOGCALLBACK pfCallback;
LONG_PTR lpCallbackData;
UINT cxWidth;
} TASKDIALOGCONFIG;
WINCOMMCTRLAPI HRESULT WINAPI TaskDialog(HWND hwndParent,HINSTANCE hInstance,PCWSTR pszWindowTitle,PCWSTR pszMainInstruction,PCWSTR pszContent,TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons,PCWSTR pszIcon,int *pnButton);
WINCOMMCTRLAPI HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig,int *pnButton,int *pnRadioButton,BOOL *pfVerificationFlagChecked);
#include <poppack.h>
#endif
#endif
/* dwmapi.h */
HRESULT WINAPI DwmFlush(VOID);
#endif

91
deps/libui/windows/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,91 @@
# 3 june 2016
list(APPEND _LIBUI_SOURCES
windows/alloc.cpp
windows/area.cpp
windows/areadraw.cpp
windows/areaevents.cpp
windows/areascroll.cpp
windows/areautil.cpp
windows/box.cpp
windows/button.cpp
windows/checkbox.cpp
windows/colorbutton.cpp
windows/colordialog.cpp
windows/combobox.cpp
windows/container.cpp
windows/control.cpp
windows/d2dscratch.cpp
windows/datetimepicker.cpp
windows/debug.cpp
windows/draw.cpp
windows/drawmatrix.cpp
windows/drawpath.cpp
windows/drawtext.cpp
windows/dwrite.cpp
windows/editablecombo.cpp
windows/entry.cpp
windows/events.cpp
windows/fontbutton.cpp
windows/fontdialog.cpp
windows/form.cpp
windows/graphemes.cpp
windows/grid.cpp
windows/group.cpp
windows/init.cpp
windows/label.cpp
windows/main.cpp
windows/menu.cpp
windows/multilineentry.cpp
windows/parent.cpp
windows/progressbar.cpp
windows/radiobuttons.cpp
windows/separator.cpp
windows/sizing.cpp
windows/slider.cpp
windows/spinbox.cpp
windows/stddialogs.cpp
windows/tab.cpp
windows/tabpage.cpp
windows/text.cpp
windows/utf16.cpp
windows/utilwin.cpp
windows/window.cpp
windows/winpublic.cpp
windows/winutil.cpp
windows/resources.rc
)
set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE)
list(APPEND _LIBUI_INCLUDEDIRS
windows
)
set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE)
# Windows won't link resources in static libraries; we need to provide the libui.res file in this case.
set(_LIBUINAME libui PARENT_SCOPE)
if(NOT BUILD_SHARED_LIBS)
set(_LIBUI_STATIC_RES ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/libui.res PARENT_SCOPE)
endif()
macro(_handle_static)
# TODO this full path feels hacky
add_custom_command(
TARGET libui POST_BUILD
COMMAND
${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:libui,BINARY_DIR>/CMakeFiles/libui.dir/windows/resources.rc.* ${_LIBUI_STATIC_RES}
COMMENT "Copying libui.res")
endmacro()
# notice that usp10 comes before gdi32
# TODO prune this list
set(_LIBUI_LIBS
user32 kernel32 usp10 gdi32 comctl32 uxtheme msimg32 comdlg32 d2d1 dwrite ole32 oleaut32 oleacc uuid
PARENT_SCOPE)
if(NOT MSVC)
if(BUILD_SHARED_LIBS)
message(FATAL_ERROR
"Sorry, but libui for Windows can currently only be built as a static library with MinGW. You will need to either build as a static library or switch to MSVC."
)
endif()
endif()

View File

@ -100,10 +100,11 @@ static void scroll(uiArea *a, int which, struct scrollParams *p, WPARAM wParam,
static void wheelscroll(uiArea *a, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam) static void wheelscroll(uiArea *a, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam)
{ {
int delta;
int lines; int lines;
UINT scrollAmount; UINT scrollAmount;
int delta = GET_WHEEL_DELTA_WPARAM(wParam);
delta = GET_WHEEL_DELTA_WPARAM(wParam);
if (SystemParametersInfoW(p->wheelSPIAction, 0, &scrollAmount, 0) == 0) if (SystemParametersInfoW(p->wheelSPIAction, 0, &scrollAmount, 0) == 0)
// TODO use scrollAmount == 3 (for both v and h) instead? // TODO use scrollAmount == 3 (for both v and h) instead?
logLastError(L"error getting area wheel scroll amount"); logLastError(L"error getting area wheel scroll amount");

191
deps/libui/windows/datetimepicker.cpp vendored Normal file
View File

@ -0,0 +1,191 @@
// 22 may 2015
#include "uipriv_windows.hpp"
struct uiDateTimePicker {
uiWindowsControl c;
HWND hwnd;
};
// utility functions
#define GLI(what, buf, n) GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, what, buf, n)
// The real date/time picker does a manual replacement of "yy" with "yyyy" for DTS_SHORTDATECENTURYFORMAT.
// Because we're also duplicating its functionality (see below), we have to do it too.
static WCHAR *expandYear(WCHAR *dts, int n)
{
WCHAR *out;
WCHAR *p, *q;
int ny = 0;
// allocate more than we need to be safe
out = (WCHAR *) uiAlloc((n * 3) * sizeof (WCHAR), "WCHAR[]");
q = out;
for (p = dts; *p != L'\0'; p++) {
// first, if the current character is a y, increment the number of consecutive ys
// otherwise, stop counting, and if there were only two, add two more to make four
if (*p != L'y') {
if (ny == 2) {
*q++ = L'y';
*q++ = L'y';
}
ny = 0;
} else
ny++;
// next, handle quoted blocks
// we do this AFTER the above so yy'abc' becomes yyyy'abc' and not yy'abc'yy
// this handles the case of 'a''b' elegantly as well
if (*p == L'\'') {
// copy the opening quote
*q++ = *p;
// copy the contents
for (;;) {
p++;
if (*p == L'\'')
break;
if (*p == L'\0')
implbug("unterminated quote in system-provided locale date string in expandYear()");
*q++ = *p;
}
// and fall through to copy the closing quote
}
// copy the current character
*q++ = *p;
}
// handle trailing yy
if (ny == 2) {
*q++ = L'y';
*q++ = L'y';
}
*q++ = L'\0';
return out;
}
// Windows has no combined date/time prebuilt constant; we have to build the format string ourselves
// TODO use a default format if one fails
static void setDateTimeFormat(HWND hwnd)
{
WCHAR *unexpandedDate, *date;
WCHAR *time;
WCHAR *datetime;
int ndate, ntime;
ndate = GLI(LOCALE_SSHORTDATE, NULL, 0);
if (ndate == 0)
logLastError(L"error getting date string length");
date = (WCHAR *) uiAlloc(ndate * sizeof (WCHAR), "WCHAR[]");
if (GLI(LOCALE_SSHORTDATE, date, ndate) == 0)
logLastError(L"error geting date string");
unexpandedDate = date; // so we can free it
date = expandYear(unexpandedDate, ndate);
uiFree(unexpandedDate);
ntime = GLI(LOCALE_STIMEFORMAT, NULL, 0);
if (ndate == 0)
logLastError(L"error getting time string length");
time = (WCHAR *) uiAlloc(ntime * sizeof (WCHAR), "WCHAR[]");
if (GLI(LOCALE_STIMEFORMAT, time, ntime) == 0)
logLastError(L"error geting time string");
datetime = strf(L"%s %s", date, time);
if (SendMessageW(hwnd, DTM_SETFORMAT, 0, (LPARAM) datetime) == 0)
logLastError(L"error applying format string to date/time picker");
uiFree(datetime);
uiFree(time);
uiFree(date);
}
// control implementation
static void uiDateTimePickerDestroy(uiControl *c)
{
uiDateTimePicker *d = uiDateTimePicker(c);
uiWindowsUnregisterReceiveWM_WININICHANGE(d->hwnd);
uiWindowsEnsureDestroyWindow(d->hwnd);
uiFreeControl(uiControl(d));
}
uiWindowsControlAllDefaultsExceptDestroy(uiDateTimePicker)
// the height returned from DTM_GETIDEALSIZE is unreliable; see http://stackoverflow.com/questions/30626549/what-is-the-proper-use-of-dtm-getidealsize-treating-the-returned-size-as-pixels
// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
#define entryHeight 14
static void uiDateTimePickerMinimumSize(uiWindowsControl *c, int *width, int *height)
{
uiDateTimePicker *d = uiDateTimePicker(c);
SIZE s;
uiWindowsSizing sizing;
int y;
s.cx = 0;
s.cy = 0;
SendMessageW(d->hwnd, DTM_GETIDEALSIZE, 0, (LPARAM) (&s));
*width = s.cx;
y = entryHeight;
uiWindowsGetSizing(d->hwnd, &sizing);
uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &y);
*height = y;
}
static uiDateTimePicker *finishNewDateTimePicker(DWORD style)
{
uiDateTimePicker *d;
uiWindowsNewControl(uiDateTimePicker, d);
d->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE,
DATETIMEPICK_CLASSW, L"",
style | WS_TABSTOP,
hInstance, NULL,
TRUE);
// automatically update date/time format when user changes locale settings
// for the standard styles, this is in the date-time picker itself
// for our date/time mode, we do it in a subclass assigned in uiNewDateTimePicker()
uiWindowsRegisterReceiveWM_WININICHANGE(d->hwnd);
return d;
}
static LRESULT CALLBACK datetimepickerSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg) {
case WM_WININICHANGE:
// we can optimize this by only doing it when the real date/time picker does it
// unfortunately, I don't know when that is :/
// hopefully this won't hurt
setDateTimeFormat(hwnd);
return 0;
case WM_NCDESTROY:
if (RemoveWindowSubclass(hwnd, datetimepickerSubProc, uIdSubclass) == FALSE)
logLastError(L"error removing date-time picker locale change handling subclass");
break;
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
uiDateTimePicker *uiNewDateTimePicker(void)
{
uiDateTimePicker *d;
d = finishNewDateTimePicker(0);
setDateTimeFormat(d->hwnd);
if (SetWindowSubclass(d->hwnd, datetimepickerSubProc, 0, (DWORD_PTR) d) == FALSE)
logLastError(L"error subclassing date-time-picker to assist in locale change handling");
// TODO set a suitable default in this case
return d;
}
uiDateTimePicker *uiNewDatePicker(void)
{
return finishNewDateTimePicker(DTS_SHORTDATECENTURYFORMAT);
}
uiDateTimePicker *uiNewTimePicker(void)
{
return finishNewDateTimePicker(DTS_TIMEFORMAT);
}

View File

@ -1,6 +1,5 @@
// 6 april 2015 // 6 april 2015
#include "uipriv_windows.hpp" #include "uipriv_windows.hpp"
#include "../../verbosity.h"
HINSTANCE hInstance; HINSTANCE hInstance;
int nCmdShow; int nCmdShow;
@ -75,107 +74,61 @@ const char *uiInit(uiInitOptions *o)
hDefaultIcon = LoadIconW(NULL, IDI_APPLICATION); hDefaultIcon = LoadIconW(NULL, IDI_APPLICATION);
if (hDefaultIcon == NULL) if (hDefaultIcon == NULL)
{
RARCH_ERR("error loading default icon for window classes\n");
return ieLastErr("loading default icon for window classes"); return ieLastErr("loading default icon for window classes");
}
hDefaultCursor = LoadCursorW(NULL, IDC_ARROW); hDefaultCursor = LoadCursorW(NULL, IDC_ARROW);
if (hDefaultCursor == NULL) if (hDefaultCursor == NULL)
{
RARCH_ERR("error loading default cursor for window classes\n");
return ieLastErr("loading default cursor for window classes"); return ieLastErr("loading default cursor for window classes");
}
RARCH_LOG("Initializing initUtilWindow.\n");
ce = initUtilWindow(hDefaultIcon, hDefaultCursor); ce = initUtilWindow(hDefaultIcon, hDefaultCursor);
if (ce != NULL) if (ce != NULL)
{
RARCH_ERR("Failed initializing util window.\n");
return initerr(ce, L"GetLastError() ==", GetLastError()); return initerr(ce, L"GetLastError() ==", GetLastError());
}
if (registerWindowClass(hDefaultIcon, hDefaultCursor) == 0) if (registerWindowClass(hDefaultIcon, hDefaultCursor) == 0)
{
RARCH_ERR("failed registering uiWindow window class.\n");
return ieLastErr("registering uiWindow window class"); return ieLastErr("registering uiWindow window class");
}
ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW)); ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW));
ncm.cbSize = sizeof (NONCLIENTMETRICSW); ncm.cbSize = sizeof (NONCLIENTMETRICSW);
if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0) if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0)
{
RARCH_ERR("Error getting default fonts.\n");
return ieLastErr("getting default fonts"); return ieLastErr("getting default fonts");
}
hMessageFont = CreateFontIndirectW(&(ncm.lfMessageFont)); hMessageFont = CreateFontIndirectW(&(ncm.lfMessageFont));
if (hMessageFont == NULL) if (hMessageFont == NULL)
{
RARCH_ERR("loading default messagebox font; this is the default UI font\n");
return ieLastErr("loading default messagebox font; this is the default UI font"); return ieLastErr("loading default messagebox font; this is the default UI font");
}
if (initContainer(hDefaultIcon, hDefaultCursor) == 0) if (initContainer(hDefaultIcon, hDefaultCursor) == 0)
{
RARCH_ERR("initializing uiWindowsMakeContainer() window class\n");
return ieLastErr("initializing uiWindowsMakeContainer() window class"); return ieLastErr("initializing uiWindowsMakeContainer() window class");
}
hollowBrush = (HBRUSH) GetStockObject(HOLLOW_BRUSH); hollowBrush = (HBRUSH) GetStockObject(HOLLOW_BRUSH);
if (hollowBrush == NULL) if (hollowBrush == NULL)
{
RARCH_ERR("getting hollow brush\n");
return ieLastErr("getting hollow brush"); return ieLastErr("getting hollow brush");
}
ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX)); ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
icc.dwSize = sizeof (INITCOMMONCONTROLSEX); icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
icc.dwICC = wantedICCClasses; icc.dwICC = wantedICCClasses;
if (InitCommonControlsEx(&icc) == 0) if (InitCommonControlsEx(&icc) == 0)
{
RARCH_ERR("initializing Common Controls\n");
return ieLastErr("initializing Common Controls"); return ieLastErr("initializing Common Controls");
}
hr = CoInitialize(NULL); hr = CoInitialize(NULL);
if (hr != S_OK && hr != S_FALSE) if (hr != S_OK && hr != S_FALSE)
{
RARCH_ERR("initializing COM\n");
return ieHRESULT("initializing COM", hr); return ieHRESULT("initializing COM", hr);
}
// LONGTERM initialize COM security // LONGTERM initialize COM security
// LONGTERM (windows vista) turn off COM exception handling // LONGTERM (windows vista) turn off COM exception handling
hr = initDraw(); hr = initDraw();
if (hr != S_OK) if (hr != S_OK)
{
RARCH_ERR("initializing Direct2D\n");
return ieHRESULT("initializing Direct2D", hr); return ieHRESULT("initializing Direct2D", hr);
}
hr = initDrawText(); hr = initDrawText();
if (hr != S_OK) if (hr != S_OK)
{
RARCH_ERR("initializing DirectWrite\n");
return ieHRESULT("initializing DirectWrite", hr); return ieHRESULT("initializing DirectWrite", hr);
}
if (registerAreaClass(hDefaultIcon, hDefaultCursor) == 0) if (registerAreaClass(hDefaultIcon, hDefaultCursor) == 0)
{
RARCH_ERR("registering uiArea window class\n");
return ieLastErr("registering uiArea window class"); return ieLastErr("registering uiArea window class");
}
if (registerMessageFilter() == 0) if (registerMessageFilter() == 0)
{
RARCH_ERR("registering libui message filter\n");
return ieLastErr("registering libui message filter"); return ieLastErr("registering libui message filter");
}
if (registerD2DScratchClass(hDefaultIcon, hDefaultCursor) == 0) if (registerD2DScratchClass(hDefaultIcon, hDefaultCursor) == 0)
{
RARCH_ERR("initializing D2D scratch window class\n");
return ieLastErr("initializing D2D scratch window class"); return ieLastErr("initializing D2D scratch window class");
}
return NULL; return NULL;
} }
@ -205,3 +158,10 @@ void uiFreeInitError(const char *err)
if (*(err - 1) == '-') if (*(err - 1) == '-')
uiFree((void *) (err - 1)); uiFree((void *) (err - 1));
} }
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
hInstance = hinstDLL;
return TRUE;
}

Some files were not shown because too many files have changed in this diff Show More