From 4815ab86206afbe7e472f13a52585d306c7eeb93 Mon Sep 17 00:00:00 2001 From: insofaras Date: Mon, 30 May 2016 04:28:12 +0100 Subject: [PATCH 1/2] linux: update to match changes + do some spring cleaning --- linux_4ed.cpp | 770 +++++++++++++++++++++++++------------------------- 1 file changed, 385 insertions(+), 385 deletions(-) diff --git a/linux_4ed.cpp b/linux_4ed.cpp index 42519140..13b7393a 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -124,8 +124,7 @@ struct Linux_Vars{ XIMStyle input_style; XIC input_context; - Key_Input_Data key_data; - Mouse_State mouse_data; + Application_Step_Input input; String clipboard_contents; String clipboard_outgoing; @@ -133,10 +132,10 @@ struct Linux_Vars{ Atom atom_CLIPBOARD; Atom atom_UTF8_STRING; - Atom atom_NET_WM_STATE; - Atom atom_NET_WM_STATE_MAXIMIZED_HORZ; - Atom atom_NET_WM_STATE_MAXIMIZED_VERT; - Atom atom_NET_WM_PING; + Atom atom__NET_WM_STATE; + Atom atom__NET_WM_STATE_MAXIMIZED_HORZ; + Atom atom__NET_WM_STATE_MAXIMIZED_VERT; + Atom atom__NET_WM_PING; Atom atom_WM_DELETE_WINDOW; b32 has_xfixes; @@ -166,11 +165,9 @@ struct Linux_Vars{ Partition font_part; Plat_Settings settings; - System_Functions *system; + System_Functions system; App_Functions app; Custom_API custom_api; - b32 first; - b32 redraw; b32 vsync; #if FRED_INTERNAL @@ -381,6 +378,20 @@ Sys_File_Time_Stamp_Sig(system_file_time_stamp){ return(microsecond_timestamp); } +internal +Sys_Now_Time_Stamp_Sig(system_now_time_stamp){ + struct timespec spec; + u64 result; + + clock_gettime(CLOCK_REALTIME, &spec); + result = (spec.tv_sec * UINT64_C(1000000)) + (spec.tv_nsec / UINT64_C(1000)); + + //LINUX_FN_DEBUG("ts: %" PRIu64, result); + + return(result); +} + + internal Sys_Set_File_List_Sig(system_set_file_list){ DIR *d; @@ -681,23 +692,6 @@ Sys_Post_Clipboard_Sig(system_post_clipboard){ XSetSelectionOwner(linuxvars.XDisplay, linuxvars.atom_CLIPBOARD, linuxvars.XWindow, CurrentTime); } -// -// Time -// - -internal -Sys_Time_Sig(system_time){ - struct timespec spec; - u64 result; - - clock_gettime(CLOCK_REALTIME, &spec); - result = (spec.tv_sec * UINT64_C(1000000)) + (spec.tv_nsec / UINT64_C(1000)); - - //LINUX_FN_DEBUG("ts: %" PRIu64, result); - - return(result); -} - // // Coroutine // @@ -947,7 +941,7 @@ ThreadProc(void* arg){ thread_memory->size = new_size; } } - full_job->job.callback(linuxvars.system, thread, thread_memory, + full_job->job.callback(&linuxvars.system, thread, thread_memory, &exchange_vars.thread, full_job->job.data); full_job->running_thread = 0; thread->running = 0; @@ -1158,45 +1152,45 @@ LinuxLoadAppCode(String* base_dir){ internal void LinuxLoadSystemCode(){ - linuxvars.system->file_time_stamp = system_file_time_stamp; - linuxvars.system->file_unique_hash = system_file_unique_hash; - linuxvars.system->set_file_list = system_set_file_list; - linuxvars.system->file_track = system_file_track; - linuxvars.system->file_untrack = system_file_untrack; - linuxvars.system->file_load_begin = system_file_load_begin; - linuxvars.system->file_load_end = system_file_load_end; - linuxvars.system->file_save = system_file_save; + linuxvars.system.file_time_stamp = system_file_time_stamp; + linuxvars.system.file_unique_hash = system_file_unique_hash; + linuxvars.system.set_file_list = system_set_file_list; + linuxvars.system.file_track = system_file_track; + linuxvars.system.file_untrack = system_file_untrack; + linuxvars.system.file_load_begin = system_file_load_begin; + linuxvars.system.file_load_end = system_file_load_end; + linuxvars.system.file_save = system_file_save; - linuxvars.system->file_exists = system_file_exists; - linuxvars.system->directory_cd = system_directory_cd; - linuxvars.system->get_4ed_path = system_get_4ed_path; + linuxvars.system.file_exists = system_file_exists; + linuxvars.system.directory_cd = system_directory_cd; + linuxvars.system.get_4ed_path = system_get_4ed_path; - linuxvars.system->post_clipboard = system_post_clipboard; - linuxvars.system->time = system_time; + linuxvars.system.post_clipboard = system_post_clipboard; + linuxvars.system.now_time_stamp = system_now_time_stamp; - linuxvars.system->create_coroutine = system_create_coroutine; - linuxvars.system->launch_coroutine = system_launch_coroutine; - linuxvars.system->resume_coroutine = system_resume_coroutine; - linuxvars.system->yield_coroutine = system_yield_coroutine; + linuxvars.system.create_coroutine = system_create_coroutine; + linuxvars.system.launch_coroutine = system_launch_coroutine; + linuxvars.system.resume_coroutine = system_resume_coroutine; + linuxvars.system.yield_coroutine = system_yield_coroutine; - linuxvars.system->cli_call = system_cli_call; - linuxvars.system->cli_begin_update = system_cli_begin_update; - linuxvars.system->cli_update_step = system_cli_update_step; - linuxvars.system->cli_end_update = system_cli_end_update; + linuxvars.system.cli_call = system_cli_call; + linuxvars.system.cli_begin_update = system_cli_begin_update; + linuxvars.system.cli_update_step = system_cli_update_step; + linuxvars.system.cli_end_update = system_cli_end_update; - linuxvars.system->post_job = system_post_job; - linuxvars.system->cancel_job = system_cancel_job; - linuxvars.system->grow_thread_memory = system_grow_thread_memory; - linuxvars.system->acquire_lock = system_acquire_lock; - linuxvars.system->release_lock = system_release_lock; + linuxvars.system.post_job = system_post_job; + linuxvars.system.cancel_job = system_cancel_job; + linuxvars.system.grow_thread_memory = system_grow_thread_memory; + linuxvars.system.acquire_lock = system_acquire_lock; + linuxvars.system.release_lock = system_release_lock; #if FRED_INTERNAL - linuxvars.system->internal_sentinel = internal_sentinel; - linuxvars.system->internal_get_thread_states = internal_get_thread_states; - linuxvars.system->internal_debug_message = internal_debug_message; + linuxvars.system.internal_sentinel = internal_sentinel; + linuxvars.system.internal_get_thread_states = internal_get_thread_states; + linuxvars.system.internal_debug_message = internal_debug_message; #endif - linuxvars.system->slash = '/'; + linuxvars.system.slash = '/'; } internal void @@ -1232,7 +1226,6 @@ LinuxResizeTarget(i32 width, i32 height){ linuxvars.target.width = width; linuxvars.target.height = height; - linuxvars.redraw = 1; } } @@ -1542,9 +1535,8 @@ init_input_result_zero(){ return(result); } -// NOTE(inso): doesn't actually use XInput anymore, i should change the name... internal Init_Input_Result -InitializeXInput(Display *dpy, Window XWindow) +LinuxInputInit(Display *dpy, Window XWindow) { Init_Input_Result result = {}; XIMStyles *styles = 0; @@ -1711,11 +1703,11 @@ LinuxPushKey(u8 code, u8 chr, u8 chr_nocaps, b8 (*mods)[MDFR_INDEX_COUNT], b32 i Key_Event_Data *data; if(is_hold){ - count = &linuxvars.key_data.hold_count; - data = linuxvars.key_data.hold; + count = &linuxvars.input.keys.hold_count; + data = linuxvars.input.keys.hold; } else { - count = &linuxvars.key_data.press_count; - data = linuxvars.key_data.press; + count = &linuxvars.input.keys.press_count; + data = linuxvars.input.keys.press; } if(*count < KEY_INPUT_BUFFER_SIZE){ @@ -1771,7 +1763,7 @@ LinuxStringDup(String* str, void* data, size_t size){ internal void LinuxScheduleStep(void) { - u64 now = system_time(); + u64 now = system_now_time_stamp(); u64 diff = (now - linuxvars.last_step); if(diff > (u64)frame_useconds){ @@ -1802,12 +1794,12 @@ LinuxMaximizeWindow(Display* d, Window w, b32 maximize) XEvent e = {}; e.xany.type = ClientMessage; - e.xclient.message_type = linuxvars.atom_NET_WM_STATE; + e.xclient.message_type = linuxvars.atom__NET_WM_STATE; e.xclient.format = 32; e.xclient.window = w; e.xclient.data.l[0] = maximize ? STATE_ADD : STATE_REMOVE; - e.xclient.data.l[1] = linuxvars.atom_NET_WM_STATE_MAXIMIZED_VERT; - e.xclient.data.l[2] = linuxvars.atom_NET_WM_STATE_MAXIMIZED_HORZ; + e.xclient.data.l[1] = linuxvars.atom__NET_WM_STATE_MAXIMIZED_VERT; + e.xclient.data.l[2] = linuxvars.atom__NET_WM_STATE_MAXIMIZED_HORZ; e.xclient.data.l[3] = 0L; XSendEvent( @@ -1837,6 +1829,194 @@ LinuxSetIcon(Display* d, Window w) ); } +// +// X11 window init +// + +internal +b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) +{ + // NOTE(allen): Here begins the linux screen setup stuff. + // Behold the true nature of this wonderful OS: + // (thanks again to Casey for providing this stuff) + + Colormap cmap; + XSetWindowAttributes swa; + b32 window_setup_success = 0; + + if (linuxvars.settings.set_window_size){ + *WinWidth = linuxvars.settings.window_w; + *WinHeight = linuxvars.settings.window_h; + } else { + *WinWidth = 800; + *WinHeight = 600; + } + + int XScreenCount = ScreenCount(linuxvars.XDisplay); + glx_config_result Config = {}; + + if(!GLXCanUseFBConfig(linuxvars.XDisplay)){ + fprintf(stderr, "Your GLX version is too old.\n"); + return false; + } + + // TODO(inso): maybe should try the default screen first? or only the default without iterating. + + for(int XScreenIndex = 0; + XScreenIndex < XScreenCount; + ++XScreenIndex) + { + Screen *XScreen = ScreenOfDisplay(linuxvars.XDisplay, XScreenIndex); + + i32 ScrnWidth, ScrnHeight; + ScrnWidth = WidthOfScreen(XScreen); + ScrnHeight = HeightOfScreen(XScreen); + + if (ScrnWidth + 50 < *WinWidth) *WinWidth = ScrnWidth + 50; + if (ScrnHeight + 50 < *WinHeight) *WinHeight = ScrnHeight + 50; + + Config = ChooseGLXConfig(linuxvars.XDisplay, XScreenIndex); + if(Config.Found) + { + swa.colormap = cmap = XCreateColormap(linuxvars.XDisplay, + RootWindow(linuxvars.XDisplay, Config.BestInfo.screen ), + Config.BestInfo.visual, AllocNone); + swa.background_pixmap = None; + swa.border_pixel = 0; + swa.event_mask = StructureNotifyMask; + + linuxvars.XWindow = + XCreateWindow(linuxvars.XDisplay, + RootWindow(linuxvars.XDisplay, Config.BestInfo.screen), + 0, 0, *WinWidth, *WinHeight, + 0, Config.BestInfo.depth, InputOutput, + Config.BestInfo.visual, + CWBorderPixel|CWColormap|CWEventMask, &swa); + + if(linuxvars.XWindow) + { + window_setup_success = 1; + break; + } + } + } + + if (!window_setup_success){ + fprintf(stderr, "Error creating window.\n"); + return false; + } + + //NOTE(inso): Set the window's type to normal + Atom _NET_WM_WINDOW_TYPE = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE", False); + Atom _NET_WIN_TYPE_NORMAL = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE_NORMAL", False); + XChangeProperty( + linuxvars.XDisplay, + linuxvars.XWindow, + _NET_WM_WINDOW_TYPE, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char*)&_NET_WIN_TYPE_NORMAL, + 1 + ); + + //NOTE(inso): window managers want the PID as a window property for some reason. + Atom _NET_WM_PID = XInternAtom(linuxvars.XDisplay, "_NET_WM_PID", False); + pid_t pid = getpid(); + XChangeProperty( + linuxvars.XDisplay, + linuxvars.XWindow, + _NET_WM_PID, + XA_CARDINAL, + 32, + PropModeReplace, + (unsigned char*)&pid, + 1 + ); + +#define WINDOW_NAME "4coder 4linux: " VERSION + + //NOTE(inso): set wm properties + XStoreName(linuxvars.XDisplay, linuxvars.XWindow, WINDOW_NAME); + + char* win_name_list[] = { WINDOW_NAME }; + XTextProperty win_name; + + XStringListToTextProperty(win_name_list, 1, &win_name); + + XSizeHints *sz_hints = XAllocSizeHints(); + XWMHints *wm_hints = XAllocWMHints(); + XClassHint *cl_hints = XAllocClassHint(); + + if(linuxvars.settings.set_window_pos){ + sz_hints->flags |= USPosition; + sz_hints->x = linuxvars.settings.window_x; + sz_hints->y = linuxvars.settings.window_y; + } + + wm_hints->flags |= InputHint; + wm_hints->input = True; + + cl_hints->res_name = "4coder"; + cl_hints->res_class = "4coder"; + + XSetWMProperties( + linuxvars.XDisplay, + linuxvars.XWindow, + &win_name, + NULL, + argv, + argc, + sz_hints, + wm_hints, + cl_hints + ); + + XFree(sz_hints); + XFree(wm_hints); + XFree(cl_hints); + + XFree(win_name.value); + + LinuxSetIcon(linuxvars.XDisplay, linuxvars.XWindow); + + //NOTE(inso): make the window visible + XMapWindow(linuxvars.XDisplay, linuxvars.XWindow); + + b32 IsLegacy = false; + GLXContext GLContext = + InitializeOpenGLContext(linuxvars.XDisplay, linuxvars.XWindow, Config.BestConfig, IsLegacy); + + XWindowAttributes WinAttribs; + if(XGetWindowAttributes(linuxvars.XDisplay, linuxvars.XWindow, &WinAttribs)) + { + *WinWidth = WinAttribs.width; + *WinHeight = WinAttribs.height; + } + + XRaiseWindow(linuxvars.XDisplay, linuxvars.XWindow); + XSync(linuxvars.XDisplay, False); + + if (linuxvars.settings.set_window_pos){ + XMoveWindow( + linuxvars.XDisplay, + linuxvars.XWindow, + linuxvars.settings.window_x, + linuxvars.settings.window_y + ); + } + + if (linuxvars.settings.maximize_window){ + LinuxMaximizeWindow(linuxvars.XDisplay, linuxvars.XWindow, 1); + } + + Atom wm_protos[] = { + linuxvars.atom_WM_DELETE_WINDOW, + linuxvars.atom__NET_WM_PING + }; + + XSetWMProtocols(linuxvars.XDisplay, linuxvars.XWindow, wm_protos, 2); +} internal void LinuxHandleX11Events(void) @@ -1933,30 +2113,30 @@ LinuxHandleX11Events(void) case MotionNotify: { should_step = 1; - linuxvars.mouse_data.x = Event.xmotion.x; - linuxvars.mouse_data.y = Event.xmotion.y; + linuxvars.input.mouse.x = Event.xmotion.x; + linuxvars.input.mouse.y = Event.xmotion.y; }break; case ButtonPress: { should_step = 1; switch(Event.xbutton.button){ case Button1: { - linuxvars.mouse_data.press_l = 1; - linuxvars.mouse_data.l = 1; + linuxvars.input.mouse.press_l = 1; + linuxvars.input.mouse.l = 1; } break; case Button3: { - linuxvars.mouse_data.press_r = 1; - linuxvars.mouse_data.r = 1; + linuxvars.input.mouse.press_r = 1; + linuxvars.input.mouse.r = 1; } break; //NOTE(inso): scroll up case Button4: { - linuxvars.mouse_data.wheel = 1; + linuxvars.input.mouse.wheel = 1; }break; //NOTE(inso): scroll down case Button5: { - linuxvars.mouse_data.wheel = -1; + linuxvars.input.mouse.wheel = -1; }break; } }break; @@ -1965,31 +2145,31 @@ LinuxHandleX11Events(void) should_step = 1; switch(Event.xbutton.button){ case Button1: { - linuxvars.mouse_data.release_l = 1; - linuxvars.mouse_data.l = 0; + linuxvars.input.mouse.release_l = 1; + linuxvars.input.mouse.l = 0; } break; case Button3: { - linuxvars.mouse_data.release_r = 1; - linuxvars.mouse_data.r = 0; + linuxvars.input.mouse.release_r = 1; + linuxvars.input.mouse.r = 0; } break; } }break; case EnterNotify: { should_step = 1; - linuxvars.mouse_data.out_of_window = 0; + linuxvars.input.mouse.out_of_window = 0; }break; case LeaveNotify: { should_step = 1; - linuxvars.mouse_data.out_of_window = 1; + linuxvars.input.mouse.out_of_window = 1; }break; case FocusIn: case FocusOut: { should_step = 1; - linuxvars.mouse_data.l = 0; - linuxvars.mouse_data.r = 0; + linuxvars.input.mouse.l = 0; + linuxvars.input.mouse.r = 0; }break; case ConfigureNotify: { @@ -2013,7 +2193,7 @@ LinuxHandleX11Events(void) should_step = 1; linuxvars.keep_running = 0; } - else if ((Atom)Event.xclient.data.l[0] == linuxvars.atom_NET_WM_PING) { + else if ((Atom)Event.xclient.data.l[0] == linuxvars.atom__NET_WM_PING) { Event.xclient.window = DefaultRootWindow(linuxvars.XDisplay); XSendEvent( linuxvars.XDisplay, @@ -2111,7 +2291,6 @@ LinuxHandleX11Events(void) case Expose: case VisibilityNotify: { should_step = 1; - linuxvars.redraw = 1; }break; default: { @@ -2160,6 +2339,9 @@ LinuxHandleFileEvents() int main(int argc, char **argv) { + // + // System & Memory init + // #if FRED_INTERNAL linuxvars.internal_bubble.next = &linuxvars.internal_bubble; @@ -2169,68 +2351,38 @@ main(int argc, char **argv) pthread_mutex_init(&linuxvars.DEBUG_sysmem_lock, 0); #endif - linuxvars.first = 1; - char base_dir_mem[PATH_MAX]; String base_dir = make_fixed_width_string(base_dir_mem); if (!LinuxLoadAppCode(&base_dir)){ - // TODO(allen): Failed to load app code, serious problem. + fprintf(stderr, "Could not load 4ed_app.so! It should be in the same dir as 4ed.\n"); return 99; } - System_Functions system_; - System_Functions *system = &system_; - linuxvars.system = system; LinuxLoadSystemCode(); + LinuxLoadRenderCode(); - linuxvars.coroutine_free = linuxvars.coroutine_data; - for (i32 i = 0; i+1 < ArrayCount(linuxvars.coroutine_data); ++i){ - linuxvars.coroutine_data[i].next = linuxvars.coroutine_data + i + 1; - } - - const size_t stack_size = Mbytes(16); - for (i32 i = 0; i < ArrayCount(linuxvars.coroutine_data); ++i){ - linuxvars.coroutine_data[i].stack.ss_size = stack_size; - linuxvars.coroutine_data[i].stack.ss_sp = system_get_memory(stack_size); - } - - memory_vars.vars_memory_size = Mbytes(2); - memory_vars.vars_memory = system_get_memory(memory_vars.vars_memory_size); + memory_vars.vars_memory_size = Mbytes(2); + memory_vars.vars_memory = system_get_memory(memory_vars.vars_memory_size); memory_vars.target_memory_size = Mbytes(512); - memory_vars.target_memory = system_get_memory(memory_vars.target_memory_size); - memory_vars.user_memory_size = Mbytes(2); - memory_vars.user_memory = system_get_memory(memory_vars.user_memory_size); + memory_vars.target_memory = system_get_memory(memory_vars.target_memory_size); + memory_vars.user_memory_size = Mbytes(2); + memory_vars.user_memory = system_get_memory(memory_vars.user_memory_size); -#if 0 - memory_vars.vars_memory_size = Mbytes(2); - memory_vars.vars_memory = mmap(0, memory_vars.vars_memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - memory_vars.target_memory_size = Mbytes(512); - memory_vars.target_memory = mmap(0, memory_vars.target_memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - memory_vars.user_memory_size = Mbytes(2); - memory_vars.user_memory = mmap(0, memory_vars.user_memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -#endif - - String current_directory; - i32 curdir_req, curdir_size; - char *curdir_mem; + linuxvars.target.max = Mbytes(1); + linuxvars.target.push_buffer = (byte*)system_get_memory(linuxvars.target.max); + + // + // Read command line + // - curdir_req = (1 << 9); - curdir_mem = (char*)system_get_memory(curdir_req); - for (; getcwd(curdir_mem, curdir_req) == 0 && curdir_req < (1 << 13);){ - system_free_memory(curdir_mem); - curdir_req *= 4; - curdir_mem = (char*)system_get_memory(curdir_req); + char* cwd = get_current_dir_name(); + if(!cwd){ + perror("get_current_dir_name"); + return 1; } - if (curdir_req >= (1 << 13)){ - // TODO(allen): bullshit string APIs makin' me pissed - return 57; - } - - for (curdir_size = 0; curdir_mem[curdir_size]; ++curdir_size); - - current_directory = make_string(curdir_mem, curdir_size, curdir_req); + String current_directory = make_string_slowly(cwd); Command_Line_Parameters clparams; clparams.argv = argv; @@ -2241,12 +2393,12 @@ main(int argc, char **argv) i32 output_size; output_size = - linuxvars.app.read_command_line(system, - &memory_vars, - current_directory, - &linuxvars.settings, - &files, &file_count, - clparams); + linuxvars.app.read_command_line(&linuxvars.system, + &memory_vars, + current_directory, + &linuxvars.settings, + &files, &file_count, + clparams); if (output_size > 0){ // TODO(allen): crt free version @@ -2256,16 +2408,12 @@ main(int argc, char **argv) sysshared_filter_real_files(files, file_count); - linuxvars.XDisplay = XOpenDisplay(0); - - if(!linuxvars.XDisplay){ - fprintf(stderr, "Can't open display!\n"); - return 1; - } - - LinuxKeycodeInit(linuxvars.XDisplay); + // + // Custom layer linkage + // #ifdef FRED_SUPER + char *custom_file_default = "4coder_custom.so"; sysshared_to_binary_path(&base_dir, custom_file_default); custom_file_default = base_dir.str; @@ -2309,15 +2457,33 @@ main(int argc, char **argv) const char* error = dlerror(); fprintf(stderr, "*** Failed to load 4coder_custom.so: %s\n", error ? error : "dlopen failed."); } + #endif if (linuxvars.custom_api.get_bindings == 0){ linuxvars.custom_api.get_bindings = get_bindings; } +#if 0 if (linuxvars.custom_api.view_routine == 0){ linuxvars.custom_api.view_routine = view_routine; } +#endif + + // + // Coroutine / Thread / Semaphore / Mutex init + // + + linuxvars.coroutine_free = linuxvars.coroutine_data; + for (i32 i = 0; i+1 < ArrayCount(linuxvars.coroutine_data); ++i){ + linuxvars.coroutine_data[i].next = linuxvars.coroutine_data + i + 1; + } + + const size_t stack_size = Mbytes(16); + for (i32 i = 0; i < ArrayCount(linuxvars.coroutine_data); ++i){ + linuxvars.coroutine_data[i].stack.ss_size = stack_size; + linuxvars.coroutine_data[i].stack.ss_sp = system_get_memory(stack_size); + } Thread_Context background[4] = {}; linuxvars.groups[BACKGROUND_THREADS].threads = background; @@ -2347,210 +2513,34 @@ main(int argc, char **argv) pthread_mutex_init(linuxvars.locks + i, NULL); } - LinuxLoadRenderCode(); - linuxvars.target.max = Mbytes(1); - linuxvars.target.push_buffer = (byte*)system_get_memory(linuxvars.target.max); + // + // X11 init + // + + linuxvars.XDisplay = XOpenDisplay(0); + if(!linuxvars.XDisplay){ + fprintf(stderr, "Can't open display!\n"); + return 1; + } + +#define LOAD_ATOM(x) linuxvars.atom_##x = XInternAtom(linuxvars.XDisplay, #x, False); - // NOTE(allen): Here begins the linux screen setup stuff. - // Behold the true nature of this wonderful OS: - // (thanks again to Casey for providing this stuff) + LOAD_ATOM(CLIPBOARD); + LOAD_ATOM(UTF8_STRING); + LOAD_ATOM(_NET_WM_STATE); + LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); + LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); + LOAD_ATOM(_NET_WM_PING); + LOAD_ATOM(WM_DELETE_WINDOW); + +#undef LOAD_ATOM - Colormap cmap; - XSetWindowAttributes swa; int WinWidth, WinHeight; - b32 window_setup_success = 0; - - if (linuxvars.settings.set_window_size){ - WinWidth = linuxvars.settings.window_w; - WinHeight = linuxvars.settings.window_h; - } else { - WinWidth = 800; - WinHeight = 600; - } - - int XScreenCount = ScreenCount(linuxvars.XDisplay); - glx_config_result Config = {}; - - if(!GLXCanUseFBConfig(linuxvars.XDisplay)){ - fprintf(stderr, "Your GLX version is too old.\n"); - exit(1); - } - - // TODO(inso): maybe should try the default screen first? or only the default without iterating. - - for(int XScreenIndex = 0; - XScreenIndex < XScreenCount; - ++XScreenIndex) - { - Screen *XScreen = ScreenOfDisplay(linuxvars.XDisplay, XScreenIndex); - - i32 ScrnWidth, ScrnHeight; - ScrnWidth = WidthOfScreen(XScreen); - ScrnHeight = HeightOfScreen(XScreen); - - if (ScrnWidth + 50 < WinWidth) WinWidth = ScrnWidth + 50; - if (ScrnHeight + 50 < WinHeight) WinHeight = ScrnHeight + 50; - - Config = ChooseGLXConfig(linuxvars.XDisplay, XScreenIndex); - if(Config.Found) - { - swa.colormap = cmap = XCreateColormap(linuxvars.XDisplay, - RootWindow(linuxvars.XDisplay, Config.BestInfo.screen ), - Config.BestInfo.visual, AllocNone); - swa.background_pixmap = None; - swa.border_pixel = 0; - swa.event_mask = StructureNotifyMask; - - linuxvars.XWindow = - XCreateWindow(linuxvars.XDisplay, - RootWindow(linuxvars.XDisplay, Config.BestInfo.screen), - 0, 0, WinWidth, WinHeight, - 0, Config.BestInfo.depth, InputOutput, - Config.BestInfo.visual, - CWBorderPixel|CWColormap|CWEventMask, &swa); - - if(linuxvars.XWindow) - { - window_setup_success = 1; - break; - } - } - } - - if (!window_setup_success){ - fprintf(stderr, "Error creating window.\n"); - exit(1); - } - - //NOTE(inso): Set the window's type to normal - Atom _NET_WM_WINDOW_TYPE = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE", False); - Atom _NET_WIN_TYPE_NORMAL = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE_NORMAL", False); - XChangeProperty( - linuxvars.XDisplay, - linuxvars.XWindow, - _NET_WM_WINDOW_TYPE, - XA_ATOM, - 32, - PropModeReplace, - (unsigned char*)&_NET_WIN_TYPE_NORMAL, - 1 - ); - - //NOTE(inso): window managers want the PID as a window property for some reason. - Atom _NET_WM_PID = XInternAtom(linuxvars.XDisplay, "_NET_WM_PID", False); - pid_t pid = getpid(); - XChangeProperty( - linuxvars.XDisplay, - linuxvars.XWindow, - _NET_WM_PID, - XA_CARDINAL, - 32, - PropModeReplace, - (unsigned char*)&pid, - 1 - ); - -#define WINDOW_NAME "4coder 4linux: " VERSION - - //NOTE(inso): set wm properties - XStoreName(linuxvars.XDisplay, linuxvars.XWindow, WINDOW_NAME); - - char* win_name_list[] = { WINDOW_NAME }; - XTextProperty win_name; - - XStringListToTextProperty(win_name_list, 1, &win_name); - - XSizeHints *sz_hints = XAllocSizeHints(); - XWMHints *wm_hints = XAllocWMHints(); - XClassHint *cl_hints = XAllocClassHint(); - - if(linuxvars.settings.set_window_pos){ - sz_hints->flags |= USPosition; - sz_hints->x = linuxvars.settings.window_x; - sz_hints->y = linuxvars.settings.window_y; - } - - wm_hints->flags |= InputHint; - wm_hints->input = True; - - cl_hints->res_name = "4coder"; - cl_hints->res_class = "4coder"; - - XSetWMProperties( - linuxvars.XDisplay, - linuxvars.XWindow, - &win_name, - NULL, - argv, - argc, - sz_hints, - wm_hints, - cl_hints - ); - - XFree(sz_hints); - XFree(wm_hints); - XFree(cl_hints); - - XFree(win_name.value); - - LinuxSetIcon(linuxvars.XDisplay, linuxvars.XWindow); - - //NOTE(inso): make the window visible - XMapWindow(linuxvars.XDisplay, linuxvars.XWindow); - - Init_Input_Result input_result = - InitializeXInput(linuxvars.XDisplay, linuxvars.XWindow); - - linuxvars.input_method = input_result.input_method; - linuxvars.input_style = input_result.best_style; - linuxvars.input_context = input_result.xic; - - b32 IsLegacy = false; - GLXContext GLContext = - InitializeOpenGLContext(linuxvars.XDisplay, linuxvars.XWindow, Config.BestConfig, IsLegacy); - - XWindowAttributes WinAttribs; - if(XGetWindowAttributes(linuxvars.XDisplay, linuxvars.XWindow, &WinAttribs)) - { - WinWidth = WinAttribs.width; - WinHeight = WinAttribs.height; - } - - XRaiseWindow(linuxvars.XDisplay, linuxvars.XWindow); - XSync(linuxvars.XDisplay, False); - - if (linuxvars.settings.set_window_pos){ - XMoveWindow( - linuxvars.XDisplay, - linuxvars.XWindow, - linuxvars.settings.window_x, - linuxvars.settings.window_y - ); - } - - Cursor xcursors[APP_MOUSE_CURSOR_COUNT] = { - None, - XCreateFontCursor(linuxvars.XDisplay, XC_arrow), - XCreateFontCursor(linuxvars.XDisplay, XC_xterm), - XCreateFontCursor(linuxvars.XDisplay, XC_sb_h_double_arrow), - XCreateFontCursor(linuxvars.XDisplay, XC_sb_v_double_arrow) - }; - - XSetICFocus(linuxvars.input_context); - - linuxvars.atom_CLIPBOARD = XInternAtom(linuxvars.XDisplay, "CLIPBOARD", False); - linuxvars.atom_UTF8_STRING = XInternAtom(linuxvars.XDisplay, "UTF8_STRING", False); - linuxvars.atom_NET_WM_STATE = XInternAtom(linuxvars.XDisplay, "_NET_WM_STATE", False); - linuxvars.atom_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(linuxvars.XDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", False); - linuxvars.atom_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(linuxvars.XDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", False); - - if (linuxvars.settings.maximize_window){ - LinuxMaximizeWindow(linuxvars.XDisplay, linuxvars.XWindow, 1); + if(!LinuxX11WindowInit(argc, argv, &WinWidth, &WinHeight)){ + return 1; } int xfixes_version_unused, xfixes_err_unused; - linuxvars.has_xfixes = XQueryExtension( linuxvars.XDisplay, "XFIXES", @@ -2568,20 +2558,26 @@ main(int argc, char **argv) ); } - linuxvars.atom_WM_DELETE_WINDOW = XInternAtom(linuxvars.XDisplay, "WM_DELETE_WINDOW", False); - linuxvars.atom_NET_WM_PING = XInternAtom(linuxvars.XDisplay, "_NET_WM_PING", False); + Init_Input_Result input_result = + LinuxInputInit(linuxvars.XDisplay, linuxvars.XWindow); - Atom wm_protos[] = { - linuxvars.atom_WM_DELETE_WINDOW, - linuxvars.atom_NET_WM_PING + linuxvars.input_method = input_result.input_method; + linuxvars.input_style = input_result.best_style; + linuxvars.input_context = input_result.xic; + + LinuxKeycodeInit(linuxvars.XDisplay); + + Cursor xcursors[APP_MOUSE_CURSOR_COUNT] = { + None, + XCreateFontCursor(linuxvars.XDisplay, XC_arrow), + XCreateFontCursor(linuxvars.XDisplay, XC_xterm), + XCreateFontCursor(linuxvars.XDisplay, XC_sb_h_double_arrow), + XCreateFontCursor(linuxvars.XDisplay, XC_sb_v_double_arrow) }; - XSetWMProtocols(linuxvars.XDisplay, linuxvars.XWindow, wm_protos, 2); - linuxvars.app.init(linuxvars.system, &linuxvars.target, &memory_vars, &exchange_vars, - linuxvars.clipboard_contents, current_directory, - linuxvars.custom_api); - - LinuxResizeTarget(WinWidth, WinHeight); + // + // Epoll init + // linuxvars.x11_fd = ConnectionNumber(linuxvars.XDisplay); linuxvars.inotify_fd = inotify_init1(IN_NONBLOCK); @@ -2606,9 +2602,26 @@ main(int argc, char **argv) e.data.u64 = LINUX_4ED_EVENT_STEP_TIMER; epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_timer_fd, &e); } + + // + // App init + // + + linuxvars.app.init(&linuxvars.system, &linuxvars.target, &memory_vars, &exchange_vars, + linuxvars.clipboard_contents, current_directory, + linuxvars.custom_api); + + LinuxResizeTarget(WinWidth, WinHeight); + + // + // Main loop + // LinuxScheduleStep(); + linuxvars.keep_running = 1; + linuxvars.input.first_step = 1; + linuxvars.input.dt = (frame_useconds / 1000000.f); while(1){ @@ -2665,12 +2678,9 @@ main(int argc, char **argv) } if(do_step){ - linuxvars.last_step = system_time(); + linuxvars.last_step = system_now_time_stamp(); - // TODO(inso): not all events should require a redraw? - linuxvars.redraw = 1; - - if(linuxvars.first || !linuxvars.has_xfixes){ + if(linuxvars.input.first_step || !linuxvars.has_xfixes){ XConvertSelection( linuxvars.XDisplay, linuxvars.atom_CLIPBOARD, @@ -2685,24 +2695,19 @@ main(int argc, char **argv) result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; result.trying_to_kill = !linuxvars.keep_running; - String clipboard = {}; if(linuxvars.new_clipboard){ - clipboard = linuxvars.clipboard_contents; + linuxvars.input.clipboard = linuxvars.clipboard_contents; linuxvars.new_clipboard = 0; + } else { + linuxvars.input.clipboard = string_zero(); } - f32 dt = frame_useconds / 1000000.f; - linuxvars.app.step( - linuxvars.system, - &linuxvars.key_data, - &linuxvars.mouse_data, + &linuxvars.system, &linuxvars.target, &memory_vars, &exchange_vars, - clipboard, - dt, - linuxvars.first, + &linuxvars.input, &result ); @@ -2713,14 +2718,10 @@ main(int argc, char **argv) } if(result.animating){ - linuxvars.redraw = 1; LinuxScheduleStep(); } - if(linuxvars.redraw){ - LinuxRedrawTarget(); - linuxvars.redraw = 0; - } + LinuxRedrawTarget(); if(result.mouse_cursor_type != linuxvars.cursor){ Cursor c = xcursors[result.mouse_cursor_type]; @@ -2728,14 +2729,13 @@ main(int argc, char **argv) linuxvars.cursor = result.mouse_cursor_type; } - linuxvars.first = 0; - linuxvars.redraw = 0; - linuxvars.key_data = key_input_data_zero(); - linuxvars.mouse_data.press_l = 0; - linuxvars.mouse_data.release_l = 0; - linuxvars.mouse_data.press_r = 0; - linuxvars.mouse_data.release_r = 0; - linuxvars.mouse_data.wheel = 0; + linuxvars.input.first_step = 0; + linuxvars.input.keys = key_input_data_zero(); + linuxvars.input.mouse.press_l = 0; + linuxvars.input.mouse.release_l = 0; + linuxvars.input.mouse.press_r = 0; + linuxvars.input.mouse.release_r = 0; + linuxvars.input.mouse.wheel = 0; } system_release_lock(FRAME_LOCK); From 16677d3f9002c2edb37bee5e7e7c8f6e84138b9a Mon Sep 17 00:00:00 2001 From: insofaras Date: Tue, 31 May 2016 00:30:06 +0100 Subject: [PATCH 2/2] linux: a few small improvements: * Add PropertyChangeMask to events, makes compiz redraw better with (un)maximizing * Create the window on the default screen instead of iterating through all of them * Set backing store hint, looks nicer when moving stuff over the 4ed window * Set some other WM hints like min/max/default size, gravity, etc since most other apps seem to set them --- linux_4ed.cpp | 150 +++++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 81 deletions(-) diff --git a/linux_4ed.cpp b/linux_4ed.cpp index 13b7393a..f2ac65d3 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -136,6 +136,9 @@ struct Linux_Vars{ Atom atom__NET_WM_STATE_MAXIMIZED_HORZ; Atom atom__NET_WM_STATE_MAXIMIZED_VERT; Atom atom__NET_WM_PING; + Atom atom__NET_WM_WINDOW_TYPE; + Atom atom__NET_WM_WINDOW_TYPE_NORMAL; + Atom atom__NET_WM_PID; Atom atom_WM_DELETE_WINDOW; b32 has_xfixes; @@ -1601,6 +1604,7 @@ LinuxInputInit(Display *dpy, Window XWindow) KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | + PropertyChangeMask | PointerMotionMask | FocusChangeMask | StructureNotifyMask | @@ -1840,93 +1844,66 @@ b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) // Behold the true nature of this wonderful OS: // (thanks again to Casey for providing this stuff) - Colormap cmap; - XSetWindowAttributes swa; - b32 window_setup_success = 0; +#define BASE_W 800 +#define BASE_H 600 if (linuxvars.settings.set_window_size){ *WinWidth = linuxvars.settings.window_w; *WinHeight = linuxvars.settings.window_h; } else { - *WinWidth = 800; - *WinHeight = 600; + *WinWidth = BASE_W; + *WinHeight = BASE_H; } - int XScreenCount = ScreenCount(linuxvars.XDisplay); - glx_config_result Config = {}; - - if(!GLXCanUseFBConfig(linuxvars.XDisplay)){ + if (!GLXCanUseFBConfig(linuxvars.XDisplay)){ fprintf(stderr, "Your GLX version is too old.\n"); return false; } - // TODO(inso): maybe should try the default screen first? or only the default without iterating. - - for(int XScreenIndex = 0; - XScreenIndex < XScreenCount; - ++XScreenIndex) - { - Screen *XScreen = ScreenOfDisplay(linuxvars.XDisplay, XScreenIndex); - - i32 ScrnWidth, ScrnHeight; - ScrnWidth = WidthOfScreen(XScreen); - ScrnHeight = HeightOfScreen(XScreen); - - if (ScrnWidth + 50 < *WinWidth) *WinWidth = ScrnWidth + 50; - if (ScrnHeight + 50 < *WinHeight) *WinHeight = ScrnHeight + 50; - - Config = ChooseGLXConfig(linuxvars.XDisplay, XScreenIndex); - if(Config.Found) - { - swa.colormap = cmap = XCreateColormap(linuxvars.XDisplay, - RootWindow(linuxvars.XDisplay, Config.BestInfo.screen ), - Config.BestInfo.visual, AllocNone); - swa.background_pixmap = None; - swa.border_pixel = 0; - swa.event_mask = StructureNotifyMask; - - linuxvars.XWindow = - XCreateWindow(linuxvars.XDisplay, - RootWindow(linuxvars.XDisplay, Config.BestInfo.screen), - 0, 0, *WinWidth, *WinHeight, - 0, Config.BestInfo.depth, InputOutput, - Config.BestInfo.visual, - CWBorderPixel|CWColormap|CWEventMask, &swa); - - if(linuxvars.XWindow) - { - window_setup_success = 1; - break; - } - } + glx_config_result Config = ChooseGLXConfig(linuxvars.XDisplay, DefaultScreen(linuxvars.XDisplay)); + if (!Config.Found){ + fprintf(stderr, "Could not create GLX FBConfig.\n"); } - if (!window_setup_success){ + XSetWindowAttributes swa = {}; + swa.backing_store = WhenMapped; + swa.event_mask = StructureNotifyMask; + swa.bit_gravity = NorthWestGravity; + swa.colormap = XCreateColormap(linuxvars.XDisplay, + RootWindow(linuxvars.XDisplay, Config.BestInfo.screen), + Config.BestInfo.visual, AllocNone); + + linuxvars.XWindow = + XCreateWindow(linuxvars.XDisplay, + RootWindow(linuxvars.XDisplay, Config.BestInfo.screen), + 0, 0, *WinWidth, *WinHeight, + 0, Config.BestInfo.depth, InputOutput, + Config.BestInfo.visual, + CWBackingStore|CWBitGravity|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &swa); + + if (!linuxvars.XWindow){ fprintf(stderr, "Error creating window.\n"); return false; } //NOTE(inso): Set the window's type to normal - Atom _NET_WM_WINDOW_TYPE = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE", False); - Atom _NET_WIN_TYPE_NORMAL = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE_NORMAL", False); XChangeProperty( linuxvars.XDisplay, linuxvars.XWindow, - _NET_WM_WINDOW_TYPE, + linuxvars.atom__NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, - (unsigned char*)&_NET_WIN_TYPE_NORMAL, + (unsigned char*)&linuxvars.atom__NET_WM_WINDOW_TYPE_NORMAL, 1 ); //NOTE(inso): window managers want the PID as a window property for some reason. - Atom _NET_WM_PID = XInternAtom(linuxvars.XDisplay, "_NET_WM_PID", False); pid_t pid = getpid(); XChangeProperty( linuxvars.XDisplay, linuxvars.XWindow, - _NET_WM_PID, + linuxvars.atom__NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, @@ -1939,45 +1916,53 @@ b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) //NOTE(inso): set wm properties XStoreName(linuxvars.XDisplay, linuxvars.XWindow, WINDOW_NAME); - char* win_name_list[] = { WINDOW_NAME }; - XTextProperty win_name; - - XStringListToTextProperty(win_name_list, 1, &win_name); - XSizeHints *sz_hints = XAllocSizeHints(); XWMHints *wm_hints = XAllocWMHints(); XClassHint *cl_hints = XAllocClassHint(); - if(linuxvars.settings.set_window_pos){ + sz_hints->flags = PMinSize | PMaxSize | PBaseSize | PWinGravity; + + sz_hints->min_width = 50; + sz_hints->min_height = 50; + + sz_hints->max_width = sz_hints->max_height = (1UL << 16UL); + + sz_hints->base_width = BASE_W; + sz_hints->base_height = BASE_H; + + sz_hints->win_gravity = NorthWestGravity; + + if (linuxvars.settings.set_window_pos){ sz_hints->flags |= USPosition; sz_hints->x = linuxvars.settings.window_x; sz_hints->y = linuxvars.settings.window_y; } - wm_hints->flags |= InputHint; + wm_hints->flags |= InputHint | StateHint; wm_hints->input = True; + wm_hints->initial_state = NormalState; cl_hints->res_name = "4coder"; cl_hints->res_class = "4coder"; + char* win_name_list[] = { WINDOW_NAME }; + XTextProperty win_name; + XStringListToTextProperty(win_name_list, 1, &win_name); + XSetWMProperties( linuxvars.XDisplay, linuxvars.XWindow, - &win_name, - NULL, - argv, - argc, - sz_hints, - wm_hints, - cl_hints + &win_name, NULL, + argv, argc, + sz_hints, wm_hints, cl_hints ); + XFree(win_name.value); + XFree(sz_hints); XFree(wm_hints); XFree(cl_hints); - XFree(win_name.value); - LinuxSetIcon(linuxvars.XDisplay, linuxvars.XWindow); //NOTE(inso): make the window visible @@ -1987,15 +1972,7 @@ b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) GLXContext GLContext = InitializeOpenGLContext(linuxvars.XDisplay, linuxvars.XWindow, Config.BestConfig, IsLegacy); - XWindowAttributes WinAttribs; - if(XGetWindowAttributes(linuxvars.XDisplay, linuxvars.XWindow, &WinAttribs)) - { - *WinWidth = WinAttribs.width; - *WinHeight = WinAttribs.height; - } - XRaiseWindow(linuxvars.XDisplay, linuxvars.XWindow); - XSync(linuxvars.XDisplay, False); if (linuxvars.settings.set_window_pos){ XMoveWindow( @@ -2009,6 +1986,14 @@ b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) if (linuxvars.settings.maximize_window){ LinuxMaximizeWindow(linuxvars.XDisplay, linuxvars.XWindow, 1); } + XSync(linuxvars.XDisplay, False); + + XWindowAttributes WinAttribs; + if (XGetWindowAttributes(linuxvars.XDisplay, linuxvars.XWindow, &WinAttribs)) + { + *WinWidth = WinAttribs.width; + *WinHeight = WinAttribs.height; + } Atom wm_protos[] = { linuxvars.atom_WM_DELETE_WINDOW, @@ -2495,7 +2480,7 @@ main(int argc, char **argv) sem_init(&linuxvars.thread_semaphores[BACKGROUND_THREADS], 0, 0); exchange_vars.thread.queues[BACKGROUND_THREADS].semaphore = - LinuxSemToHandle(&linuxvars.thread_semaphores[BACKGROUND_THREADS]); + LinuxSemToHandle(&linuxvars.thread_semaphores[BACKGROUND_THREADS]); for(i32 i = 0; i < linuxvars.groups[BACKGROUND_THREADS].count; ++i){ Thread_Context *thread = linuxvars.groups[BACKGROUND_THREADS].threads + i; @@ -2522,7 +2507,7 @@ main(int argc, char **argv) fprintf(stderr, "Can't open display!\n"); return 1; } - + #define LOAD_ATOM(x) linuxvars.atom_##x = XInternAtom(linuxvars.XDisplay, #x, False); LOAD_ATOM(CLIPBOARD); @@ -2531,6 +2516,9 @@ main(int argc, char **argv) LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); LOAD_ATOM(_NET_WM_PING); + LOAD_ATOM(_NET_WM_WINDOW_TYPE); + LOAD_ATOM(_NET_WM_WINDOW_TYPE_NORMAL); + LOAD_ATOM(_NET_WM_PID); LOAD_ATOM(WM_DELETE_WINDOW); #undef LOAD_ATOM