From 6784ba6ebc7f0cb3c983503ce99bdbf375f8d81c Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Tue, 18 Nov 2025 18:03:58 +0100 Subject: [PATCH] Linux Signed-off-by: Hans Dijkema --- .gitignore | 4 + CMakeLists.txt | 3 +- gtk-imports.h | 269 +++++++++++++++++++++++++++++++++++++++++++++++- gtkloader.cpp | 49 +++++++++ gtkloader.h | 2 + main.cpp | 24 +++-- yellownotes.png | Bin 0 -> 2298 bytes yellownotes.svg | 7 ++ 8 files changed, 348 insertions(+), 10 deletions(-) create mode 100644 yellownotes.png create mode 100644 yellownotes.svg diff --git a/.gitignore b/.gitignore index e257658..4bc3d11 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,7 @@ *.out *.app +# Project specific +*.user +build + diff --git a/CMakeLists.txt b/CMakeLists.txt index ad32c65..74da535 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(yellownotes main.cpp gtk-imports.h gtkloader.h gtkloader.cpp - gtk-imports.c) + gtk-imports.c + yellownotes.h yellownotes.cpp) include(GNUInstallDirs) install(TARGETS yellownotes diff --git a/gtk-imports.h b/gtk-imports.h index 89a431a..cbe3a26 100644 --- a/gtk-imports.h +++ b/gtk-imports.h @@ -36,11 +36,35 @@ typedef void GApplication; typedef void GObject; typedef void *GCallback; typedef void *gpointer; +typedef void GClosure; +typedef void (*GClosureNotify) (gpointer data, GClosure *closure); +typedef void GtkStatusIcon; +typedef void GtkMenuShell; +typedef GtkMenuShell GtkMenu; +typedef void GtkMenuItem; +typedef void GdkEvent; +typedef void GtkTextBuffer; +typedef void GtkTextTagTable; +typedef void GtkContainer; +typedef void GtkLabel; +typedef void GtkHeaderBar; +typedef void GdkWindow; +typedef void GdkDevice; + typedef int gboolean; typedef int gint; typedef char gchar; -typedef void GClosure; -typedef void (*GClosureNotify) (gpointer data, GClosure *closure); +typedef long glong; +typedef unsigned long gulong; +typedef unsigned long guint32; +typedef unsigned int guint; +typedef long long gint64; +typedef unsigned long long guint64; +typedef float gfloat; +typedef double gdouble; +typedef char gint8; +typedef short gint16; + typedef enum { GTK_WINDOW_TOPLEVEL = 0 @@ -66,6 +90,190 @@ typedef enum { G_CONNECT_SWAPPED = 2 } GConnectFlags; +typedef enum { + GDK_GRAVITY_NORTH_WEST = 1, + GDK_GRAVITY_NORTH, + GDK_GRAVITY_NORTH_EAST, + GDK_GRAVITY_WEST, + GDK_GRAVITY_CENTER, + GDK_GRAVITY_EAST, + GDK_GRAVITY_SOUTH_WEST, + GDK_GRAVITY_SOUTH, + GDK_GRAVITY_SOUTH_EAST, + GDK_GRAVITY_STATIC +} GdkGravity; + +typedef enum { + GTK_ORIENTATION_HORIZONTAL = 0, + GTK_ORIENTATION_VERTICAL = 1 +} GtkOrientation; + +typedef enum { + PANGO_ELLIPSIZE_NONE = 0, + PANGO_ELLIPSIZE_START = 1, + PANGO_ELLIPSIZE_MIDDLE = 2, + PANGO_ELLIPSIZE_END = 3 +} PangoEllipsizeMode; + +struct GdkRectangle { + int x; + int y; + int width; + int height; +}; + +typedef struct GdkRectangle GtkAllocation; + +#define G_VALUE_INIT { 0, { { 0 } } } + +typedef void *GType; + +typedef struct _GValue +{ + /*< private >*/ + GType g_type; + + /* public for GTypeValueTable methods */ + union { + gint v_int; + guint v_uint; + glong v_long; + gulong v_ulong; + gint64 v_int64; + guint64 v_uint64; + gfloat v_float; + gdouble v_double; + gpointer v_pointer; + } data[2]; +} GValue; + +typedef struct _GtkTextIter { + /* GtkTextIter is an opaque datatype; ignore all these fields. + * Initialize the iter with gtk_text_buffer_get_iter_* + * functions + */ + /*< private >*/ + gpointer dummy1; + gpointer dummy2; + gint dummy3; + gint dummy4; + gint dummy5; + gint dummy6; + gint dummy7; + gint dummy8; + gpointer dummy9; + gpointer dummy10; + gint dummy11; + gint dummy12; + /* padding */ + gint dummy13; + gpointer dummy14; +} GtkTextIter; + +typedef enum +{ + GDK_DELETE, + GDK_MOTION_NOTIFY, + GDK_BUTTON_PRESS, + GDK_BUTTON_RELEASE, + GDK_KEY_PRESS, + GDK_KEY_RELEASE, + GDK_ENTER_NOTIFY, + GDK_LEAVE_NOTIFY, + GDK_FOCUS_CHANGE, + GDK_PROXIMITY_IN, + GDK_PROXIMITY_OUT, + GDK_DRAG_ENTER, + GDK_DRAG_LEAVE, + GDK_DRAG_MOTION, + GDK_DROP_START, + GDK_SCROLL, + GDK_GRAB_BROKEN, + GDK_TOUCH_BEGIN, + GDK_TOUCH_UPDATE, + GDK_TOUCH_END, + GDK_TOUCH_CANCEL, + GDK_TOUCHPAD_SWIPE, + GDK_TOUCHPAD_PINCH, + GDK_PAD_BUTTON_PRESS, + GDK_PAD_BUTTON_RELEASE, + GDK_PAD_RING, + GDK_PAD_STRIP, + GDK_PAD_GROUP_MODE, + GDK_TOUCHPAD_HOLD, + GDK_PAD_DIAL, + GDK_EVENT_LAST /* helper variable for decls */ +} GdkEventType; + +typedef struct _GdkEventButton +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble *axes; + guint state; + guint button; + GdkDevice *device; + gdouble x_root, y_root; +} GdkEventButton; + +typedef struct _GdkEventMotion +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble *axes; + guint state; + gint16 is_hint; + GdkDevice *device; + gdouble x_root, y_root; +} GdkEventMotion; + + + + +typedef enum +{ + GDK_EXPOSURE_MASK = 1 << 1, + GDK_POINTER_MOTION_MASK = 1 << 2, + GDK_POINTER_MOTION_HINT_MASK = 1 << 3, + GDK_BUTTON_MOTION_MASK = 1 << 4, + GDK_BUTTON1_MOTION_MASK = 1 << 5, + GDK_BUTTON2_MOTION_MASK = 1 << 6, + GDK_BUTTON3_MOTION_MASK = 1 << 7, + GDK_BUTTON_PRESS_MASK = 1 << 8, + GDK_BUTTON_RELEASE_MASK = 1 << 9, + GDK_KEY_PRESS_MASK = 1 << 10, + GDK_KEY_RELEASE_MASK = 1 << 11, + GDK_ENTER_NOTIFY_MASK = 1 << 12, + GDK_LEAVE_NOTIFY_MASK = 1 << 13, + GDK_FOCUS_CHANGE_MASK = 1 << 14, + GDK_STRUCTURE_MASK = 1 << 15, + GDK_PROPERTY_CHANGE_MASK = 1 << 16, + GDK_VISIBILITY_NOTIFY_MASK = 1 << 17, + GDK_PROXIMITY_IN_MASK = 1 << 18, + GDK_PROXIMITY_OUT_MASK = 1 << 19, + GDK_SUBSTRUCTURE_MASK = 1 << 20, + GDK_SCROLL_MASK = 1 << 21, + GDK_TOUCH_MASK = 1 << 22, + GDK_SMOOTH_SCROLL_MASK = 1 << 23, + GDK_TOUCHPAD_GESTURE_MASK = 1 << 24, + GDK_TABLET_PAD_MASK = 1 << 25, + GDK_ALL_EVENTS_MASK = 0x3FFFFFE +} GdkEventMask; + + +#define G_TYPE_FUNDAMENTAL_SHIFT (2) +#define G_TYPE_MAKE_FUNDAMENTAL(x) ((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT)) +#define G_TYPE_INT G_TYPE_MAKE_FUNDAMENTAL (6) + + #endif DECL(GtkApplication *, gtk_application_new, (const char *name, GApplicationFlags flags)) @@ -74,23 +282,80 @@ DECL(int, g_application_run, (GApplication* application, int argc, char** argv)) DECL(GtkWidget*, gtk_application_window_new, ( GtkApplication* application )) DECL(GtkWidget *, gtk_window_new, (GtkWindowType)) DECL(void, gtk_window_close, (GtkWindow *)) + +DECL(void, gtk_window_set_decorated, (GtkWindow* window, gboolean setting )) + DECL(void, gtk_widget_show_all, (GtkWindow *window)) +DECL(void, gtk_widget_hide, (GtkWidget* widget )) + +DECL(GtkWidget*, gtk_event_box_new, (void)) + DECL(void, gtk_window_get_size, (GtkWindow *win, int *width, int *height)) DECL(void, gtk_window_resize, (GtkWindow* window, gint width, gint height)) DECL(void, gtk_window_set_default_size, (GtkWindow *window, gint width, gint height)) DECL(void, gtk_window_get_position, (GtkWindow* window, gint* root_x, gint* root_y)) DECL(void, gtk_window_move, (GtkWindow* window, gint x, gint y)) +DECL(void, gtk_window_set_resizable, (GtkWindow* window, gboolean resizable)) +DECL(GdkWindow *, gtk_widget_get_window, (GtkWidget *w)); + + DECL(gboolean, gtk_window_get_decorated, (GtkWindow* window)) +DECL(void, gdk_window_set_events, (GdkWindow* window, GdkEventMask event_mask )) DECL(void, gtk_window_set_title, (GtkWindow* window, const gchar* title)) DECL(const gchar*, gtk_window_get_title, (GtkWindow* window)) +DECL(void, gtk_widget_destroy, (GtkWidget* widget)) +DECL(void, gtk_container_add, (GtkContainer* container, GtkWidget* widget)) +DECL(gboolean, gtk_widget_is_visible, (GtkWidget* widget)) +DECL(GtkWidget*, gtk_label_new, (const char* str)) +DECL(void, gtk_label_set_ellipsize, (GtkLabel* label, PangoEllipsizeMode mode)) +DECL(void, gtk_label_set_label, (GtkLabel* label, const gchar* str)) +DECL(const gchar*, gtk_label_get_text, (GtkLabel* label)) + +DECL(GtkWidget*, gtk_box_new, (GtkOrientation orientation, gint spacing )) + DECL(void, gtk_main, (void)) DECL(void, gtk_main_quit, (void)) DECL(unsigned long, g_signal_connect_data, (GObject *obj, const char *signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags)) + +// GObject / GValue DECL(void, g_object_unref, (GObject* object)) +DECL(void, g_object_set_property, (GObject* object, const gchar* property_name, const GValue* value)) +DECL(GValue*, g_value_init, (GValue* value, GType g_type)) +DECL(void, g_value_unset, (GValue* value)) +DECL(void, g_value_set_int, (GValue* value, gint v_int)) + + +// Menus + +DECL(void, gtk_menu_popup_at_pointer, (GtkMenu* menu, const GdkEvent* trigger_event)) +DECL(void, gtk_menu_popup_at_widget, (GtkMenu *menu, GtkWidget *widget, GdkGravity widget_anchor, GdkGravity menu_anchor, const GdkEvent *trigger_event)) +DECL(GtkMenu *, gtk_menu_new, (void)) +DECL(GtkMenuItem *, gtk_menu_item_new, (void)); +DECL(GtkMenuItem *, gtk_menu_item_new_with_label, (const gchar *label)); +DECL(void, gtk_menu_shell_append, (GtkMenuShell* menu_shell, GtkWidget* child)) +DECL(GtkWidget *, gtk_separator_menu_item_new, (void)) + +// Text Buffer / Widget +DECL(GtkTextBuffer*, gtk_text_buffer_new, (GtkTextTagTable* table)) +DECL(gchar*, gtk_text_buffer_get_text, (GtkTextBuffer* buffer, const GtkTextIter* start, const GtkTextIter* end, gboolean include_hidden_chars)) +DECL(void,gtk_text_buffer_get_start_iter, (GtkTextBuffer* buffer, GtkTextIter* iter)) +DECL(void, gtk_text_buffer_get_end_iter, (GtkTextBuffer* buffer, GtkTextIter* iter)) +DECL(GtkWidget*, gtk_text_view_new, (void)) +DECL(GtkWidget*, gtk_text_view_new_with_buffer, ( GtkTextBuffer* buffer )) +DECL(void, gtk_text_buffer_set_text, (GtkTextBuffer* buffer, const gchar* text, gint len )) + +// Titlebar +DECL(GtkWidget*, gtk_header_bar_new, (void)) +DECL(void, gtk_header_bar_set_custom_title, (GtkHeaderBar* bar, GtkWidget* title_widget)) + +// Deprecated in Gtk3 + +DECL(GtkStatusIcon*, gtk_status_icon_new, (void )) +DECL(GtkStatusIcon*, gtk_status_icon_new_from_file, (const gchar* filename)) #define g_signal_connect(instance, signal, c_handler, data) \ g_signal_connect_data(instance, signal, reinterpret_cast(c_handler), data, NULL, G_CONNECT_DEFAULT) diff --git a/gtkloader.cpp b/gtkloader.cpp index 34e7599..cfd62e2 100644 --- a/gtkloader.cpp +++ b/gtkloader.cpp @@ -11,6 +11,10 @@ extern "C" { #include #endif +#ifdef __linux +#include +#endif + void GtkLoader::loadLibraryWin64(const char *lib, void **handle) { #ifdef _WIN32 @@ -46,6 +50,16 @@ void GtkLoader::loadLibraryWin64(const char *lib, void **handle) #endif } +void GtkLoader::loadLibraryLinux(const char *lib, void **handle) +{ +#ifdef __linux + *handle = ::dlopen(lib, RTLD_LAZY); + if (*handle == NULL) { + throw std::string("Cannot load library '") + lib + "'"; + } +#endif +} + void GtkLoader::loadFunctionWin64(const char *func, void **func_ptr) { #ifdef _WIN32 @@ -66,6 +80,22 @@ void GtkLoader::loadFunctionWin64(const char *func, void **func_ptr) #endif } +void GtkLoader::loadFunctionLinux(const char *func, void **func_ptr) +{ +#ifdef __linux + *func_ptr = nullptr; + std::list::const_iterator it = library_handles.begin(); + while(*func_ptr == nullptr && it != library_handles.end()) { + void *handle = *it; + *func_ptr = dlsym(handle, func); + it++; + } + if (*func_ptr == nullptr) { + throw std::string("Cannot load function '") + func; + } +#endif +} + void GtkLoader::dlopen() { if (library_handles.size() == 0) { @@ -83,6 +113,22 @@ void GtkLoader::dlopen() loadLibraryWin64(libs[i], &lib); if (lib) { library_handles.push_back(lib); } } +#endif +#ifdef __linux + const char *libs[] = { + "libgtk-3.so", + "libgobject-2.0.so", + "libgio-2.0.so", + "libglib-2.0.so", + "libgdk-3.so", + NULL + }; + int i; + for(i = 0; libs[i] != NULL; i++) { + void *lib; + loadLibraryLinux(libs[i], &lib); + if (lib) { library_handles.push_back(lib); } + } #endif } } @@ -92,6 +138,9 @@ void GtkLoader::loadFunction(const char *func, void **func_ptr) #ifdef _WIN32 loadFunctionWin64(func, func_ptr); #endif +#ifdef __linux + loadFunctionLinux(func, func_ptr); +#endif } static void loader(const char *func, void **func_ptr, void *user_data) diff --git a/gtkloader.h b/gtkloader.h index 7866f02..8cab61a 100644 --- a/gtkloader.h +++ b/gtkloader.h @@ -11,6 +11,8 @@ private: private: void loadLibraryWin64(const char *lib, void **handle); void loadFunctionWin64(const char *func, void **func_ptr); + void loadLibraryLinux(const char *lib, void **handle); + void loadFunctionLinux(const char *func, void **func_ptr); public: void dlopen(); diff --git a/main.cpp b/main.cpp index 90eb865..0a68b54 100644 --- a/main.cpp +++ b/main.cpp @@ -5,14 +5,17 @@ extern "C" { #include "gtk-imports.h" } +#include "yellownotes.h" + +SIGNAL(YellowNotes, on_tray_activate, popupTrayMenu) + static void activate (GtkApplication* app, gpointer user_data) { GtkWidget *window; + YellowNotes *notes = YELLOWNOTES(user_data); - window = gtk_application_window_new (app); - gtk_window_set_title (window, "Window"); - gtk_window_set_default_size (window, 200, 200); - gtk_widget_show_all (window); + GtkStatusIcon *tray = gtk_status_icon_new_from_file(notes->imageFile("yellownotes.svg").c_str()); + g_signal_connect(tray, "activate", on_tray_activate, notes); } int main(int argc, char **argv) @@ -28,9 +31,16 @@ int main(int argc, char **argv) GtkApplication *app; int status; - app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE); - g_signal_connect (app, "activate", activate, NULL); - status = g_application_run (app, argc, argv); + app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE); + + YellowNotes notes(app); + + g_signal_connect (app, "activate", activate, ¬es); + status = g_application_run(app, argc, argv); + + notes.loadNotes(); + + gtk_main(); g_object_unref (app); return status; diff --git a/yellownotes.png b/yellownotes.png new file mode 100644 index 0000000000000000000000000000000000000000..b5a03a3a6cb1c77dcd5c66943fe45e1f503a7f47 GIT binary patch literal 2298 zcmeHJ>06Um9=$KJ*jUOUni2~cY}iu>qQzlJA|kQ~B0H1<0VIit2?R-yvWymdf@1I?THGiE;A=XdWp=brPs_rrZI*T?&~ zCJKWB0BE|qx%dJADW(wEsjettiGo-~`Hbln!UEunN63Ks8G;xEsGoE!ILVI@o5ZFh zo(60-+lqcJjulN|p0;8nQcIQ{F#znm?Cx^JpTl1of5Hf(LfI=)zW(_AXg9hJx~IZz zr?$g0AFhu}V?0^SsQ3JZq*?blzX( zyg%SSy+tehwKP1R%ZN^OWX(-XzG-uNw=zHf-Rrc(K0{L*SLnktgM|GK`Tb5wA+DO9&!&n?ZgbxCuU!+u@8zX-j=@#&bUn$Lp-6#^mk#CGt*4=)+N{HvJ$UUhZeBN3OMQpAEUJ;!_%Kof0*>x-~zzYX%7C^`F#Hbiu@?U)3+_pQl+?7y9#eP7kay~@hw-lj#~zquJcXD z&G)i2@{;W{y0#OHf>a4kHfPcriW#7ao^PEjW=TobuWLa~Y$f`i(kmNN8FR(ycmE7J zr%5ygWS+>ZVbXjqV|zKb@S2bB}fAs^G>GUKFGV{fF4{l9o=*=EQ5zZ z4dwLT1yd#PbCOrJ_whk%e*3R2pW-GUaA^0XBx!Q^Q<;M=+jS5h&XH$PB9MUf)Khg& zj-(K0WV`9fRs*X%c;6Lt<5s-zt_~=VvT>EzRXh)>Xyy%Mm(}=EO#({$J37M;OaCYc znzEnYPz4P-s{%*Mck%FB2KH@Yen-ZD2&hr zWX75^VOsC~Y^+98jDC%+@M3H}1wN$*Y*Fip=iyktD>Rrmhb` z2~LNwNag~q8}ZX?GE!>m)pT% z=rflP8C%&X|0WX36v>Qrz~LxZsslI_*g+e}BH>hRz=?#9>VOukcnS@XJ8ZUgC>Cfj zNe?1B*lb$p9Y7Oso&+Yh_zBFOIM-q0ZANnZ4iar=P zU6>6W(V!P}zE^cj*+_98^gvaYsefsa;`i$J%3LAm(G&`veIoSD54*AM-QEu+KWM}e zt23Nr#a-*8`vR~vypLU~W6N5k`S}^Gbest5VQ)?Es=w6pyt&FV=YspjOV7>6q|sWU zPl>@-nM;%MIsUl@QoZ1$nF+RJ`F^A^&nb&@)YjH+eR;?Bh%}=tC=G|M)BxnSFm^r5 W&<-*m!YlqQ!2OuFOQUn-#lHX`9cZNh literal 0 HcmV?d00001 diff --git a/yellownotes.svg b/yellownotes.svg new file mode 100644 index 0000000..6d5823f --- /dev/null +++ b/yellownotes.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file