Thu, 11 Dec 2025 20:07:16 +0100
remove window data arg
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2024 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #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 "pathbar.h" #include "../common/context.h" #include "../common/utils.h" #include "Grid.h" #include "Fsb.h" #include <cx/mempool.h> static int nwindows = 0; static int window_default_width = 600; static int window_default_height = 500; void ui_window_widget_destroy(UiObject *obj) { XtDestroyWidget(obj->widget); uic_object_destroy(obj); nwindows--; if(nwindows == 0) { ui_app_quit(); } } static void window_close_handler(Widget window, void *udata, void *cdata) { UiObject *obj = udata; uic_context_prepare_close(obj->ctx); obj->ref--; if(obj->ref > 0) { XtUnmapWidget(obj->widget); } else { ui_window_widget_destroy(obj); } } 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->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_width); n++; XtSetArg(args[n], XmNheight, window_height); n++; Widget toplevel = XtAppCreateShell( ui_appname(), "mainwindow", //applicationShellWidgetClass, vendorShellWidgetClass, ui_motif_get_display(), args, n); Atom wm_delete_window; wm_delete_window = XmInternAtom( XtDisplay(toplevel), "WM_DELETE_WINDOW", 0); XmAddWMProtocolCallback( toplevel, wm_delete_window, window_close_handler, obj); Widget window = XtVaCreateManagedWidget( title, xmMainWindowWidgetClass, toplevel, NULL); // menu if(!simple) { appwindow->menubar = ui_create_menubar(obj, window); } // content frame n = 0; Widget frame = XmCreateFrame(window, "window_frame", args, n); XtManageChild(frame); Widget form = XmCreateForm(frame, "window_form", args, 0); XtManageChild(form); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; Widget vbox = XtCreateManagedWidget("window_vbox", gridClass, form, args, n); UiContainerX *container = ui_box_container(obj, vbox, UI_BOX_VERTICAL); uic_object_push_container(obj, container); obj->widget = toplevel; nwindows++; return obj; } 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); } } 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); } }