ui/motif/window.c

changeset 115
e57ca2747782
parent 108
77254bd6dccb
--- a/ui/motif/window.c	Sun Dec 07 20:00:33 2025 +0100
+++ b/ui/motif/window.c	Sat Dec 13 15:58:58 2025 +0100
@@ -28,15 +28,22 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include "window.h"
 
 #include "toolkit.h"
 #include "menu.h"
 #include "toolbar.h"
 #include "container.h"
-#include "../ui/window.h"
+#include "pathbar.h"
 #include "../common/context.h"
+#include "../common/utils.h"
 
 #include "Grid.h"
+#include "Fsb.h"
 
 #include <cx/mempool.h>
 
@@ -50,7 +57,7 @@
     uic_object_destroy(obj);
     nwindows--;
     if(nwindows == 0) {
-        ui_exit_mainloop();
+        ui_app_quit();
     }
 }
 
@@ -67,20 +74,28 @@
 }
 
 
-static UiObject* create_window(const char *title, void *window_data, Boolean simple) {
+static UiObject* create_window(const char *title, Boolean simple) {
     CxMempool *mp = cxMempoolCreateSimple(256);
     const CxAllocator *a = mp->allocator;
     UiObject *obj = uic_object_new_toplevel();
-    obj->window = window_data;
     obj->destroy = ui_window_widget_destroy;
     
+    int window_width = window_default_width;
+    int window_height = window_default_height;
+    if(!simple) {
+        ui_get_window_default_width(&window_width, &window_height);
+    }
+    
+    UiMotifAppWindow *appwindow = cxZalloc(a, sizeof(UiMotifAppWindow));
+    ui_object_set(obj, "ui_motif_app_window", appwindow);
+    
     Arg args[16];
     int n = 0;
     XtSetArg(args[n], XmNtitle, title); n++;
     XtSetArg(args[n], XmNminWidth, 100); n++;
     XtSetArg(args[n], XmNminHeight, 50); n++;
-    XtSetArg(args[n], XmNwidth, window_default_width); n++;
-    XtSetArg(args[n], XmNheight, window_default_height); n++;
+    XtSetArg(args[n], XmNwidth, window_width); n++;
+    XtSetArg(args[n], XmNheight, window_height); n++;
     
     Widget toplevel = XtAppCreateShell(
             ui_appname(),
@@ -110,7 +125,7 @@
     
     // menu
     if(!simple) {
-        ui_create_menubar(obj, window);
+        appwindow->menubar = ui_create_menubar(obj, window);
     }
     
     // content frame
@@ -135,10 +150,161 @@
     return obj;
 } 
 
-UiObject* ui_window(const char *title, void *window_data) {
-    return create_window(title, window_data, FALSE);
+UiObject* ui_window(const char *title) {
+    return create_window(title, FALSE);
+}
+
+UiObject* ui_simple_window(const char *title) {
+    return create_window(title, TRUE);
+}
+
+void ui_window_size(UiObject *obj, int width, int height) {
+    XtVaSetValues(obj->widget, XmNwidth, width, XmNheight, height, NULL);
+}
+
+void ui_window_default_size(int width, int height) {
+    window_default_width = width;
+    window_default_height = height;
+}
+
+void ui_window_menubar_set_visible(UiObject *obj, UiBool visible) {
+    UiMotifAppWindow *window = ui_object_get(obj, "ui_motif_app_window");
+    if(window) {
+        if(window->menubar) {
+            ui_set_visible(window->menubar, visible);
+        }
+    } else {
+        fprintf(stderr, "Error: obj is not an application window\n");
+    }
+}
+
+static Atom net_wm_state;
+static Atom net_wm_state_fullscreen;
+static int net_wm_atoms_initialized = 0;
+
+void ui_window_fullscreen(UiObject *obj, UiBool fullscreen) {
+    Display *dpy = XtDisplay(obj->widget);
+    
+    // init net_wm_state atoms
+    if(!net_wm_atoms_initialized) {
+        net_wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
+        net_wm_state_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+        net_wm_atoms_initialized = 1;
+    }
+    
+    XEvent ev;
+    memset(&ev, 0, sizeof(XEvent));
+    ev.type = ClientMessage;
+    ev.xclient.window = XtWindow(obj->widget);
+    ev.xclient.message_type = net_wm_state;
+    ev.xclient.format = 32;
+    ev.xclient.data.l[0] = fullscreen ? 1 : 0;
+    ev.xclient.data.l[1] = net_wm_state_fullscreen;
+    ev.xclient.data.l[2] = 0;
+    XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureNotifyMask | SubstructureRedirectMask, &ev);
+}
+
+static void filedialog_event(UiEventData *event, int result, UiFileList flist) {
+    UiEvent evt;
+    evt.obj = event->obj;
+    evt.document = evt.obj->ctx->document;
+    evt.window = evt.obj->window;
+    evt.intval = result;
+    
+    evt.eventdata = &flist;
+    evt.eventdatatype = UI_EVENT_DATA_FILE_LIST;
+    
+    if(event->callback) {
+        event->callback(&evt, event->userdata);
+    }
 }
 
-UiObject* ui_simple_window(const char *title, void *window_data) {
-    return create_window(title, window_data, TRUE);
+static void filedialog_select(
+        Widget widget,
+        UiEventData *data,
+        XmFileSelectionBoxCallbackStruct *selection)
+{
+    UiFileList flist;
+    
+    char *value = NULL;
+    XmStringGetLtoR(selection->value, XmSTRING_DEFAULT_CHARSET, &value);
+    flist.files = &value;
+    flist.nfiles = 1;
+    
+    filedialog_event(data, 1, flist);
+    
+    XtFree(value);
+    
+    XtUnmanageChild(widget);
+    XtDestroyWidget(widget);
+}
+
+static void filedialog_cancel(
+        Widget widget,
+        UiEventData *data,
+        XmFileSelectionBoxCallbackStruct *selection)
+{
+    UiFileList flist;
+    flist.files = NULL;
+    flist.nfiles = 0;
+    filedialog_event(data, 0, flist);
+    
+    XtUnmanageChild(widget);
+    XtDestroyWidget(widget);
 }
+
+void ui_openfiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata) {
+    Widget dialog = XnCreateFileSelectionDialog(obj->widget, "dialog", NULL, 0);
+    
+    UiEventData *data = malloc(sizeof(UiEventData));
+    memset(data, 0, sizeof(UiEventData));
+    data->obj = obj;
+    data->callback = file_selected_callback;
+    data->userdata = cbdata;
+    
+    XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)filedialog_select, data);
+    XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)filedialog_cancel, data);
+    //XtAddCallback(dialog, XmNhelpCallback, (XtCallbackProc)filedialog_help, wd);
+    
+    XtManageChild(dialog);
+}
+
+void ui_savefiledialog(UiObject *obj, const char *name, ui_callback file_selected_callback, void *cbdata) {
+    Arg args[16];
+    int n = 0;
+    
+    // Save File Dialog needs this parameter
+    XtSetArg(args[n], XnNfsbType, FILEDIALOG_SAVE); n++;
+    char *selectedpath = (char*)name;
+    if(name) {
+        if(name[0] != '/') {
+            char cwd[PATH_MAX];
+            if(getcwd(cwd, PATH_MAX)) {
+                pathbar_concat_path(cwd, name);
+            } else {
+                fprintf(stderr, "Error: getcwd failed: %s\n", strerror(errno));
+                selectedpath = NULL;
+            }
+        }
+        if(selectedpath) {
+            XtSetArg(args[n], XnNselectedPath, selectedpath); n++;
+        }
+    }
+    Widget dialog = XnCreateFileSelectionDialog(obj->widget, "dialog", args, n);
+    
+    UiEventData *data = malloc(sizeof(UiEventData));
+    memset(data, 0, sizeof(UiEventData));
+    data->obj = obj;
+    data->callback = file_selected_callback;
+    data->userdata = cbdata;
+    
+    XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)filedialog_select, data);
+    XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)filedialog_cancel, data);
+    //XtAddCallback(dialog, XmNhelpCallback, (XtCallbackProc)filedialog_help, wd);
+    
+    XtManageChild(dialog);
+    
+    if(selectedpath != name) {
+        free(selectedpath);
+    }
+}

mercurial