From 5023b63a7ef6b668d0289196d078d9c6f6225090 Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Wed, 26 Nov 2025 13:56:19 +0100 Subject: [PATCH] windows integration Signed-off-by: Hans Dijkema --- CMakeLists.txt | 4 +- exe_path.cpp | 20 ---- exe_path.h | 14 --- gtk-imports.h | 25 ++++- info_over_me.cpp | 109 ++++++++++++++++++ info_over_me.h | 20 ++++ main.cpp | 8 +- tr.cpp | 1 + yellownotes.cpp | 283 ++++++++++++++++++++++++++++++++++++++++++++--- yellownotes.h | 12 +- 10 files changed, 440 insertions(+), 56 deletions(-) delete mode 100644 exe_path.cpp delete mode 100644 exe_path.h create mode 100644 info_over_me.cpp create mode 100644 info_over_me.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f203a07..937e0fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,9 +11,9 @@ add_executable(yellownotes main.cpp gtk-imports.c yellownotes.h yellownotes.cpp tr.h tr.cpp - win32gtkdownloader.h win32gtkdownloader.cpp) + win32gtkdownloader.h win32gtkdownloader.cpp utils/whereami.c utils/whereami.h - exe_path.h exe_path.cpp) + info_over_me.h info_over_me.cpp) include(GNUInstallDirs) install(TARGETS yellownotes diff --git a/exe_path.cpp b/exe_path.cpp deleted file mode 100644 index ecbd4c6..0000000 --- a/exe_path.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "exe_path.h" - -#include "utils/whereami.h" - -#include - -std::string WhereAmI::containing_folder() -{ - int len = wai_getExecutablePath(NULL, 0, NULL); - - char *path = static_cast(malloc(len + 1)); - wai_getExecutablePath(path, len, NULL); - path[len] = '\0'; - - std::string p(path); - std::cout << p << std::endl; - return p; -} - -WhereAmI::WhereAmI() {} diff --git a/exe_path.h b/exe_path.h deleted file mode 100644 index e532334..0000000 --- a/exe_path.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef EXE_PATH_H -#define EXE_PATH_H - -#include - -class WhereAmI -{ -public: - std::string containing_folder(); -public: - WhereAmI(); -}; - -#endif // EXE_PATH_H diff --git a/gtk-imports.h b/gtk-imports.h index 20c3eaf..ede788d 100644 --- a/gtk-imports.h +++ b/gtk-imports.h @@ -74,6 +74,8 @@ typedef void GtkGrid; typedef void GtkColorButton; typedef void GtkColorChooser; typedef void GtkSpinButton; +typedef void GdkMonitor; +typedef void GdkScreen; typedef int gboolean; typedef int gint; @@ -142,14 +144,14 @@ typedef enum { PANGO_ELLIPSIZE_END = 3 } PangoEllipsizeMode; -struct GdkRectangle { +typedef struct _GdkRectangle { int x; int y; int width; int height; -}; +} GdkRectangle; -typedef struct GdkRectangle GtkAllocation; +typedef struct _GdkRectangle GtkAllocation; #define G_VALUE_INIT { 0, { { 0 } } } @@ -570,6 +572,14 @@ typedef struct _GdkEventVisibility GdkVisibilityState state; } GdkEventVisibility; +typedef struct _GList { + gpointer data; + gpointer next; + gpointer prev; +} GList; + +typedef void GListModel; + #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) @@ -693,6 +703,15 @@ DECL(GtkWidget*, gtk_dialog_get_content_area, (GtkDialog* dialog )) DECL(gboolean, gtk_combo_box_set_active_id, ( GtkComboBox* combo_box, const gchar* active_id )) DECL(const gchar*, gtk_combo_box_get_active_id, (GtkComboBox* combo_box)) +// Gdk Monitor/Screen + +DECL(GdkDisplay*, gdk_display_get_default, (void)) +DECL(int, gdk_display_get_n_monitors, (GdkDisplay* display)) +DECL(GdkMonitor*, gdk_display_get_monitor, (GdkDisplay* display, int monitor_num)) +DECL(void, gdk_monitor_get_geometry, (GdkMonitor* monitor, GdkRectangle* geometry)) +DECL(GList*, gdk_screen_get_window_stack, (GdkScreen* screen)) +DECL(GdkScreen*, gdk_screen_get_default, (void)) + // GObject / GValue DECL(void, g_object_unref, (GObject* object)) DECL(void, g_object_ref, (GObject* object)) diff --git a/info_over_me.cpp b/info_over_me.cpp new file mode 100644 index 0000000..d3d2449 --- /dev/null +++ b/info_over_me.cpp @@ -0,0 +1,109 @@ +#include "info_over_me.h" + +#include "utils/whereami.h" + +#include +#ifdef __linux +#include +#endif + +#ifdef _WIN32 +#include +#endif + +extern "C" { +#include "gtk-imports.h" +} +#include + +std::string InfoOverMe::containingFolder() +{ + int len = wai_getExecutablePath(NULL, 0, NULL); + + char *path = static_cast(malloc(len + 1)); + wai_getExecutablePath(path, len, NULL); + path[len] = '\0'; + + std::string p(path); + std::cout << p << std::endl; + return p; +} + +std::string InfoOverMe::myHostname() +{ + char buf[10240]; +#ifdef __linux + int r = gethostname(buf, 10240); +#endif +#ifdef _WIN32 + DWORD size = 10240; + bool r = GetComputerNameA(buf, &size); + buf[size] = '\0'; + if (!r) { sprintf(buf, "unknown"); } +#endif + std::string name(buf); + return name; +} + +std::string InfoOverMe::myOsHostname() +{ + std::string os; +#ifdef __linux + os = "linux"; +#else +#ifdef _WIN32 + os = "windows"; +#else + os = "unknown"; +#endif +#endif + return os + "_" + myHostname(); +} + +std::string InfoOverMe::myId() +{ + + std::list l; + GdkDisplay *d = gdk_display_get_default(); + int n = gdk_display_get_n_monitors(d); + int i; + for(i = 0; i < n; i++) { + GdkMonitor *m = gdk_display_get_monitor(d, i); + GdkRectangle r; + gdk_monitor_get_geometry(m, &r); + l.push_back(r); + //std::cout << r.width << ", " << r.height << ", x = " << r.x << ", y = " << r.y << std::endl; + } + + auto compare = [](const GdkRectangle &a, const GdkRectangle &b) { + if (a.x < b.x) { + return true; + } else if (a.x > b. x) { + return false; + } else if (a.y < b.y) { + return true; + } else { + return false; + } + }; + + l.sort(compare); + std::list::iterator it; + std::string monitor_id; + std::string sep = ""; + for(it = l.begin(); it != l.end(); it++) { + char buf[200]; + const GdkRectangle &r = *it; + sprintf(buf, "%d-%d-%d-%d", r.x, r.y, r.width, r.height); + std::string geom(buf); + monitor_id += sep; + monitor_id += geom; + sep = "-"; + } + + monitor_id = myOsHostname() + "/" + monitor_id; + + return monitor_id; +} + +InfoOverMe::InfoOverMe() {} diff --git a/info_over_me.h b/info_over_me.h new file mode 100644 index 0000000..0c63b7e --- /dev/null +++ b/info_over_me.h @@ -0,0 +1,20 @@ +#ifndef INFO_OVER_ME_H +#define INFO_OVER_ME_H + +#include + +class InfoOverMe +{ +public: + std::string containingFolder(); + +public: + std::string myHostname(); + std::string myOsHostname(); + std::string myId(); + +public: + InfoOverMe(); +}; + +#endif // INFO_OVER_ME_H diff --git a/main.cpp b/main.cpp index e9906c9..513696f 100644 --- a/main.cpp +++ b/main.cpp @@ -6,7 +6,7 @@ extern "C" { } #include "yellownotes.h" -#include "exe_path.h" +#include "info_over_me.h" SIGNAL(YellowNotes, on_tray_activate, popupTrayMenu) @@ -23,11 +23,13 @@ static void activate (GtkApplication* app, gpointer user_data) int main(int argc, char **argv) { GtkLoader l; - WhereAmI w; + InfoOverMe w; + + std::cout << w.myOsHostname() << std::endl; srand(time(NULL)); // seed with current time - std::string my_path = w.containing_folder(); + std::string my_path = w.containingFolder(); try { l.loadGtk(); diff --git a/tr.cpp b/tr.cpp index 9db430b..742a631 100644 --- a/tr.cpp +++ b/tr.cpp @@ -95,6 +95,7 @@ tr::tr() nl("Grey", "Grijs"); nl("Font size:", "Lettertype Grootte:"); nl("Actual Font Size in Note", "Werkelijke lettertype grootte in de notitie"); + nl("Reorder Notes", "Notities opnieuw ordenen"); _lang = "en"; } diff --git a/yellownotes.cpp b/yellownotes.cpp index 1a3d9c0..0c49479 100644 --- a/yellownotes.cpp +++ b/yellownotes.cpp @@ -13,6 +13,7 @@ #ifdef _WIN32 #include +#include #endif #include @@ -21,7 +22,9 @@ extern "C" { } #include "tr.h" - +#include "info_over_me.h" +#include +#include #include static void trim(std::string &s) { @@ -34,6 +37,17 @@ static void trim(std::string &s) { s = s.substr(start, end - start + 1); } +class StoredCoords +{ +public: + bool hidden; + int x; + int y; + int width; + int height; + std::string os_host; +}; + class YellowNote { @@ -65,6 +79,8 @@ private: std::string _note; std::string _title; + std::list _stored_coords; + bool _hidden; bool _hidden_loaded; @@ -143,6 +159,7 @@ public: bool textSaveTimeout(); bool windowPresented(void *sender, GdkEventVisibility *evt); void showNote(GtkWidget *sender); + void moveTo(int x, int y); public: std::string title(); @@ -232,10 +249,12 @@ SIGNAL(YellowNotes, on_to_back, notesToDesktop); SIGNAL(YellowNotes, on_reload, reloadNotes); SIGNAL(YellowNotes, on_setup, setup); SIGNAL(YellowNotes, on_quit, quit) +SIGNAL(YellowNotes, on_reorder, reOrder); SIGNAL(YellowNotes, on_hide_toplevel, topLevelHidden) SIGNAL(YellowNotes, on_setup_ok, setupClose); SIGNAL(YellowNotes, on_setup_close, setupCancel); BSIGNAL2(YellowNotes, on_setup_del, setupDel, void); +SIGNAL(YellowNotes, on_monitors_changed, monitorsChanged); std::string YellowNotes::imageFile(const char *name) @@ -326,6 +345,11 @@ void YellowNotes::updateWidgetCss(GtkWidget *w, ColorType_t col) set_style(w); } +GtkWidget *YellowNotes::getWindow() +{ + return topLevel(); +} + std::string YellowNotes::getFgColor(ColorType_t type) { char buf[100]; @@ -496,6 +520,7 @@ void YellowNotes::popupTrayMenu(void *sender) GtkWidget *sep1 = gtk_separator_menu_item_new(); GtkMenuItem *setup = gtk_menu_item_new_with_label(_("Setup")); + GtkMenuItem *reorder = gtk_menu_item_new_with_label(_("Reorder Notes")); GtkMenuItem *quit = gtk_menu_item_new_with_label(_("Quit")); gtk_menu_shell_append(tray_menu, new_yellow); @@ -512,6 +537,7 @@ void YellowNotes::popupTrayMenu(void *sender) gtk_menu_shell_append(tray_menu, sep1); gtk_menu_shell_append(tray_menu, setup); + gtk_menu_shell_append(tray_menu, reorder); gtk_menu_shell_append(tray_menu, quit); gtk_widget_show_all(tray_menu); @@ -520,6 +546,7 @@ void YellowNotes::popupTrayMenu(void *sender) g_signal_connect(notes_to_back, "activate", on_to_back, this); g_signal_connect(reload_notes, "activate", on_reload, this); g_signal_connect(setup, "activate", on_setup, this); + g_signal_connect(reorder, "activate", on_reorder, this); g_signal_connect(quit, "activate", on_quit, this); w_it = hidden.begin(); it = h_notes.begin(); @@ -811,6 +838,22 @@ void YellowNotes::setup(void *sender) gtk_widget_show_all(dlg); } +void YellowNotes::reOrder(void *sender) +{ + int x = 50; + int y = 50; + + std::list::iterator it; + for(it = _notes.begin(); it != _notes.end(); it++, x += 25, y += 25) { + (*it)->moveTo(x, y); + } +} + +void YellowNotes::monitorsChanged(void *sender) +{ + this->reloadNotes(sender); +} + void YellowNotes::reloadNotes(void *sender) { std::list::const_iterator it = _notes.begin(); @@ -911,6 +954,87 @@ void YellowNotes::topLevelHidden(GtkWidget *sender) g_timeout_add(500, show_notes_timed, this); } +void YellowNotes::checkMonitors() +{ + auto compare = [](const Geom_t &a, const Geom_t &b) { + if (a.x < b.x) { + return true; + } else if (a.x > b. x) { + return false; + } else if (a.y < b.y) { + return true; + } else { + return false; + } + }; + + GdkDisplay *d = gdk_display_get_default(); + int n = gdk_display_get_n_monitors(d); + + if (_monitors.empty()) { + int i; + for(i = 0; i < n; i++) { + GdkMonitor *m = gdk_display_get_monitor(d, i); + GdkRectangle r; + gdk_monitor_get_geometry(m, &r); + Geom_t g; + g.x = r.x; + g.y = r.y; + g.width = r.width; + g.height = r.height; + _monitors.push_back(g); + } + _monitors.sort(compare); + } else { + if (n != _monitors.size()) { + _monitors.clear(); + checkMonitors(); + monitorsChanged(nullptr); + } else { + std::list l; + int i; + for(i = 0; i < n; i++) { + GdkMonitor *m = gdk_display_get_monitor(d, i); + GdkRectangle r; + gdk_monitor_get_geometry(m, &r); + Geom_t g; + g.x = r.x; + g.y = r.y; + g.width = r.width; + g.height = r.height; + l.push_back(g); + } + l.sort(compare); + std::list::iterator m_it = _monitors.begin(); + std::list::iterator l_it = l.begin(); + while(l_it != l.end()) { + Geom_t g_l = *l_it; + Geom_t g_m = *m_it; + if (g_l.x != g_m.x || g_l.y != g_m.y || g_l.width != g_m.width || g_l.height != g_m.height) { + _monitors.clear(); + checkMonitors(); + monitorsChanged(nullptr); + } + l_it++; + m_it++; + } + } + } +} + +static YellowNotes *_the_notes = nullptr; + +gboolean monitor_monitors(void *data) +{ + YellowNotes *n = reinterpret_cast(data); + if (_the_notes == nullptr) { + return false; + } else { + n->checkMonitors(); + return true; + } +} + GtkWindow *YellowNotes::topLevel() { if (_toplevel == nullptr) { @@ -927,11 +1051,14 @@ YellowNotes::YellowNotes(void *app) _tray_menu = nullptr; _font_size = 15; _toplevel = nullptr; + _the_notes = this; + g_timeout_add(1000, monitor_monitors, this); // Beware monitor_monitors checks _the_notes. loadConfig(); } YellowNotes::~YellowNotes() { + _the_notes = nullptr; if (_tray_menu) { gtk_widget_destroy(reinterpret_cast(_tray_menu)); } clearNotes(); gtk_widget_destroy(_toplevel); @@ -1228,6 +1355,13 @@ void YellowNote::showNote(GtkWidget *sender) show(); } +void YellowNote::moveTo(int x, int y) +{ + _x = x; + _y = y; + updatePosition(); +} + void YellowNote::setLoaded() { _pos_loaded = true; @@ -1299,12 +1433,20 @@ void YellowNote::toFront() } } - void YellowNote::toDesktop() { #ifdef __linux gtk_window_set_type_hint(_note_widget, GdkWindowTypeHint::GDK_WINDOW_TYPE_HINT_DESKTOP); #endif +#ifdef _WIN32 + GdkWindow *notes_win = gtk_widget_get_window(_notes->getWindow()); + HWND nw = gdk_win32_window_get_handle(notes_win); + SetWindowPos(nw, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + + GdkWindow *win = gtk_widget_get_window(_note_widget); + HWND w = gdk_win32_window_get_handle(win); + SetWindowPos(w, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); +#endif } void YellowNote::fromDesktop() @@ -1655,7 +1797,7 @@ bool YellowNote::moving(GtkWidget *sender, GdkEventMotion *evt) return false; } -#define YELLOWNOTE_VERSION 2 +#define YELLOWNOTE_VERSION 3 void YellowNote::load() { @@ -1678,6 +1820,68 @@ void YellowNote::load() std::string title; bool title_only; + InfoOverMe info; + std::string my_name = info.myId(); + + auto readKind = [my_name, this](std::string line, std::function f) { + // Split line in parts. + std::istringstream inp(line); + std::string part; + bool found = false; + while(std::getline(inp, part, ',')) { + std::string os_host; + int val; + int idx; + idx = part.find(":"); + if (idx >= 0) { + os_host = part.substr(0, idx); + std::string s = part.substr(idx + 1); + val = atoi(s.c_str()); + f(os_host,val); + if (os_host == my_name) { found = true; } + } + } + return found; + }; + + auto getStoredCoord = [this](const std::string &os_host, bool &created) { + std::list::iterator it = _stored_coords.begin(); + while(it != _stored_coords.end() && it->os_host != os_host) { + it++; + } + if (it == _stored_coords.end()) { + StoredCoords c; + c.os_host = os_host; + _stored_coords.push_back(c); + StoredCoords *r = &(_stored_coords.back()); + created = true; + return r; + } else { + StoredCoords *r = &(*it); + created = false; + return r; + } + }; + + auto setStoredCoordVar = [this, getStoredCoord, readKind](std::string line, std::function f) { + auto setter = [f, this, getStoredCoord](const std::string &os_name, int val) { + bool created; + StoredCoords *r = getStoredCoord(os_name, created); + f(r, val); + }; + readKind(line, setter); + }; + + auto readLine = [](FILE *f) { + char buf[10240]; + fgets(buf, 10240, f); + std::string l(buf); + trim(l); + return l; + }; + + _stored_coords.clear(); + size_t s = 0; if (std::filesystem::is_regular_file(p)) { s = std::filesystem::file_size(p); @@ -1687,11 +1891,36 @@ void YellowNote::load() if (f) { int version = readInt(f, -1); - hidden = readInt(f, -1); - x = readInt(f, 200); - y = readInt(f, 200); - width = readInt(f, 300); - height = readInt(f, 200); + if (version <= 2) { + hidden = readInt(f, -1); + x = readInt(f, 200); + y = readInt(f, 200); + width = readInt(f, 300); + height = readInt(f, 200); + } else { + // fill in the dots. + setStoredCoordVar(readLine(f), [](StoredCoords *c, int val) { c->hidden = val; }); + setStoredCoordVar(readLine(f), [](StoredCoords *c, int val) { c->x = val; }); + setStoredCoordVar(readLine(f), [](StoredCoords *c, int val) { c->y = val; }); + setStoredCoordVar(readLine(f), [](StoredCoords *c, int val) { c->width = val; }); + setStoredCoordVar(readLine(f), [](StoredCoords *c, int val) { c->height = val; }); + + bool created; + StoredCoords *r = getStoredCoord(my_name, created); + if (created) { + r->hidden = false; + r->x = 100; + r->y = 100; + r->width = 300; + r->height = 200; + } + + hidden = r->hidden; + x = r->x; + y = r->y; + width = r->width; + height = r->height; + } int color; color = readInt(f, ColorType_t::YELLOW); @@ -1751,15 +1980,43 @@ void YellowNote::save() return; } + InfoOverMe info; + std::string my_name = info.myId(); + + auto storeKind = [my_name, this](int val, std::function f) { + std::string line(""); + std::list::iterator it; + std::string comma(""); + bool stored = false; + for(it = _stored_coords.begin(); it != _stored_coords.end(); it++) { + const StoredCoords &c = *it; + int num = (my_name == c.os_host) ? val : f(c); + if (my_name == c.os_host) { stored = true; } + char buf[100]; + sprintf(buf, "%d", num); + line += comma + c.os_host + ":" + buf; + comma = ","; + } + if (!stored) { + char buf[100]; + sprintf(buf, "%d", val); + line += comma + my_name + ":" + buf; + } + return line; + }; + std::filesystem::path p(_filename); FILE *f = fopen(_filename.c_str(), "wt"); if (f) { fprintf(f, "%d\n", YELLOWNOTE_VERSION); - fprintf(f, "%d\n", _hidden); - fprintf(f, "%d\n", _x); - fprintf(f, "%d\n", _y); - fprintf(f, "%d\n", _width); - fprintf(f, "%d\n", _height); + + + fprintf(f, "%s\n", storeKind(_hidden, [](const StoredCoords &c) { return c.hidden; }).c_str()); + fprintf(f, "%s\n", storeKind(_x, [](const StoredCoords &c) { return c.x; }).c_str()); + fprintf(f, "%s\n", storeKind(_y, [](const StoredCoords &c) { return c.y; }).c_str()); + fprintf(f, "%s\n", storeKind(_width, [](const StoredCoords &c) { return c.width; }).c_str()); + fprintf(f, "%s\n", storeKind(_height, [](const StoredCoords &c) { return c.height; }).c_str()); + fprintf(f, "%d\n", _color); fprintf(f, "%d\n", _title_only); fprintf(f, "%s\n", _title.c_str()); diff --git a/yellownotes.h b/yellownotes.h index 2ec54e1..2a754d2 100644 --- a/yellownotes.h +++ b/yellownotes.h @@ -25,6 +25,11 @@ typedef enum { LAST = GREY } ColorType_t; +class Geom_t { +public: + int x, y, width, height; +}; + class YellowNotes { private: @@ -34,12 +39,13 @@ private: void *_langs; std::list _settings_containers; - std::list _notes; int _font_size; GtkWindow *_toplevel; std::unordered_map _cfg; + std::list _monitors; + private: void loadConfig(); void saveConfig(); @@ -66,13 +72,16 @@ public: void notesToDesktop(void *sender); void notesFromDesktop(void *sender); void reloadNotes(void *sender); + void monitorsChanged(void *sender); void quit(void *sender); void topLevelHidden(GtkWidget *sender); void setup(void *sender); + void reOrder(void *sender); void setupClose(GtkWidget *sender); void setupCancel(GtkWidget *sender); bool setupDel(GtkWidget *sender, void *evt); void remove(YellowNote *n); + void checkMonitors(); public: std::string currentLang(); @@ -86,6 +95,7 @@ public: std::string fromRGBA(const GdkRGBA &rgba); void toRGBA(const std::string &col, GdkRGBA &rgba); void updateWidgetCss(GtkWidget *w, ColorType_t col); + GtkWidget *getWindow(); public: YellowNotes(void *app);