/* * DWN - Desktop Window Manager * Main entry point and event loop */ #include "dwn.h" #include "config.h" #include "atoms.h" #include "client.h" #include "workspace.h" #include "layout.h" #include "decorations.h" #include "panel.h" #include "keys.h" #include "notifications.h" #include "systray.h" #include "news.h" #include "applauncher.h" #include "ai.h" #include "util.h" #include #include #include #include #include #include #include #include #include /* Global state instance */ DWNState *dwn = NULL; static DWNState dwn_state; /* Signal handling */ static volatile sig_atomic_t received_signal = 0; static void signal_handler(int sig) { received_signal = sig; } /* Crash signal handler - flush logs before dying */ static void crash_signal_handler(int sig) { /* Flush logs synchronously before crashing */ log_flush(); /* Re-raise the signal with default handler to get proper crash behavior */ signal(sig, SIG_DFL); raise(sig); } /* X11 error handlers */ static int last_x_error = 0; /* Track last error for checking */ static int x_error_handler(Display *dpy, XErrorEvent *ev) { char error_text[256]; XGetErrorText(dpy, ev->error_code, error_text, sizeof(error_text)); /* Store last error code for functions that want to check */ last_x_error = ev->error_code; /* Write all X errors to crash log for debugging */ FILE *crash = fopen("/tmp/dwn_crash.log", "a"); if (crash) { fprintf(crash, "[X_ERROR] code=%d request=%d resource=%lu: %s\n", ev->error_code, ev->request_code, ev->resourceid, error_text); fflush(crash); fsync(fileno(crash)); fclose(crash); } /* BadWindow errors are common and recoverable - just log and continue */ if (ev->error_code == BadWindow) { LOG_DEBUG("X11 BadWindow error (request %d, resource %lu) - window was destroyed", ev->request_code, ev->resourceid); return 0; /* Continue - this is not fatal */ } /* BadMatch, BadValue, BadDrawable are also often recoverable */ if (ev->error_code == BadMatch || ev->error_code == BadValue || ev->error_code == BadDrawable || ev->error_code == BadPixmap) { LOG_WARN("X11 error: %s (request %d, resource %lu) - continuing", error_text, ev->request_code, ev->resourceid); return 0; /* Continue - these are recoverable */ } /* Log other errors but don't crash */ LOG_WARN("X11 error: %s (request %d, resource %lu)", error_text, ev->request_code, ev->resourceid); return 0; } static int x_io_error_handler(Display *dpy) { (void)dpy; /* Write directly to crash log - do not rely on async logging */ FILE *crash = fopen("/tmp/dwn_crash.log", "a"); if (crash) { fprintf(crash, "[IO_ERROR] Fatal X11 I/O error - X server connection lost\n"); fflush(crash); fsync(fileno(crash)); fclose(crash); } fprintf(stderr, "[IO_ERROR] Fatal X11 I/O error - X server connection lost\n"); fflush(stderr); /* I/O errors mean the X server connection is broken - we must exit */ /* But first, try to flush any pending logs */ log_flush(); LOG_ERROR("Fatal X11 I/O error - X server connection lost"); log_flush(); _exit(EXIT_FAILURE); /* Use _exit to avoid cleanup that might touch X */ return 0; /* Never reached */ } /* Check if another WM is running */ static int wm_detected = 0; static int wm_detect_error_handler(Display *dpy, XErrorEvent *ev) { (void)dpy; (void)ev; wm_detected = 1; return 0; } static bool check_other_wm(void) { XSetErrorHandler(wm_detect_error_handler); XSelectInput(dwn->display, dwn->root, SubstructureRedirectMask | SubstructureNotifyMask); XSync(dwn->display, False); XSetErrorHandler(x_error_handler); return wm_detected != 0; } /* Initialize multi-monitor support */ static void init_monitors(void) { if (!XineramaIsActive(dwn->display)) { /* Single monitor */ dwn->monitors[0].x = 0; dwn->monitors[0].y = 0; dwn->monitors[0].width = dwn->screen_width; dwn->monitors[0].height = dwn->screen_height; dwn->monitors[0].index = 0; dwn->monitors[0].primary = true; dwn->monitor_count = 1; return; } int num_screens; XineramaScreenInfo *info = XineramaQueryScreens(dwn->display, &num_screens); if (info == NULL || num_screens == 0) { dwn->monitors[0].x = 0; dwn->monitors[0].y = 0; dwn->monitors[0].width = dwn->screen_width; dwn->monitors[0].height = dwn->screen_height; dwn->monitors[0].index = 0; dwn->monitors[0].primary = true; dwn->monitor_count = 1; return; } dwn->monitor_count = (num_screens > MAX_MONITORS) ? MAX_MONITORS : num_screens; for (int i = 0; i < dwn->monitor_count; i++) { dwn->monitors[i].x = info[i].x_org; dwn->monitors[i].y = info[i].y_org; dwn->monitors[i].width = info[i].width; dwn->monitors[i].height = info[i].height; dwn->monitors[i].index = i; dwn->monitors[i].primary = (i == 0); } XFree(info); LOG_INFO("Detected %d monitor(s)", dwn->monitor_count); } /* Scan for existing windows */ static void scan_existing_windows(void) { Window root_return, parent_return; Window *children; unsigned int num_children; if (XQueryTree(dwn->display, dwn->root, &root_return, &parent_return, &children, &num_children)) { for (unsigned int i = 0; i < num_children; i++) { XWindowAttributes wa; if (XGetWindowAttributes(dwn->display, children[i], &wa)) { if (wa.map_state == IsViewable && wa.override_redirect == False) { client_manage(children[i]); } } } if (children != NULL) { XFree(children); } } LOG_INFO("Scanned %d existing window(s)", client_count()); } /* ========== Event handlers ========== */ static void handle_map_request(XMapRequestEvent *ev) { /* Defensive: validate pointers */ if (ev == NULL || dwn == NULL || dwn->display == NULL) { return; } if (ev->window == None) { LOG_WARN("handle_map_request: received invalid window (None)"); return; } XWindowAttributes wa; if (!XGetWindowAttributes(dwn->display, ev->window, &wa)) { LOG_WARN("handle_map_request: XGetWindowAttributes failed for window %lu", ev->window); return; } if (wa.override_redirect) { return; } client_manage(ev->window); } static void handle_unmap_notify(XUnmapEvent *ev) { /* Defensive: validate pointers */ if (ev == NULL || dwn == NULL) { return; } Client *c = client_find_by_window(ev->window); if (c == NULL) { return; } /* Ignore synthetic events */ if (ev->send_event) { return; } /* Don't unmanage windows that are intentionally hidden: * - Windows on a different workspace (hidden during workspace switch) * - Minimized windows * These windows are still managed, just not visible */ if (c->workspace != (unsigned int)dwn->current_workspace) { return; } if (c->flags & CLIENT_MINIMIZED) { return; } /* Window was actually closed/withdrawn - unmanage it */ client_unmanage(c); } static void handle_destroy_notify(XDestroyWindowEvent *ev) { /* Defensive: validate pointers */ if (ev == NULL) { return; } Client *c = client_find_by_window(ev->window); if (c != NULL) { client_unmanage(c); } } static void handle_configure_request(XConfigureRequestEvent *ev) { /* Defensive: validate pointers */ if (ev == NULL || dwn == NULL || dwn->display == NULL) { return; } Client *c = client_find_by_window(ev->window); if (c != NULL) { /* Managed window - respect some requests for floating windows */ if (client_is_floating(c) || client_is_fullscreen(c)) { if (ev->value_mask & CWX) c->x = ev->x; if (ev->value_mask & CWY) c->y = ev->y; if (ev->value_mask & CWWidth) c->width = ev->width; if (ev->value_mask & CWHeight) c->height = ev->height; client_configure(c); } else { /* Just send configure notify with current geometry */ client_configure(c); } } else { /* Unmanaged window - pass through */ XWindowChanges wc; wc.x = ev->x; wc.y = ev->y; wc.width = ev->width; wc.height = ev->height; wc.border_width = ev->border_width; wc.sibling = ev->above; wc.stack_mode = ev->detail; XConfigureWindow(dwn->display, ev->window, ev->value_mask, &wc); } } static void handle_property_notify(XPropertyEvent *ev) { /* Defensive: validate pointers */ if (ev == NULL || dwn == NULL) { return; } Client *c = client_find_by_window(ev->window); if (c == NULL) { return; } if (ev->atom == icccm.WM_NAME || ev->atom == ewmh.NET_WM_NAME) { client_update_title(c); panel_render_all(); } } static void handle_expose(XExposeEvent *ev) { /* Defensive: validate pointers */ if (ev == NULL || dwn == NULL) { return; } /* Only handle final expose in a sequence */ if (ev->count != 0) { return; } /* Check if it's a panel */ if (dwn->top_panel != NULL && ev->window == dwn->top_panel->window) { panel_render(dwn->top_panel); return; } if (dwn->bottom_panel != NULL && ev->window == dwn->bottom_panel->window) { panel_render(dwn->bottom_panel); return; } /* Check if it's a notification */ Notification *notif = notification_find_by_window(ev->window); if (notif != NULL) { notification_render(notif); return; } /* Check if it's a frame */ Client *c = client_find_by_frame(ev->window); if (c != NULL) { Workspace *ws = workspace_get(c->workspace); bool focused = (ws != NULL && ws->focused == c); decorations_render(c, focused); } } static void handle_enter_notify(XCrossingEvent *ev) { /* Defensive: validate all pointers */ if (ev == NULL || dwn == NULL || dwn->config == NULL) { return; } if (dwn->config->focus_mode != FOCUS_FOLLOW) { return; } /* Focus on enter for follow-mouse mode */ Client *c = client_find_by_frame(ev->window); if (c == NULL) { c = client_find_by_window(ev->window); } if (c != NULL && c->workspace == (unsigned int)dwn->current_workspace) { client_focus(c); } } static void handle_button_press(XButtonEvent *ev) { /* Defensive: validate all pointers */ if (ev == NULL || dwn == NULL || dwn->display == NULL) { return; } /* Check volume slider first */ if (volume_slider != NULL && volume_slider->visible) { if (ev->window == volume_slider->window) { volume_slider_handle_click(volume_slider, ev->x, ev->y); return; } else { /* Clicked outside slider - close it */ volume_slider_hide(volume_slider); } } /* Check WiFi dropdown menu */ if (wifi_menu != NULL && wifi_menu->visible) { if (ev->window == wifi_menu->window) { dropdown_handle_click(wifi_menu, ev->x, ev->y); return; } else { /* Clicked outside dropdown - close it */ dropdown_hide(wifi_menu); } } /* Check notifications first - clicking dismisses them */ Notification *notif = notification_find_by_window(ev->window); if (notif != NULL) { notification_close(notif->id); return; } /* Check panels first */ if (dwn->top_panel != NULL && ev->window == dwn->top_panel->window) { panel_handle_click(dwn->top_panel, ev->x, ev->y, ev->button); return; } if (dwn->bottom_panel != NULL && ev->window == dwn->bottom_panel->window) { panel_handle_click(dwn->bottom_panel, ev->x, ev->y, ev->button); return; } /* Find client */ Client *c = client_find_by_frame(ev->window); bool is_client_window = false; if (c == NULL) { c = client_find_by_window(ev->window); is_client_window = (c != NULL); } if (c == NULL) { return; } /* Focus on click */ client_focus(c); /* If click was on client window content, replay the event to the application */ if (is_client_window) { XAllowEvents(dwn->display, ReplayPointer, ev->time); return; } /* Check for button clicks in decorations */ if (c->frame != None && ev->window == c->frame) { ButtonType btn = decorations_hit_test_button(c, ev->x, ev->y); if (btn != BUTTON_COUNT) { decorations_button_press(c, btn); return; } /* Check for title bar drag */ if (decorations_hit_test_title_bar(c, ev->x, ev->y)) { if (ev->button == 1) { /* Start move */ dwn->drag_client = c; dwn->drag_start_x = ev->x_root; dwn->drag_start_y = ev->y_root; dwn->drag_orig_x = c->x; dwn->drag_orig_y = c->y; dwn->resizing = false; XGrabPointer(dwn->display, c->frame, True, PointerMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); } return; } /* Check for resize */ int direction; if (decorations_hit_test_resize_area(c, ev->x, ev->y, &direction)) { if (ev->button == 1) { dwn->drag_client = c; dwn->drag_start_x = ev->x_root; dwn->drag_start_y = ev->y_root; dwn->drag_orig_x = c->x; dwn->drag_orig_y = c->y; dwn->drag_orig_w = c->width; dwn->drag_orig_h = c->height; dwn->resizing = true; XGrabPointer(dwn->display, c->frame, True, PointerMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); } } } } static void handle_button_release(XButtonEvent *ev) { /* Defensive: validate pointers */ if (dwn == NULL || dwn->display == NULL) { return; } /* Handle volume slider release */ if (volume_slider != NULL && volume_slider->visible && volume_slider->dragging) { volume_slider_handle_release(volume_slider); } (void)ev; if (dwn->drag_client != NULL) { XUngrabPointer(dwn->display, CurrentTime); dwn->drag_client = NULL; } } static void handle_motion_notify(XMotionEvent *ev) { /* Defensive: validate pointers */ if (ev == NULL || dwn == NULL || dwn->display == NULL) { return; } /* Check volume slider drag */ if (volume_slider != NULL && volume_slider->visible && ev->window == volume_slider->window) { volume_slider_handle_motion(volume_slider, ev->x, ev->y); return; } /* Check WiFi dropdown hover */ if (wifi_menu != NULL && wifi_menu->visible && ev->window == wifi_menu->window) { dropdown_handle_motion(wifi_menu, ev->x, ev->y); return; } if (dwn->drag_client == NULL) { return; } Client *c = dwn->drag_client; if (c == NULL) { dwn->drag_client = NULL; /* Reset invalid drag state */ return; } int dx = ev->x_root - dwn->drag_start_x; int dy = ev->y_root - dwn->drag_start_y; if (dwn->resizing) { int new_w = dwn->drag_orig_w + dx; int new_h = dwn->drag_orig_h + dy; if (new_w < 50) new_w = 50; if (new_h < 50) new_h = 50; client_resize(c, new_w, new_h); } else { client_move(c, dwn->drag_orig_x + dx, dwn->drag_orig_y + dy); } } static void handle_client_message(XClientMessageEvent *ev) { /* Defensive: validate pointers */ if (ev == NULL || dwn == NULL || dwn->display == NULL) { return; } Client *c = client_find_by_window(ev->window); if (ev->message_type == ewmh.NET_ACTIVE_WINDOW) { if (c != NULL) { if (c->workspace != (unsigned int)dwn->current_workspace) { workspace_switch(c->workspace); } client_focus(c); } } else if (ev->message_type == ewmh.NET_CLOSE_WINDOW) { if (c != NULL) { client_close(c); } } else if (ev->message_type == ewmh.NET_WM_STATE) { if (c != NULL) { Atom action = ev->data.l[0]; Atom prop1 = ev->data.l[1]; Atom prop2 = ev->data.l[2]; bool set = (action == 1); bool toggle = (action == 2); if (prop1 == ewmh.NET_WM_STATE_FULLSCREEN || prop2 == ewmh.NET_WM_STATE_FULLSCREEN) { if (toggle) { client_toggle_fullscreen(c); } else { client_set_fullscreen(c, set); } } } } else if (ev->message_type == ewmh.NET_CURRENT_DESKTOP) { int desktop = ev->data.l[0]; if (desktop >= 0 && desktop < MAX_WORKSPACES) { workspace_switch(desktop); } } } /* Sync log - disabled in production (enable for debugging crashes) */ #if 0 static FILE *crash_log_file = NULL; static void sync_log(const char *msg) { if (crash_log_file == NULL) { crash_log_file = fopen("/tmp/dwn_crash.log", "a"); } fprintf(stderr, "[SYNC] %s\n", msg); fflush(stderr); if (crash_log_file != NULL) { fprintf(crash_log_file, "[SYNC] %s\n", msg); fflush(crash_log_file); fsync(fileno(crash_log_file)); } } #endif /* Main event dispatcher */ void dwn_handle_event(XEvent *ev) { /* Defensive: validate event pointer */ if (ev == NULL) { LOG_WARN("dwn_handle_event: received NULL event"); return; } /* Defensive: validate global state */ if (dwn == NULL || dwn->display == NULL) { LOG_ERROR("dwn_handle_event: dwn or display is NULL"); return; } switch (ev->type) { case MapRequest: handle_map_request(&ev->xmaprequest); break; case UnmapNotify: handle_unmap_notify(&ev->xunmap); break; case DestroyNotify: handle_destroy_notify(&ev->xdestroywindow); break; case ConfigureRequest: handle_configure_request(&ev->xconfigurerequest); break; case PropertyNotify: handle_property_notify(&ev->xproperty); break; case Expose: handle_expose(&ev->xexpose); break; case EnterNotify: handle_enter_notify(&ev->xcrossing); break; case ButtonPress: handle_button_press(&ev->xbutton); break; case ButtonRelease: handle_button_release(&ev->xbutton); break; case MotionNotify: handle_motion_notify(&ev->xmotion); break; case KeyPress: keys_handle_press(&ev->xkey); break; case KeyRelease: keys_handle_release(&ev->xkey); break; case ClientMessage: handle_client_message(&ev->xclient); break; default: break; } } /* ========== Core functions ========== */ int dwn_init(void) { /* Initialize global state */ dwn = &dwn_state; memset(dwn, 0, sizeof(DWNState)); /* Open display */ dwn->display = XOpenDisplay(NULL); if (dwn->display == NULL) { fprintf(stderr, "Cannot open X display\n"); return -1; } dwn->screen = DefaultScreen(dwn->display); dwn->root = RootWindow(dwn->display, dwn->screen); dwn->screen_width = DisplayWidth(dwn->display, dwn->screen); dwn->screen_height = DisplayHeight(dwn->display, dwn->screen); dwn->colormap = DefaultColormap(dwn->display, dwn->screen); /* Set error handlers */ XSetErrorHandler(x_error_handler); XSetIOErrorHandler(x_io_error_handler); /* Check for other WM */ if (check_other_wm()) { fprintf(stderr, "Another window manager is already running\n"); XCloseDisplay(dwn->display); return -1; } /* Initialize logging */ log_init("~/.local/share/dwn/dwn.log"); LOG_INFO("DWN %s starting", DWN_VERSION); /* Load configuration */ dwn->config = config_create(); config_load(dwn->config, NULL); /* Initialize colors (after display is open) */ extern void config_init_colors(Config *cfg); config_init_colors(dwn->config); /* Load font */ dwn->font = XLoadQueryFont(dwn->display, dwn->config->font_name); if (dwn->font == NULL) { dwn->font = XLoadQueryFont(dwn->display, "fixed"); } /* Load Xft font for UTF-8 support */ dwn->xft_font = XftFontOpenName(dwn->display, dwn->screen, "monospace:size=10:antialias=true"); if (dwn->xft_font == NULL) { dwn->xft_font = XftFontOpenName(dwn->display, dwn->screen, "fixed:size=10"); } if (dwn->xft_font != NULL) { LOG_INFO("Loaded Xft font for UTF-8 support"); } /* Create GC */ XGCValues gcv; gcv.foreground = dwn->config->colors.panel_fg; gcv.background = dwn->config->colors.panel_bg; gcv.font = dwn->font ? dwn->font->fid : None; dwn->gc = XCreateGC(dwn->display, dwn->root, GCForeground | GCBackground | (dwn->font ? GCFont : 0), &gcv); /* Initialize atoms */ atoms_init(dwn->display); /* Initialize monitors */ init_monitors(); /* Initialize workspaces */ workspace_init(); /* Initialize decorations */ decorations_init(); /* Initialize panels */ panels_init(); /* Initialize system tray (WiFi, Audio indicators) */ systray_init(); /* Initialize news ticker */ news_init(); /* Initialize app launcher */ applauncher_init(); /* Initialize keyboard shortcuts */ keys_init(); /* Initialize D-Bus notifications */ notifications_init(); /* Initialize AI */ ai_init(); /* Setup EWMH */ atoms_setup_ewmh(); /* Select events on root window */ XSelectInput(dwn->display, dwn->root, SubstructureRedirectMask | SubstructureNotifyMask | StructureNotifyMask | PropertyChangeMask | ButtonPressMask | PointerMotionMask); /* Set cursor */ Cursor cursor = XCreateFontCursor(dwn->display, XC_left_ptr); XDefineCursor(dwn->display, dwn->root, cursor); /* Scan existing windows */ scan_existing_windows(); /* Arrange initial workspace */ workspace_arrange_current(); /* Render panels */ panel_render_all(); dwn->running = true; LOG_INFO("DWN initialized successfully"); return 0; } void dwn_cleanup(void) { LOG_INFO("DWN shutting down"); /* Cleanup subsystems */ ai_cleanup(); notifications_cleanup(); news_cleanup(); applauncher_cleanup(); keys_cleanup(); systray_cleanup(); panels_cleanup(); decorations_cleanup(); workspace_cleanup(); /* Unmanage all clients */ while (dwn->client_list != NULL) { client_unmanage(dwn->client_list); } /* Free resources */ if (dwn->gc != None) { XFreeGC(dwn->display, dwn->gc); } if (dwn->font != NULL) { XFreeFont(dwn->display, dwn->font); } if (dwn->xft_font != NULL) { XftFontClose(dwn->display, dwn->xft_font); } if (dwn->config != NULL) { config_destroy(dwn->config); } /* Close display */ if (dwn->display != NULL) { XCloseDisplay(dwn->display); } log_close(); dwn = NULL; } void dwn_run(void) { int x11_fd = ConnectionNumber(dwn->display); int dbus_fd = -1; if (dbus_conn != NULL) { dbus_connection_get_unix_fd(dbus_conn, &dbus_fd); } long last_clock_update = 0; long last_news_update = 0; while (dwn->running && received_signal == 0) { /* Handle pending X events */ while (XPending(dwn->display)) { XEvent ev; XNextEvent(dwn->display, &ev); dwn_handle_event(&ev); } /* Process D-Bus messages */ notifications_process_messages(); /* Process AI requests */ ai_process_pending(); /* Process Exa requests */ exa_process_pending(); /* Update notifications (check for expired) */ notifications_update(); long now = get_time_ms(); /* Update news ticker frequently for smooth scrolling (~60fps) */ if (now - last_news_update >= 16) { news_update(); panel_render_all(); last_news_update = now; } /* Update clock and system stats every second */ if (now - last_clock_update >= 1000) { panel_update_clock(); panel_update_system_stats(); systray_update(); last_clock_update = now; } /* Wait for events with timeout - short for smooth animation */ fd_set fds; FD_ZERO(&fds); FD_SET(x11_fd, &fds); if (dbus_fd >= 0) { FD_SET(dbus_fd, &fds); } struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 16000; /* ~16ms for 60fps smooth scrolling */ int max_fd = x11_fd; if (dbus_fd > max_fd) max_fd = dbus_fd; select(max_fd + 1, &fds, NULL, NULL, &tv); } /* Handle signal */ if (received_signal != 0) { LOG_INFO("Received signal %d", received_signal); } } void dwn_quit(void) { dwn->running = false; } /* ========== Main ========== */ static void print_usage(const char *program) { printf("Usage: %s [OPTIONS]\n", program); printf("\n"); printf("Options:\n"); printf(" -h, --help Show this help message\n"); printf(" -v, --version Show version information\n"); printf(" -c CONFIG Use specified config file\n"); printf("\n"); printf("Environment variables:\n"); printf(" OPENROUTER_API_KEY Enable AI features\n"); printf(" EXA_API_KEY Enable semantic search\n"); } static void print_version(void) { printf("DWN - Desktop Window Manager %s\n", DWN_VERSION); printf("AI-enhanced X11 window manager\n"); } int main(int argc, char *argv[]) { /* Parse arguments */ for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { print_usage(argv[0]); return 0; } if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) { print_version(); return 0; } } /* Setup signal handlers */ signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); signal(SIGHUP, signal_handler); /* Setup crash signal handlers to flush logs before dying */ signal(SIGSEGV, crash_signal_handler); signal(SIGABRT, crash_signal_handler); signal(SIGFPE, crash_signal_handler); signal(SIGBUS, crash_signal_handler); signal(SIGILL, crash_signal_handler); /* Initialize */ if (dwn_init() != 0) { return EXIT_FAILURE; } /* Run event loop */ dwn_run(); /* Cleanup */ dwn_cleanup(); return EXIT_SUCCESS; }