ok
This commit is contained in:
commit
5634b5d5d7
17 changed files with 731 additions and 0 deletions
8
CMakeLists.txt
Normal file
8
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
cmake_minimum_required(VERSION 3.25)
|
||||
project(
|
||||
mdebase
|
||||
)
|
||||
|
||||
add_subdirectory(mdm)
|
||||
add_subdirectory(milkwm)
|
||||
add_subdirectory(mpanel)
|
||||
24
LICENSE
Normal file
24
LICENSE
Normal file
|
|
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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.
|
||||
1
README.md
Normal file
1
README.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Base package for MDE
|
||||
29
mdm/CMakeLists.txt
Normal file
29
mdm/CMakeLists.txt
Normal file
|
|
@ -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
|
||||
)
|
||||
19
mdm/config.c
Normal file
19
mdm/config.c
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include "mdm.h"
|
||||
|
||||
#include <ini.h>
|
||||
|
||||
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);
|
||||
}
|
||||
274
mdm/login.c
Normal file
274
mdm/login.c
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
#include "mdm.h"
|
||||
|
||||
#include <ini.h>
|
||||
#include <sched.h>
|
||||
#include <security/_pam_types.h>
|
||||
#include <security/pam_appl.h>
|
||||
#include <stb_ds.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
}
|
||||
128
mdm/main.c
Normal file
128
mdm/main.c
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
#include "mdm.h"
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
}
|
||||
62
mdm/mdm.h
Normal file
62
mdm/mdm.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#ifndef __MDM_H__
|
||||
#define __MDM_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* Milsko */
|
||||
#include <MDE/Foundation.h>
|
||||
#include <Mw/Milsko.h>
|
||||
|
||||
/* External */
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
/* Standard */
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <setjmp.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* 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
|
||||
BIN
mdm/mdm.png
Normal file
BIN
mdm/mdm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
2
mdm/mdmrc.in
Normal file
2
mdm/mdmrc.in
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
[MDM Config]
|
||||
Picture=@CMAKE_INSTALL_FULL_DATAROOTDIR@/mdm/mdm.png
|
||||
5
mdm/pam
Normal file
5
mdm/pam
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
auth required pam_unix.so
|
||||
auth required pam_nologin.so
|
||||
account required pam_unix.so
|
||||
password required pam_unix.so
|
||||
session required pam_unix.so
|
||||
2
mdm/stb_ds.c
Normal file
2
mdm/stb_ds.c
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#define STB_DS_IMPLEMENTATION
|
||||
#include <stb_ds.h>
|
||||
163
mdm/xserver.c
Normal file
163
mdm/xserver.c
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
#include <stdlib.h>
|
||||
#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);
|
||||
}
|
||||
2
milkwm/CMakeLists.txt
Normal file
2
milkwm/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
include(MDEBase)
|
||||
setup_project(milkwm ${CMAKE_INSTALL_BINDIR})
|
||||
1
milkwm/main.c
Normal file
1
milkwm/main.c
Normal file
|
|
@ -0,0 +1 @@
|
|||
int main() {}
|
||||
10
mpanel/CMakeLists.txt
Normal file
10
mpanel/CMakeLists.txt
Normal file
|
|
@ -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()
|
||||
1
mpanel/main.c
Normal file
1
mpanel/main.c
Normal file
|
|
@ -0,0 +1 @@
|
|||
int main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue