From 5634b5d5d73c8b2a58313102dcfacf5501e29fa5 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 18 Nov 2025 18:47:11 -0700 Subject: [PATCH] ok --- CMakeLists.txt | 8 ++ LICENSE | 24 ++++ README.md | 1 + mdm/CMakeLists.txt | 29 +++++ mdm/config.c | 19 +++ mdm/login.c | 274 ++++++++++++++++++++++++++++++++++++++++++ mdm/main.c | 128 ++++++++++++++++++++ mdm/mdm.h | 62 ++++++++++ mdm/mdm.png | Bin 0 -> 5033 bytes mdm/mdmrc.in | 2 + mdm/pam | 5 + mdm/stb_ds.c | 2 + mdm/xserver.c | 163 +++++++++++++++++++++++++ milkwm/CMakeLists.txt | 2 + milkwm/main.c | 1 + mpanel/CMakeLists.txt | 10 ++ mpanel/main.c | 1 + 17 files changed, 731 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 README.md create mode 100644 mdm/CMakeLists.txt create mode 100644 mdm/config.c create mode 100644 mdm/login.c create mode 100644 mdm/main.c create mode 100644 mdm/mdm.h create mode 100644 mdm/mdm.png create mode 100644 mdm/mdmrc.in create mode 100644 mdm/pam create mode 100644 mdm/stb_ds.c create mode 100644 mdm/xserver.c create mode 100644 milkwm/CMakeLists.txt create mode 100644 milkwm/main.c create mode 100644 mpanel/CMakeLists.txt create mode 100644 mpanel/main.c diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e7f87e3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.25) +project( + mdebase +) + +add_subdirectory(mdm) +add_subdirectory(milkwm) +add_subdirectory(mpanel) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d6a83e7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2025, Milsko Desktop Experience development team +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* 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. +* Neither the name of the nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +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 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8764fdd --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Base package for MDE diff --git a/mdm/CMakeLists.txt b/mdm/CMakeLists.txt new file mode 100644 index 0000000..7ff4ebe --- /dev/null +++ b/mdm/CMakeLists.txt @@ -0,0 +1,29 @@ +include(MDEBase) +include(MDEPkgConfig) +setup_project(mdm ${CMAKE_INSTALL_SBINDIR}) + +pkg_config_add(mdm x11) +pkg_config_add(mdm inih) + +target_link_libraries( + mdm + PRIVATE + pam pthread +) + +include(GNUInstallDirs) +configure_file(mdmrc.in mdmrc) + +install( + FILES pam + RENAME mdm + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/examples/pam.d +) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/mdmrc + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/examples/mdm +) +install( + FILES mdm.png + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/mdm +) diff --git a/mdm/config.c b/mdm/config.c new file mode 100644 index 0000000..bfb3f9e --- /dev/null +++ b/mdm/config.c @@ -0,0 +1,19 @@ +#include "mdm.h" + +#include + +char* config_picture = NULL; + +static int dumper(void* user, const char* section, const char* name, const char* value) { + (void)user; + + if(strcmp(section, "MDM Config") != 0) return 1; + + if(strcmp(name, "Picture") == 0) config_picture = MDEStringDuplicate(value); + + return 1; +} + +void parse_config(void) { + ini_parse(CONFDIR "/mdm/mdmrc", dumper, NULL); +} diff --git a/mdm/login.c b/mdm/login.c new file mode 100644 index 0000000..aa22177 --- /dev/null +++ b/mdm/login.c @@ -0,0 +1,274 @@ +#include "mdm.h" + +#include +#include +#include +#include +#include +#include +#include + +MwWidget root; +MwWidget window, sesscombo, usercombo, passentry, error; + +typedef struct session { + char* key; + session_environment_t* value; +} session_t; + +session_t* sessions = NULL; +char* name_line = NULL; +char* try_exec_line = NULL; +char* exec_line = NULL; +char* desktop_names_line = NULL; + +static void add_user(const char* name, void* user) { + MwComboBoxAdd(user, -1, name); +} + +static int dumper(void* user, const char* section, const char* name, const char* value) { + if(strcmp(section, "Desktop Entry") != 0) return 1; + + if(strcmp(name, "Name") == 0) { + name_line = MDEStringDuplicate(value); + } else if(strcmp(name, "TryExec") == 0) { + try_exec_line = MDEStringDuplicate(value); + } else if(strcmp(name, "Exec") == 0) { + exec_line = MDEStringDuplicate(value); + } else if(strcmp(name, "DesktopNames") == 0) { + desktop_names_line = MDEStringDuplicate(value); + } + + return 1; +} + +static void add_session(session_type_t session_type, const char* path, int dir, int symlink, void* user) { + int m = 1; + session_environment_t* value = malloc(sizeof(session_environment_t)); + + name_line = NULL; + exec_line = NULL; + try_exec_line = NULL; + desktop_names_line = NULL; + + if(dir || symlink) return; + + ini_parse(path, dumper, user); + + if(name_line != NULL && (exec_line != NULL || try_exec_line != NULL)) { + int i; + for(i = 0; i < shlen(sessions); i++) { + if(strcmp(sessions[i].key, name_line) == 0) break; + } + + if(i == shlen(sessions)) { + MwComboBoxAdd(user, -1, name_line); + + value->run = exec_line; + value->try_run = try_exec_line; + value->session_type = session_type; + value->desktop_names = desktop_names_line; + shput(sessions, name_line, value); + + m = 0; + } + } + + if(name_line != NULL) free(name_line); + if(desktop_names_line != NULL) free(desktop_names_line); + if(m && try_exec_line != NULL) free(try_exec_line); + if(m && exec_line != NULL) free(exec_line); +} + +static void add_session_x(const char* path, int dir, int symlink, void* user) { + add_session(MDM_SESSION_TYPE_X, path, dir, symlink, user); +} +static void add_session_wayland(const char* path, int dir, int symlink, void* user) { + add_session(MDM_SESSION_TYPE_WAYLAND, path, dir, symlink, user); +} +static int conversation(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata) { + int i; + + *resp = malloc(num_msg * sizeof(struct pam_response)); + + for(i = 0; i < num_msg; i++) { + if(msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) { + const char* txt = MwGetText(passentry, MwNtext); + if(txt == NULL) txt = ""; + + resp[i]->resp_retcode = PAM_SUCCESS; + resp[i]->resp = MDEStringDuplicate(txt); + } else { + return PAM_CONV_ERR; + } + } + + return PAM_SUCCESS; +} + +static void try_login(MwWidget handle, void* user, void* client) { + const char* username; + const char* place; + struct pam_conv conv; + pam_handle_t* pam; + int err; + int err2; + int ret; + char err_str[255]; + int print_error = 0; + int i, n; + + username = MwComboBoxGet(usercombo, MwGetInteger(usercombo, MwNvalue)); + conv.conv = conversation; + conv.appdata_ptr = NULL; + err = 1; + + (void)handle; + (void)user; + (void)client; + + ret = pam_start("mdm", username, &conv, &pam); + if(ret != PAM_SUCCESS) { + place = "Error calling pam_start"; + goto cleanup; + } + + ret = pam_authenticate(pam, 0); + if(ret != PAM_SUCCESS) { + place = "Error calling pam_authenticate"; + goto cleanup; + } + + ret = pam_acct_mgmt(pam, 0); + if(ret != PAM_SUCCESS) { + place = "Error calling pam_acct_mgmt"; + goto cleanup; + } + + ret = pam_open_session(pam, 0); + if(ret != PAM_SUCCESS) { + place = "Error calling pam_open_session"; + goto cleanup; + } +cleanup: + pam_close_session(pam, 0); + + // if pam_end fails but we have another error, we care more about the error at hand + // then whether pam successfully ended. + err2 = pam_end(pam, 0); + + if(err && ret != PAM_SUCCESS) { + MwSetText(passentry, MwNtext, ""); + snprintf(err_str, 255, "%s: %s", place, pam_strerror(pam, err)); + print_error = 1; + } else if(err2) { + MwSetText(passentry, MwNtext, ""); + snprintf(err_str, 255, "Error calling pam_end: %s", pam_strerror(pam, err2)); + print_error = 1; + } + if(print_error) { + n = 0; + for(i = 0; err_str[i] != '\0' && i <= 255; i++ && n++) { + if(err_str[i] == ' ' && n >= 40) { + err_str[i] = '\n'; + n = 0; + } + } + MwSetText(error, MwNtext, err_str); + } else { + printf("Logging in as %s\n", username); + struct passwd* pwd = getpwnam(username); + const char* session = MwComboBoxGet(sesscombo, MwGetInteger(sesscombo, MwNvalue)); + + uid = pwd->pw_uid; + gid = pwd->pw_gid; + env = shget(sessions, session); + + MwDestroyWidget(root); + } +} + +void login_window(void) { + MwWidget pic, userlabel, passlabel, mainsep, sesslabel, fieldsep, shutdown, reboot, ok; + MwLLPixmap p; + void* out; + int i; + + pthread_mutex_lock(&xmutex); + + MwLibraryInit(); + + root = MwCreateWidget(NULL, "root", NULL, 0, 0, 0, 0); + + window = MwVaCreateWidget(MwWindowClass, "login", root, (x_width() - 366) / 2, (x_height() - 200) / 2, 366, 250, + MwNtitle, "login", + NULL); + p = config_picture == NULL ? NULL : MwLoadImage(window, config_picture); + pic = MwVaCreateWidget(MwImageClass, "image", window, 10, 10, 80, 137, + MwNhasBorder, 1, + NULL); + userlabel = MwVaCreateWidget(MwLabelClass, "userlabel", window, 95, 10, MwTextWidth(window, "User:"), 16, + MwNtext, "User:", + NULL); + usercombo = MwCreateWidget(MwComboBoxClass, "usercombo", window, 95, 10 + 16 + 5, 265, 18); + passlabel = MwVaCreateWidget(MwLabelClass, "passlabel", window, 95, 10 + 16 + 5 + 18 + 5, MwTextWidth(window, "Password:"), 16, + MwNtext, "Password:", + NULL); + passentry = MwVaCreateWidget(MwEntryClass, "passentry", window, 95, 10 + 16 + 5 + 18 + 5 + 16 + 5, 265, 18, + MwNhideInput, 1, + NULL); + mainsep = MwVaCreateWidget(MwSeparatorClass, "mainsep", window, 95, 10 + 16 + 5 + 18 + 5 + 16 + 5 + 18, 265, 10, + MwNorientation, MwHORIZONTAL, + NULL); + sesslabel = MwVaCreateWidget(MwLabelClass, "sesslabel", window, 95, 10 + 16 + 5 + 18 + 5 + 16 + 5 + 18 + 10, MwTextWidth(window, "Session Type:"), 16, + MwNtext, "Session Type:", + NULL); + sesscombo = MwCreateWidget(MwComboBoxClass, "sesscombo", window, 95, 10 + 16 + 5 + 18 + 5 + 16 + 5 + 18 + 10 + 16 + 5, 265, 18); + fieldsep = MwVaCreateWidget(MwSeparatorClass, "fieldsep", window, 10, 10 + 137, 351, 10, + MwNorientation, MwHORIZONTAL, + NULL); + shutdown = MwVaCreateWidget(MwButtonClass, "shutdown", window, 10, 10 + 137 + 10, 80, 18, + MwNtext, "Shut Down", + NULL); + reboot = MwVaCreateWidget(MwButtonClass, "reboot", window, 10 + 80 + 5, 10 + 137 + 10, 70, 18, + MwNtext, "Reboot", + NULL); + ok = MwVaCreateWidget(MwButtonClass, "ok", window, 366 - 10 - 60, 10 + 137 + 10, 60, 18, + MwNtext, "OK", + NULL); + error = MwVaCreateWidget(MwLabelClass, "error", window, 10, 10 + 137 + 10 + 20, 366, 48, NULL); + if(p != NULL) MwVaApply(pic, MwNpixmap, p, NULL); + + MwAddUserHandler(ok, MwNactivateHandler, try_login, NULL); + MwAddUserHandler(passentry, MwNactivateHandler, try_login, NULL); + + MDEUsersList(add_user, usercombo); + + for(i = 0; i < shlen(sessions); i++) { + free(sessions[i].value); + } + shfree(sessions); + sh_new_strdup(sessions); + shdefault(sessions, NULL); + MDEDirectoryScan(DATADIR "/xsessions", add_session_x, sesscombo); + MDEDirectoryScan("/usr/share/xsessions", add_session_x, sesscombo); + MDEDirectoryScan(DATADIR "/wayland-sessions", add_session_wayland, sesscombo); + MDEDirectoryScan("/usr/share/wayland-sessions", add_session_wayland, sesscombo); + + pthread_mutex_unlock(&xmutex); + + while(1) { + int s = 0; + + pthread_mutex_lock(&xmutex); + while(MwPending(root)) { + if((s = MwStep(root)) != 0) break; + } + pthread_mutex_unlock(&xmutex); + if(s != 0) break; + + MwTimeSleep(30); + } + + pthread_join(xthread, &out); +} diff --git a/mdm/main.c b/mdm/main.c new file mode 100644 index 0000000..455ef3f --- /dev/null +++ b/mdm/main.c @@ -0,0 +1,128 @@ +#include "mdm.h" +#include +#include +#include +#include + +int is_launch_x = 1; +int is_daemon = 1; + +gid_t gid; +uid_t uid; +session_environment_t* env; + +static void set_env_standard(struct passwd* pwd); +static void set_env_xdg(struct passwd* pwd); + +int main(int argc, char** argv) { + int i, st, exit; + char* backup = NULL; + pid_t pid; + + for(i = 1; i < argc; i++) { + if(argv[i][0] == '-') { + if(strcmp(argv[i], "-X") == 0 || strcmp(argv[i], "--no-launch-x") == 0) { + is_launch_x = 0; + } else if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--no-daemon") == 0) { + is_daemon = 0; + } else { + fprintf(stderr, "%s: bad option: %s\n", argv[0], argv[i]); + return 1; + } + } + } + + if(getuid() != 0) { + fprintf(stderr, "MDM has to be ran as root\n"); + return 1; + } + + if(is_daemon && (pid = fork()) != 0) { + FILE* f = fopen("/var/run/mdm.pid", "w"); + fprintf(f, "%d\n", pid); + fclose(f); + return 0; + } + + if(access(CONFDIR, F_OK) != 0) mkdir(CONFDIR, 0755); + if(access(CONFDIR "/mdm", F_OK) != 0) mkdir(CONFDIR "/mdm", 0755); + if(access(CONFDIR "/mdm/mdmrc", F_OK) != 0) MDEFileCopy(DATADIR "/examples/mdm/mdmrc", CONFDIR "/mdm/mdmrc"); + + parse_config(); + + if(getenv("DISPLAY") != NULL) backup = MDEStringDuplicate(getenv("DISPLAY")); + do { + setenv("DISPLAY", backup == NULL ? "" : backup, 1); + if(is_launch_x && (st = launch_x()) != 0) return st; + + if((st = init_x()) != 0) return st; + + login_window(); + + if(env->run == NULL && env->try_run == NULL) continue; + + if((pid = fork()) == 0) { + struct passwd* pwd = getpwuid(uid); + + setgid(gid); + setuid(uid); + chdir(pwd->pw_dir); + + set_env_standard(pwd); + set_env_xdg(pwd); + + if((exit = system(env->try_run)) != 0) { + exit = system(env->run); + } else { + _exit(exit); + } + } else { + waitpid(pid, NULL, 0); + } + + if(is_launch_x) { + unsetenv("DISPLAY"); + kill_x(); + } + } while(is_launch_x); + + if(backup != NULL) free(backup); +} + +void set_env_standard(struct passwd* pwd) { + setenv("HOME", pwd->pw_dir, 1); + setenv("PWD", pwd->pw_dir, 1); + setenv("USER", pwd->pw_name, 1); + setenv("SHELL", pwd->pw_shell, 1); + setenv("LOGNAME", pwd->pw_shell, 1); +} +void set_env_xdg(struct passwd* pwd) { + // this directory isn't avaliable on bsd, but we can't check for all of them. + // so just assume it's only on linux, idek if that's true but who care +#if defined(__linux__) + char runtime_dir[255]; + snprintf(runtime_dir, 255, "/run/user/%d", pwd->pw_uid); + setenv("XDG_RUNTIME_DIR", runtime_dir, 1); +#endif + + switch(env->session_type) { + case MDM_SESSION_TYPE_X: + setenv("XDG_SESSION_TYPE", "x11", 1); + break; + case MDM_SESSION_TYPE_WAYLAND: + setenv("XDG_SESSION_TYPE", "wayland", 1); + break; + } + + if(env->desktop_names) { + if(strlen(env->desktop_names) > 1) { + setenv("XDG_SESSION_DESKTOP", strtok(env->desktop_names, ";"), 1); + } + setenv("XDG_CURRENT_DESKTOP", env->desktop_names, 1); + } + + setenv("XDG_SESSION_CLASS", "user", 1); + setenv("XDG_SESSION_ID", "1", 1); + setenv("XDG_SEAT", "seat0", 1); + // setenv("XDG_VTNR", "/dev/pts/7", 1); +} diff --git a/mdm/mdm.h b/mdm/mdm.h new file mode 100644 index 0000000..25375f7 --- /dev/null +++ b/mdm/mdm.h @@ -0,0 +1,62 @@ +#ifndef __MDM_H__ +#define __MDM_H__ + +#include "config.h" + +/* Milsko */ +#include +#include + +/* External */ +#include + +/* Standard */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* login.c */ +extern MwWidget root; +typedef enum session_type { + MDM_SESSION_TYPE_X, + MDM_SESSION_TYPE_WAYLAND, +} session_type_t; +typedef struct session_environment { + char* run; + char* try_run; + session_type_t session_type; + char* desktop_names; +} session_environment_t; + +void login_window(void); + +/* main.c */ +extern gid_t gid; +extern uid_t uid; +extern session_environment_t* env; + +/* xserver.c */ +extern pthread_t xthread; +extern pthread_mutex_t xmutex; +extern Display* xdisplay; + +int launch_x(void); +int x_width(void); +int x_height(void); +int init_x(void); +void loop_x(void); +void kill_x(void); + +/* config.c */ +extern char* config_picture; + +void parse_config(void); + +#endif diff --git a/mdm/mdm.png b/mdm/mdm.png new file mode 100644 index 0000000000000000000000000000000000000000..a190f66782c7309b591fc161a2d8a9f5fbf992fb GIT binary patch literal 5033 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 diff --git a/mdm/xserver.c b/mdm/xserver.c new file mode 100644 index 0000000..e1bb954 --- /dev/null +++ b/mdm/xserver.c @@ -0,0 +1,163 @@ +#include +#define _MILSKO +#define USE_X11 +#include "mdm.h" + +#include "stb_ds.h" + +static pid_t xserver; +static int got_usr1; + +Display* xdisplay; +pthread_t xthread; +pthread_mutex_t xmutex; + +static void catch_usr1(int sig) { + (void)sig; + + got_usr1 = 1; +} + +int launch_x(void) { + got_usr1 = 0; + + signal(SIGUSR1, catch_usr1); + + if((xserver = fork()) == 0) { + signal(SIGUSR1, SIG_IGN); + execlp("X", "X", ":0", NULL); + _exit(-1); + } else { + while(!got_usr1) { + if(waitpid(xserver, NULL, WNOHANG) != 0) { + fprintf(stderr, "server died. what happened?\n"); + return 1; + } + usleep(1000); + } + } + + setenv("DISPLAY", ":0", 1); + + return 0; +} + +static int wm_detected = 0; +static int wm_detect(Display* disp, XErrorEvent* ev) { + (void)disp; + (void)ev; + + wm_detected = 1; +} + +static void* x11_thread_routine(void* arg) { + loop_x(); + XCloseDisplay(xdisplay); +} + +int init_x(void) { + XColor bg; + void* old; + + xdisplay = XOpenDisplay(NULL); + + bg.red = 0x1c * 256; + bg.green = 0x45 * 256; + bg.blue = 0x73 * 256; + XAllocColor(xdisplay, DefaultColormap(xdisplay, DefaultScreen(xdisplay)), &bg); + + XSetWindowBackground(xdisplay, DefaultRootWindow(xdisplay), bg.pixel); + XClearWindow(xdisplay, DefaultRootWindow(xdisplay)); + XFlush(xdisplay); + + old = XSetErrorHandler(wm_detect); + XSelectInput(xdisplay, DefaultRootWindow(xdisplay), SubstructureRedirectMask); + XSync(xdisplay, False); + XSetErrorHandler(old); + + if(wm_detected) { + fprintf(stderr, "WM or something seem to be running\n"); + return 1; + } + + pthread_mutex_init(&xmutex, NULL); + + pthread_create(&xthread, NULL, x11_thread_routine, NULL); + + return 0; +} + +int x_width(void) { + return DisplayWidth(xdisplay, DefaultScreen(xdisplay)); +} + +int x_height(void) { + return DisplayHeight(xdisplay, DefaultScreen(xdisplay)); +} + +typedef struct window { + MwWidget frame; + Window client; +} window_t; + +void loop_x(void) { + XEvent ev; + window_t* frames = NULL; + + while(1) { + XNextEvent(xdisplay, &ev); + if(ev.type == MapRequest) { + XWindowAttributes xwa; + window_t w; + int i; + + pthread_mutex_lock(&xmutex); + for(i = 0; i < arrlen(frames); i++) { + if(frames[i].frame->lowlevel->x11.window == ev.xmaprequest.window) { + XReparentWindow(xdisplay, frames[i].client, frames[i].frame->lowlevel->x11.window, MwDefaultBorderWidth(root), MwDefaultBorderWidth(root)); + XMapWindow(xdisplay, ev.xmaprequest.window); + XMapWindow(xdisplay, frames[i].client); + break; + } + } + if(i != arrlen(frames)) { + pthread_mutex_unlock(&xmutex); + continue; + } + + XGetWindowAttributes(xdisplay, ev.xmaprequest.window, &xwa); + + w.client = ev.xmaprequest.window; + w.frame = MwVaCreateWidget(MwWindowClass, "frame", root, xwa.x - MwDefaultBorderWidth(root), xwa.y - MwDefaultBorderWidth(root), xwa.width + MwDefaultBorderWidth(root) * 2, xwa.height + MwDefaultBorderWidth(root) * 2, + MwNhasBorder, 1, + MwNinverted, 0, + NULL); + + XSelectInput(xdisplay, w.client, StructureNotifyMask); + + arrput(frames, w); + pthread_mutex_unlock(&xmutex); + } else if(ev.type == UnmapNotify) { + int i; + int c = 0; + + pthread_mutex_lock(&xmutex); + for(i = 0; i < arrlen(frames); i++) { + if(frames[i].client == ev.xunmap.window) { + MwDestroyWidget(frames[i].frame); + arrdel(frames, i); + c = 1; + break; + } + } + pthread_mutex_unlock(&xmutex); + + if(c) break; + } + } +} + +void kill_x(void) { + kill(xserver, SIGINT); + waitpid(xserver, NULL, 0); +} diff --git a/milkwm/CMakeLists.txt b/milkwm/CMakeLists.txt new file mode 100644 index 0000000..1c6db46 --- /dev/null +++ b/milkwm/CMakeLists.txt @@ -0,0 +1,2 @@ +include(MDEBase) +setup_project(milkwm ${CMAKE_INSTALL_BINDIR}) diff --git a/milkwm/main.c b/milkwm/main.c new file mode 100644 index 0000000..237c8ce --- /dev/null +++ b/milkwm/main.c @@ -0,0 +1 @@ +int main() {} diff --git a/mpanel/CMakeLists.txt b/mpanel/CMakeLists.txt new file mode 100644 index 0000000..8e1c41b --- /dev/null +++ b/mpanel/CMakeLists.txt @@ -0,0 +1,10 @@ +include(MDEBase) +setup_project(mpanel ${CMAKE_INSTALL_BINDIR}) + +if(${CMAKE_SYSTEM_NAME} STREQUAL Linux) + target_link_libraries( + mpanel + PRIVATE + dl + ) +endif() diff --git a/mpanel/main.c b/mpanel/main.c new file mode 100644 index 0000000..237c8ce --- /dev/null +++ b/mpanel/main.c @@ -0,0 +1 @@ +int main() {}