Files
zswm/src/main.c

802 lines
24 KiB
C

#include <cairo-xcb.h>
#include <cairo.h>
#include <glib.h>
#include <glibconfig.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wordexp.h>
#include "action.h"
#include "config.h"
#include "event-adapter.h"
#include "layout.h"
#include "renderer.h"
#include "types.h"
#include "utils.h"
#include "xcb.h"
static void init_monitors(void);
static char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index);
static void init_wallpaper(void);
static gboolean update_wallpaper(gpointer user_data);
static void set_wallpaper_by_index(uint32_t index);
static wallpaper_config_t *parse_wallpaper_config(void);
static void free_wallpaper_config(wallpaper_config_t *wallpaper_config);
static void init_color_set(void);
static void parse_color(const char *hex, color_t *color);
static void init_monitor_bar(void);
static void get_xresource_config(void);
static void draw_all_monitor_bars(void);
static void draw_monitor_bar(monitor_t *monitor);
static void init_xcb_event_loop(void);
static void xcb_event_handler(generic_event_t *event, void *user_data);
static void key_press(key_press_event_t *event);
static void configure_request(configure_request_event_t *event);
static void map_request(map_request_event_t *event);
static void unmap_notify(unmap_notify_event_t *event);
static void manage_window(xcb_window_t window);
static void unmanage_client(client_t *client);
static void update_client_name(client_t *client);
static void apply_rules(client_t *client);
static uint32_t get_tags_mask_of_monitor(monitor_t *monitor);
static void attach_client(client_t *client);
static void detach_client(client_t *client);
static void attach_stack_client(client_t *client);
static void detach_stack_client(client_t *client);
static void arrange(monitor_t *monitor);
static void show_hide_client(client_t *client);
static void restack(monitor_t *monitor);
static void focus(client_t *client);
static void apply_monitor_layout(monitor_t *monitor);
static client_t *get_client_of_window(xcb_window_t window);
static gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition,
gpointer userdata);
static void cleanup(void);
static monitor_t *monitors = NULL;
static monitor_t *current_monitor = NULL;
static wallpaper_config_t *wallpaper_config = NULL;
static color_set_t *color_set = NULL;
static GMainLoop *loop = NULL;
static event_adapter_t *adapter = NULL;
static char *font_family = NULL;
static uint32_t font_size = default_font_size;
static uint32_t dpi = dpi_fallback;
static uint32_t bar_y_pad = bar_y_padding;
static uint32_t tag_x_pad = tag_x_padding;
static uint32_t bar_height = 0;
static uint32_t border_px = border_width;
static bool need_restart = false;
void spawn(const user_action_arg_t *arg) {
g_spawn_command_line_async(arg->ptr, NULL);
}
void quit(const user_action_arg_t *arg) {
need_restart = arg->b;
g_main_loop_quit(loop);
}
void select_tag(const user_action_arg_t *arg) {
uint32_t tags_mask = get_tags_mask_of_monitor(current_monitor);
uint32_t target_tag = (1 << arg->ui) & tags_mask;
if (!target_tag || current_monitor->selected_tags == target_tag) return;
current_monitor->selected_tags = target_tag;
focus(NULL);
arrange(current_monitor);
}
/* 调试函数,开发完成后删除 */
static void print_monitor_list_info(monitor_t *monitor_list) {
printf("========================= monitor info =========================\n");
for (monitor_t *m = monitor_list; m; m = m->next) {
printf("========== mon[%u]:\n", m->index);
printf("x: %d, y: %d, width: %u, height: %u\n", m->monitor_x, m->monitor_y,
m->monitor_width, m->monitor_height);
printf("mon[%u] tags: ", m->index);
for (int i = 0; m->tags[i]; i++) {
printf("%s%s", i > 0 ? ", " : "", m->tags[i]);
}
printf("\n");
}
printf("======================= monitor info end =======================\n");
}
static void print_color(const char *prompt, const color_t *color) {
const char *p = strlen(prompt) ? " " : "";
printf("%s%srgba: #%08x, argb: #%08x\n", prompt, p, color->rgba, color->argb);
}
static void print_color_set(color_set_t *set) {
print_color("== bar bg:", &set->bar_bg);
print_color("== tag bg:", &set->tag_bg);
print_color("== active tag bg:", &set->active_tag_bg);
print_color("== tag color:", &set->tag_color);
print_color("== active tag color:", &set->active_tag_color);
print_color("== layout bg:", &set->layout_color);
print_color("== client name color:", &set->client_name_color);
print_color("== active client name color:", &set->active_client_name_color);
print_color("== status color:", &set->status_color);
print_color("== border color:", &set->border_color);
print_color("== active border color:", &set->active_border_color);
}
static void print_wallpaper_config(wallpaper_config_t *config) {
if (!config) {
printf("no wallpaper\n");
return;
}
printf("wallpaper count: %u\n", config->count);
for (uint32_t i = 0; i < config->count; i++) {
printf("wallpaper[%02u]: %s\n", i, config->path_list[i]);
}
}
static void print_window_list(window_list_t *window_list) {
if (!window_list) {
printf("no window\n");
return;
}
for (uint32_t i = 0; i < window_list->count; i++) {
printf("window[%u]: 0x%x\n", i, window_list->list[i]);
}
}
static char *bool2string(bool b) { return b ? "true" : "false"; }
static void print_client(client_t *c) {
if (!c) return;
printf("======= client info ========\n");
printf("window: 0x%x, x: %d, y: %d, w: %u, h: %u, bw: %u\n", c->window, c->x,
c->y, c->width, c->height, c->border_width);
printf("floating: %s, fullscreen: %s, maximize: %s\n",
bool2string(c->floating), bool2string(c->fullscreen),
bool2string(c->maximize));
printf("tags: %b, monitor selected tags: %b\n", c->tags,
c->monitor->selected_tags);
printf("name: %s\n", c->name);
printf("===== client info end ======\n");
}
static void print_rule(const rule_t *r) {
printf("==================== rule ====================\n");
printf("class: %s, instance: %s, title: %s\n", r->class, r->instance,
r->title);
printf("floating: %s, maximize: %s, fullscreen: %s, switch to tag: %s\n",
bool2string(r->action.floating), bool2string(r->action.maximize),
bool2string(r->action.fullscreen),
bool2string(r->action.switch_to_tag));
for (uint32_t i = 0; r->tag && r->tag[i].monitor_amount; i++) {
const rule_tag_t *t = &r->tag[i];
printf("monitor amount: %u, monitor index: %u, tags: %b\n",
t->monitor_amount, t->monitor_index, t->tags);
}
printf("================== rule end ==================\n");
}
/* 调试函数结束 */
void init_monitors(void) {
monitor_rect_t *mr = detect_monitor_rect();
uint32_t i = 0;
monitor_t *prev_monitor = NULL;
while (mr) {
monitor_t *m = ecalloc(1, sizeof(monitor_t));
m->monitor_x = mr->x;
m->monitor_y = mr->y;
m->monitor_width = mr->width;
m->monitor_height = mr->height;
m->index = i;
m->layout = &layouts[0];
if (prev_monitor) {
prev_monitor->next = m;
} else {
monitors = m;
current_monitor = m;
}
prev_monitor = m;
i++;
monitor_rect_t *next_mr = mr->next;
free(mr);
mr = next_mr;
}
for (monitor_t *m = monitors; m; m = m->next) {
m->tags = get_monitor_tags(i, m->index);
m->selected_tags = 0x1;
}
}
char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index) {
GStrvBuilder *builder = g_strv_builder_new();
const char *const *tags = NULL;
/* 倒序遍历,达到后面的配置覆盖前面相同配置的效果 */
for (int i = LENGTH(monitor_tags) - 1; i >= 0; i--) {
const char *const *const *config = monitor_tags[i];
uint32_t monitor_count_in_tags_config = 0;
while (config[monitor_count_in_tags_config]) monitor_count_in_tags_config++;
if (monitor_count_in_tags_config != monitor_count) continue;
tags = config[monitor_index];
break;
const char *const *const tags = config[monitor_index];
for (int j = 0; tags[j]; j++) g_strv_builder_add(builder, tags[j]);
return g_strv_builder_unref_to_strv(builder);
}
if (tags == NULL) tags = default_monitor_tags;
for (int i = 0; tags[i]; i++) g_strv_builder_add(builder, tags[i]);
return g_strv_builder_unref_to_strv(builder);
}
void init_wallpaper(void) {
wallpaper_config = parse_wallpaper_config();
if (!wallpaper_config) return;
update_wallpaper(wallpaper_config);
if (!wallpaper_interval) return;
g_timeout_add_seconds(wallpaper_interval, update_wallpaper, wallpaper_config);
}
gboolean update_wallpaper(gpointer user_data) {
wallpaper_config_t *wc = user_data;
if (!wc) return false;
static uint32_t index = 0;
set_wallpaper_by_index(index);
uint32_t monitor_count = 0;
for (monitor_t *m = monitors; m; m = m->next) monitor_count++;
/* 屏幕比壁纸多则不动态切换 */
if (!monitor_count || monitor_count >= wc->count) return false;
if (monitor_count) {
index += monitor_count;
index %= wc->count;
}
return true;
}
void set_wallpaper_by_index(uint32_t index) {
if (!wallpaper_config) return;
rect_size_t *screen_size = get_screen_size();
uint32_t *wallpaper = generate_wallpaper(
wallpaper_config, monitors, index, screen_size->width, screen_size->height);
if (wallpaper) {
double start = get_time();
set_wallpaper(wallpaper);
double end = get_time();
free(wallpaper);
printf("set wallpaper cost: %fs\n", end - start);
}
free(screen_size);
}
wallpaper_config_t *parse_wallpaper_config(void) {
if (!LENGTH(wallpapers)) return NULL;
wallpaper_config_t *wc = ecalloc(1, sizeof(wallpaper_config_t));
GStrvBuilder *builder = g_strv_builder_new();
for (int i = 0; i < LENGTH(wallpapers); i++) {
wordexp_t p;
if (wordexp(wallpapers[i], &p, 0)) continue;
for (size_t i = 0; i < p.we_wordc; i++) {
size_t len = strlen(p.we_wordv[i]) + 1;
char *realpath = ecalloc(len, sizeof(char));
strncpy(realpath, p.we_wordv[i], len);
g_strstrip(realpath);
if (file_exist(realpath)) g_strv_builder_add(builder, realpath);
free(realpath);
}
wordfree(&p);
}
wc->path_list = g_strv_builder_unref_to_strv(builder);
wc->count = g_strv_length(wc->path_list);
if (wc->count) return wc;
free_wallpaper_config(wc);
return NULL;
}
void free_wallpaper_config(wallpaper_config_t *wallpaper_config) {
if (!wallpaper_config) return;
g_strfreev(wallpaper_config->path_list);
free(wallpaper_config);
}
void init_color_set(void) {
color_set = ecalloc(1, sizeof(color_set_t));
char *bar_background = NULL;
char *tag_background = NULL;
char *active_tag_background = NULL;
char *tag = NULL;
char *active_tag = NULL;
char *layout = NULL;
char *client_name = NULL;
char *active_client_name = NULL;
char *status = NULL;
char *border = NULL;
char *active_border = NULL;
get_xresource_string("zswm.color.bar_bg", &bar_background, bar_bg);
get_xresource_string("zswm.color.tag_bg", &tag_background, tag_bg);
get_xresource_string("zswm.color.active_tag_bg", &active_tag_background,
active_tag_bg);
get_xresource_string("zswm.color.tag", &tag, tag_color);
get_xresource_string("zswm.color.active_tag", &active_tag, active_tag_color);
get_xresource_string("zswm.color.layout", &layout, layout_color);
get_xresource_string("zswm.color.client_name", &client_name,
client_name_color);
get_xresource_string("zswm.color.active_client_name", &active_client_name,
active_client_name_color);
get_xresource_string("zswm.color.status", &status, status_color);
get_xresource_string("zswm.color.border", &border, border_color);
get_xresource_string("zswm.color.active_border", &active_border,
active_border_color);
parse_color(bar_background, &color_set->bar_bg);
parse_color(tag_background, &color_set->tag_bg);
parse_color(active_tag_background, &color_set->active_tag_bg);
parse_color(tag, &color_set->tag_color);
parse_color(active_tag, &color_set->active_tag_color);
parse_color(layout, &color_set->layout_color);
parse_color(client_name, &color_set->client_name_color);
parse_color(active_client_name, &color_set->active_client_name_color);
parse_color(status, &color_set->status_color);
parse_color(border, &color_set->border_color);
parse_color(active_border, &color_set->active_border_color);
free(bar_background);
free(tag_background);
free(active_tag_background);
free(tag);
free(active_tag);
free(layout);
free(client_name);
free(active_client_name);
free(status);
free(border);
free(active_border);
}
void parse_color(const char *hex, color_t *color) {
bool success = hex_color_to_rgba(hex, &color->rgba);
if (!success) die("invalid hex color: %s", hex);
color->argb = rgba_to_argb(color->rgba);
extract_color_channel(color->rgba, &color->red, &color->green, &color->blue,
&color->alpha);
}
void init_monitor_bar(void) {
get_xresource_config();
uint32_t font_height = get_font_height(font_family, font_size, dpi);
bar_height = font_height + bar_y_pad * 2;
for (monitor_t *m = monitors; m; m = m->next) {
bar_cairo_params_t *p =
create_bar_window(m->monitor_x, m->monitor_y, m->monitor_width,
bar_height, color_set->bar_bg.argb, cursor_normal);
m->window_x = m->monitor_x;
m->window_width = m->monitor_width;
m->window_y = m->monitor_y + bar_height;
m->window_height = m->monitor_height - bar_height;
m->bar_window = p->window;
cairo_surface_t *surface = cairo_xcb_surface_create(
p->conn, p->window, p->visual, m->monitor_width, bar_height);
cairo_t *cr = cairo_create(surface);
cairo_surface_destroy(surface);
free(p);
cairo_status_t status = cairo_status(cr);
if (status != CAIRO_STATUS_SUCCESS) {
die("cannot create cairo context: %s\n", cairo_status_to_string(status));
}
m->cr = cr;
}
printf("font height: %u, bar height: %u\n", font_height, bar_height);
}
void get_xresource_config(void) {
get_xresource_uint32("Xft.dpi", &dpi);
get_xresource_string("zswm.font_family", &font_family, default_font_family);
get_xresource_uint32("zswm.font_size", &font_size);
get_xresource_uint32("zswm.bar_y_padding", &bar_y_pad);
get_xresource_uint32("zswm.tag_x_padding", &tag_x_pad);
get_xresource_uint32("zswm.border_width", &border_px);
printf("dpi: %u, font family: %s, font size: %u\n", dpi, font_family,
font_size);
clean_xresource();
}
void draw_all_monitor_bars(void) {
for (monitor_t *m = monitors; m; m = m->next) draw_monitor_bar(m);
}
void draw_monitor_bar(monitor_t *m) {
draw_bar(m, m == current_monitor, color_set, bar_height, tag_x_pad);
flush_xcb_connection();
}
void init_xcb_event_loop(void) {
adapter = create_event_adapter();
event_adapter_set_handler(adapter, xcb_event_handler, NULL);
GIOChannel *channel = g_io_channel_unix_new(get_xcb_connection_fd());
g_io_channel_set_encoding(channel, NULL, NULL);
GIOCondition cond = G_IO_IN | G_IO_HUP | G_IO_ERR;
g_io_add_watch(channel, cond, handle_xcb_event, NULL);
g_io_channel_unref(channel);
}
void xcb_event_handler(generic_event_t *event, void *user_data) {
switch (event->type) {
#define EVENT(type, callback) \
case type: \
callback((void *)event); \
break
EVENT(EVENT_TYPE_KEY_PRESS, key_press);
EVENT(EVENT_TYPE_CONFIGURE_REQUEST, configure_request);
EVENT(EVENT_TYPE_MAP_REQUEST, map_request);
EVENT(EVENT_TYPE_UNMAP_NOTIFY, unmap_notify);
#undef EVENT
default:
break;
}
}
void key_press(key_press_event_t *event) {
const keybinding_t *key = NULL;
for (int i = 0; i < LENGTH(keys); i++) {
key = &keys[i];
if (key->key_symbol == event->key_symbol &&
key->modifiers == event->modifiers && key->func) {
key->func(&key->arg);
}
}
}
void configure_request(configure_request_event_t *event) {
client_t *client = get_client_of_window(event->window);
if (!client) {
configure_window(event->window, event->x, event->y, event->width,
event->height, event->border_width);
} else {
configure_window(client->window, client->x, client->y, client->width,
client->height, client->border_width);
printf("configure request: %s\n", client->name);
}
flush_xcb_connection();
}
void map_request(map_request_event_t *event) {
if (!get_window_visible(event->window)) return;
if (get_client_of_window(event->window)) return;
if (event->parent != get_root_window()) return;
manage_window(event->window);
}
void unmap_notify(unmap_notify_event_t *event) {
client_t *c = get_client_of_window(event->window);
if (c) {
unmanage_client(c);
}
}
void manage_window(xcb_window_t window) {
window_geometry_t *geometry = get_window_geometry(window);
client_t *c = ecalloc(1, sizeof(client_t));
c->window = window;
c->x = c->old_x = geometry->x;
c->y = c->old_y = geometry->y;
c->width = c->old_width = geometry->width;
c->height = c->old_height = geometry->height;
c->old_border_width = geometry->border_width;
c->border_width = border_px;
update_client_name(c);
printf("== manage window: %u\n", window);
printf("== x: %d, y: %d, w: %u, h: %u, bw: %u\n", c->x, c->y, c->width,
c->height, c->border_width);
xcb_window_t tw = get_transient_window_for(window);
client_t *tc = NULL;
if (tw != WINDOW_NONE && (tc = get_client_of_window(tw))) {
c->monitor = tc->monitor;
c->tags = tc->tags;
} else {
c->monitor = current_monitor;
apply_rules(c);
}
attach_client(c);
attach_stack_client(c);
init_window_event_mask(window);
change_window_border_color(window, color_set->border_color.argb);
arrange(c->monitor);
map_window(window);
draw_all_monitor_bars();
}
void unmanage_client(client_t *client) {
monitor_t *monitor = client->monitor;
detach_client(client);
detach_stack_client(client);
free(client);
arrange(monitor);
flush_xcb_connection();
}
void update_client_name(client_t *client) {
char *name = get_window_name(client->window);
strncpy(client->name, name, sizeof(client->name) - 1);
free(name);
}
void apply_rules(client_t *client) {
uint32_t monitor_amount = 0;
for (monitor_t *m = monitors; m; m = m->next) monitor_amount++;
window_class_instance_t class_instance;
get_window_class_instance(client->window, &class_instance);
bool switch_to_tag = 0;
for (int i = 0; i < LENGTH(rules); i++) {
const rule_t *r = &rules[i];
if (!((!r->title || strstr(client->name, r->title)) &&
(!r->class || strstr(class_instance.class, r->class)) &&
(!r->instance || strstr(class_instance.instance, r->instance)))) {
continue;
}
print_rule(r);
switch_to_tag = r->action.switch_to_tag;
client->fullscreen = r->action.fullscreen;
client->maximize = r->action.maximize;
client->floating = r->action.floating;
if (!r->tag) continue;
const rule_tag_t *tag = NULL;
for (uint32_t i = 0;; i++) {
const rule_tag_t *t = &r->tag[i];
if (!t->monitor_amount) break;
if (t->monitor_amount == monitor_amount) {
tag = t;
break;
}
}
if (tag) {
monitor_t *m = monitors;
for (uint32_t i = 0; i < tag->monitor_index; i++) m = m ? m->next : NULL;
if (!m) continue;
uint32_t tags_mask = get_tags_mask_of_monitor(m);
client->tags = tag->tags & tags_mask;
}
}
if (!client->tags) {
client->monitor = current_monitor;
client->tags = current_monitor->selected_tags;
}
if (switch_to_tag) {
current_monitor = client->monitor;
current_monitor->selected_tags = client->tags;
}
print_client(client);
printf("apply rules done\n");
}
uint32_t get_tags_mask_of_monitor(monitor_t *monitor) {
uint32_t tags_mask = 0;
for (uint32_t i = 0; monitor->tags[i]; i++) tags_mask |= (1 << i);
return tags_mask;
}
void attach_client(client_t *client) {
client->next = client->monitor->clients;
client->monitor->clients = client;
}
void detach_client(client_t *client) {
client_t **c = &client->monitor->clients;
for (; *c && *c != client; c = &(*c)->next);
*c = client->next;
}
void attach_stack_client(client_t *client) {
client->stack_next = client->monitor->clients_stack;
client->monitor->clients_stack = client;
}
void detach_stack_client(client_t *client) {
client_t **tc = &client->monitor->clients_stack;
for (; *tc && *tc != client; tc = &(*tc)->stack_next);
*tc = client->stack_next;
if (client == client->monitor->selected_client) {
client_t *t = client->monitor->clients_stack;
for (; t && !CLIENT_VISIBLE(t); t = t->stack_next);
client->monitor->selected_client = t;
}
}
void arrange(monitor_t *monitor) {
if (monitor) {
show_hide_client(monitor->clients_stack);
apply_monitor_layout(monitor);
restack(monitor);
} else {
for (monitor = monitors; monitor; monitor = monitor->next) {
show_hide_client(monitor->clients_stack);
apply_monitor_layout(monitor);
}
}
}
void restack(monitor_t *monitor) { /* TODO: */ draw_monitor_bar(monitor); }
void focus(client_t *client) {
/* TODO: */
current_monitor->selected_client = client;
draw_all_monitor_bars();
}
void show_hide_client(client_t *client) {
if (!client) return;
if (CLIENT_VISIBLE(client)) {
if (client->fullscreen) {
fullscreen_client(client);
} else if (client->maximize) {
maximize_client(client);
} else if (!client->monitor->layout->arrange || client->floating) {
client->x = client->old_x;
client->y = client->old_y;
}
configure_window(client->window, client->x, client->y, client->width,
client->height, client->border_width);
show_hide_client(client->stack_next);
} else {
if (!client->monitor->layout->arrange || client->floating) {
client->old_x = client->x;
client->old_y = client->y;
}
client->x = client->monitor->monitor_x;
client->y = client->monitor->monitor_y + client->monitor->monitor_height;
show_hide_client(client->stack_next);
configure_window(client->window, client->x, client->y, client->window,
client->height, client->border_width);
}
}
void apply_monitor_layout(monitor_t *monitor) {
if (!monitor || !monitor->layout || !monitor->layout->arrange) return;
monitor->layout->arrange(monitor);
for (client_t *c = next_visible_client(monitor->clients); c;
c = next_visible_client(c->next)) {
configure_window(c->window, c->x, c->y, c->width, c->height,
c->border_width);
}
}
client_t *get_client_of_window(xcb_window_t window) {
for (monitor_t *m = monitors; m; m = m->next) {
for (client_t *c = m->clients; c; c = c->next) {
if (c->window == window) return c;
}
}
return NULL;
}
gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition,
gpointer userdata) {
if (condition & (G_IO_HUP | G_IO_ERR)) {
g_main_loop_quit(loop);
return false;
}
event_adapter_poll(adapter);
return true;
}
void cleanup(void) {
clean_pango_context();
free_wallpaper_config(wallpaper_config);
wallpaper_config = NULL;
free(color_set);
color_set = NULL;
free(font_family);
font_family = NULL;
monitor_t *m = monitors;
client_t *c = m->clients;
while (m) {
while (c) {
client_t *tc = c->next;
free(c);
c = tc;
}
monitor_t *next_monitor = m->next;
if (m->cr) cairo_destroy(m->cr);
destroy_window(m->bar_window);
g_strfreev(m->tags);
free(m);
m = next_monitor;
}
monitors = NULL;
destroy_event_adapter(adapter);
adapter = NULL;
clean_xcb();
}
int main(int argc, char *argv[]) {
if (has_other_wm_running()) {
die("another window manager is already running");
}
init_monitors();
init_color_set();
init_monitor_bar();
change_window_cursor(get_root_window(), cursor_normal);
init_wallpaper();
draw_all_monitor_bars();
window_list_t *window_list = scan_window_list();
print_monitor_list_info(monitors);
print_color_set(color_set);
print_wallpaper_config(wallpaper_config);
print_window_list(window_list);
free_window_list(window_list);
grab_keybindings(keys, LENGTH(keys));
init_xcb_event_loop();
loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
cleanup();
if (need_restart) {
need_restart = false;
execvp(argv[0], argv);
}
return 0;
}