/* Stop watching a directory specified by a pointer to its dirwatch object. */ static int remove_watch (struct notification *dirwatch) { if (dirwatch && dirwatch->signature == DIRWATCH_SIGNATURE) { int i; BOOL status; DWORD exit_code = 0, err = 0; /* Only the thread that issued the outstanding I/O call can call CancelIo on it. (CancelIoEx is available only since Vista.) So we need to queue an APC for the worker thread telling it to terminate. */ if (!QueueUserAPC (watch_end, dirwatch->thr, (ULONG_PTR)dirwatch->dir)) DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ())); /* We also signal the thread that it can terminate. */ SetEvent(dirwatch->terminate); /* Wait for the thread to exit. FIXME: is there a better method that is not overly complex? */ for (i = 0; i < 50; i++) { if (!((status = GetExitCodeThread (dirwatch->thr, &exit_code)) && exit_code == STILL_ACTIVE)) break; Sleep (10); } if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE) || exit_code == STILL_ACTIVE) { if (!(status == FALSE && err == ERROR_INVALID_HANDLE)) { DebPrint(("Forcing thread termination.\n")); TerminateThread (dirwatch->thr, 0); if (dirwatch->dir) CloseHandle (dirwatch->dir); } } /* Clean up. */ if (dirwatch->thr) { CloseHandle (dirwatch->thr); dirwatch->thr = NULL; } CloseHandle(dirwatch->terminate); xfree (dirwatch->buf); xfree (dirwatch->io_info); xfree (dirwatch->watchee); xfree (dirwatch); return 0; } else { DebPrint (("Unknown dirwatch object!\n")); return -1; } }
/* Stop watching a directory specified by a pointer to its dirwatch object. */ static int remove_watch (struct notification *dirwatch) { if (dirwatch && dirwatch->signature == DIRWATCH_SIGNATURE) { int i; BOOL status; DWORD exit_code, err; /* Only the thread that issued the outstanding I/O call can call CancelIo on it. (CancelIoEx is available only since Vista.) So we need to queue an APC for the worker thread telling it to terminate. */ if (!QueueUserAPC (watch_end, dirwatch->thr, (ULONG_PTR)dirwatch->dir)) DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ())); /* We also set the terminate flag, for when the thread is waiting on the critical section that never gets acquired. FIXME: is there a cleaner method? Using SleepEx there is a no-no, as that will lead to recursive APC invocations and stack overflow. */ dirwatch->terminate = 1; /* Wait for the thread to exit. FIXME: is there a better method that is not overly complex? */ for (i = 0; i < 50; i++) { if (!((status = GetExitCodeThread (dirwatch->thr, &exit_code)) && exit_code == STILL_ACTIVE)) break; Sleep (10); } if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE) || exit_code == STILL_ACTIVE) { if (!(status == FALSE && err == ERROR_INVALID_HANDLE)) { TerminateThread (dirwatch->thr, 0); if (dirwatch->dir) CloseHandle (dirwatch->dir); } } /* Clean up. */ if (dirwatch->thr) { CloseHandle (dirwatch->thr); dirwatch->thr = NULL; } xfree (dirwatch->buf); xfree (dirwatch->io_info); xfree (dirwatch->watchee); xfree (dirwatch); return 0; } else { DebPrint (("Unknown dirwatch object!\n")); return -1; } }
/* Free memory used by owner-drawn strings. */ static void w32_free_submenu_strings (HMENU menu) { int i, num = GetMenuItemCount (menu); for (i = 0; i < num; i++) { MENUITEMINFO info; memset (&info, 0, sizeof (info)); info.cbSize = sizeof (info); info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU; get_menu_item_info (menu, i, TRUE, &info); /* Owner-drawn names are held in dwItemData. */ if ((info.fType & MF_OWNERDRAW) && info.dwItemData) { #ifdef MENU_DEBUG DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData); #endif local_free (info.dwItemData); } /* Recurse down submenus. */ if (info.hSubMenu) w32_free_submenu_strings (info.hSubMenu); } }
void mmap_free (void **var) { if (*var) { if (VirtualFree (*var, 0, MEM_RELEASE) == 0) DebPrint (("mmap_free: error %ld\n", GetLastError ())); *var = NULL; } }
objID cGameWorld::GetGoodSpawnEnt() { /** * Step through the list of spawn ents. * choose the one that is farthest from * the rest of the players. */ list< cGamePlayerEnt* > players; ListPlayers( &players ); DebPrint( "found %d players", players.size() ); int nSpawnEnts = m_spawnEnts.size(); int best=0; float bestDist = 0.f; for( int i=0; i<nSpawnEnts; i++ ) { cGameEnt* pEnt = (cGameEnt*)MsgDaemon()->Get( m_spawnEnts[i] ); if( !pEnt ) { LogPrint("cGameWorld::GetGoodSpawnEnt: bad ID"); return -1; } list< cGamePlayerEnt* >::iterator iter; float bestCurrDist = 10000.f; for( iter = players.begin(); iter != players.end(); iter++ ) { float currDist = point3::Dist( (*iter)->GetLoc(), pEnt->GetLoc() ); if( currDist < bestCurrDist ) { bestCurrDist = currDist; } } // If this is the new best one, take it. if( bestCurrDist > bestDist ) { best = i; bestDist = bestCurrDist; } } // return the best one. return m_spawnEnts[ best ]; }
void * mmap_alloc (void **var, size_t nbytes) { void *p = NULL; /* We implement amortized allocation. We start by reserving twice the size requested and commit only the size requested. Then realloc could proceed and use the reserved pages, reallocating only if needed. Buffer shrink would happen only so that we stay in the 2x range. This is a big win when visiting compressed files, where the final size of the buffer is not known in advance, and the buffer is enlarged several times as the data is decompressed on the fly. */ if (nbytes < MAX_BUFFER_SIZE) p = VirtualAlloc (NULL, ROUND_UP (nbytes * 2, get_allocation_unit ()), MEM_RESERVE, PAGE_READWRITE); /* If it fails, or if the request is above 512MB, try with the requested size. */ if (p == NULL) p = VirtualAlloc (NULL, ROUND_UP (nbytes, get_allocation_unit ()), MEM_RESERVE, PAGE_READWRITE); if (p != NULL) { /* Now, commit pages for NBYTES. */ *var = VirtualAlloc (p, nbytes, MEM_COMMIT, PAGE_READWRITE); if (*var == NULL) p = *var; } if (!p) { DWORD e = GetLastError (); if (e == ERROR_NOT_ENOUGH_MEMORY) errno = ENOMEM; else { DebPrint (("mmap_alloc: error %ld\n", e)); errno = EINVAL; } } return *var = p; }
/* Worker routine for the watch thread. */ static DWORD WINAPI watch_worker (LPVOID arg) { struct notification *dirwatch = (struct notification *)arg; BOOL bErr; DWORD _bytes = 0; DWORD status; if (dirwatch->dir) { bErr = ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, DIRWATCH_BUFFER_SIZE, dirwatch->subtree, dirwatch->filter, &_bytes, dirwatch->io_info, watch_completion); if (!bErr) { DebPrint (("ReadDirectoryChangesW: %lu\n", GetLastError ())); /* We cannot remove the dirwatch object from watch_list, because we are in a separate thread. For the same reason, we also cannot free memory consumed by the buffers allocated for the dirwatch object. So we close the directory handle, but do not free the object itself or its buffers. We also don't touch the signature. This way, remove_watch can still identify the object, remove it, and free its memory. */ CloseHandle (dirwatch->dir); dirwatch->dir = NULL; return 1; } } do { status = WaitForSingleObjectEx(dirwatch->terminate, INFINITE, TRUE); } while (status == WAIT_IO_COMPLETION); /* The thread is about to terminate, so we clean up the dir handle. */ CloseHandle (dirwatch->dir); dirwatch->dir = NULL; return 0; }
/* Worker routine for the watch thread. */ static DWORD WINAPI watch_worker (LPVOID arg) { struct notification *dirwatch = (struct notification *)arg; do { BOOL status; DWORD sleep_result; DWORD bytes_ret = 0; if (dirwatch->dir) { status = ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, 16384, dirwatch->subtree, dirwatch->filter, &bytes_ret, dirwatch->io_info, watch_completion); if (!status) { DebPrint (("watch_worker, abnormal exit: %lu\n", GetLastError ())); /* We cannot remove the dirwatch object from watch_list, because we are in a separate thread. For the same reason, we also cannot free memory consumed by the buffers allocated for the dirwatch object. So we close the directory handle, but do not free the object itself or its buffers. We also don't touch the signature. This way, remove_watch can still identify the object, remove it, and free its memory. */ CloseHandle (dirwatch->dir); dirwatch->dir = NULL; return 1; } } /* Sleep indefinitely until awoken by the I/O completion, which could be either a change notification or a cancellation of the watch. */ sleep_result = SleepEx (INFINITE, TRUE); } while (!dirwatch->terminate); return 0; }
/* return code -1 means that event_queue_ptr won't be incremented. In other word, this event makes two key codes. (by himi) */ static int key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead) { static int mod_key_state = 0; int wParam; *isdead = 0; /* Skip key-up events. */ if (!event->bKeyDown) { switch (event->wVirtualKeyCode) { case VK_LWIN: mod_key_state &= ~LEFT_WIN_PRESSED; break; case VK_RWIN: mod_key_state &= ~RIGHT_WIN_PRESSED; break; case VK_APPS: mod_key_state &= ~APPS_PRESSED; break; } return 0; } /* Ignore keystrokes we fake ourself; see below. */ if (faked_key == event->wVirtualKeyCode) { faked_key = 0; return 0; } /* To make it easier to debug this code, ignore modifier keys! */ switch (event->wVirtualKeyCode) { case VK_LWIN: if (NILP (Vw32_pass_lwindow_to_system)) { /* Prevent system from acting on keyup (which opens the Start menu if no other key was pressed) by simulating a press of Space which we will ignore. */ if ((mod_key_state & LEFT_WIN_PRESSED) == 0) { if (NUMBERP (Vw32_phantom_key_code)) faked_key = XUINT (Vw32_phantom_key_code) & 255; else faked_key = VK_SPACE; keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0); } } mod_key_state |= LEFT_WIN_PRESSED; if (!NILP (Vw32_lwindow_modifier)) return 0; break; case VK_RWIN: if (NILP (Vw32_pass_rwindow_to_system)) { if ((mod_key_state & RIGHT_WIN_PRESSED) == 0) { if (NUMBERP (Vw32_phantom_key_code)) faked_key = XUINT (Vw32_phantom_key_code) & 255; else faked_key = VK_SPACE; keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0); } } mod_key_state |= RIGHT_WIN_PRESSED; if (!NILP (Vw32_rwindow_modifier)) return 0; break; case VK_APPS: mod_key_state |= APPS_PRESSED; if (!NILP (Vw32_apps_modifier)) return 0; break; case VK_CAPITAL: /* Decide whether to treat as modifier or function key. */ if (NILP (Vw32_enable_caps_lock)) goto disable_lock_key; return 0; case VK_NUMLOCK: /* Decide whether to treat as modifier or function key. */ if (NILP (Vw32_enable_num_lock)) goto disable_lock_key; return 0; case VK_SCROLL: /* Decide whether to treat as modifier or function key. */ if (NILP (Vw32_scroll_lock_modifier)) goto disable_lock_key; return 0; disable_lock_key: /* Ensure the appropriate lock key state is off (and the indicator light as well). */ wParam = event->wVirtualKeyCode; if (GetAsyncKeyState (wParam) & 0x8000) { /* Fake another press of the relevant key. Apparently, this really is the only way to turn off the indicator. */ faked_key = wParam; keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0), KEYEVENTF_EXTENDEDKEY | 0, 0); keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); } break; case VK_MENU: case VK_CONTROL: case VK_SHIFT: return 0; case VK_CANCEL: /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL, which is confusing for purposes of key binding; convert VK_CANCEL events into VK_PAUSE events. */ event->wVirtualKeyCode = VK_PAUSE; break; case VK_PAUSE: /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing for purposes of key binding; convert these back into VK_NUMLOCK events, at least when we want to see NumLock key presses. (Note that there is never any possibility that VK_PAUSE with Ctrl really is C-Pause as per above.) */ if (NILP (Vw32_enable_num_lock) && (event->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0) event->wVirtualKeyCode = VK_NUMLOCK; break; } /* Recognize state of Windows and Apps keys. */ event->dwControlKeyState |= mod_key_state; /* Distinguish numeric keypad keys from extended keys. */ event->wVirtualKeyCode = map_keypad_keys (event->wVirtualKeyCode, (event->dwControlKeyState & ENHANCED_KEY)); if (lispy_function_keys[event->wVirtualKeyCode] == 0) { if (!NILP (Vw32_recognize_altgr) && (event->dwControlKeyState & LEFT_CTRL_PRESSED) && (event->dwControlKeyState & RIGHT_ALT_PRESSED)) { /* Don't try to interpret AltGr key chords; ToAscii seems not to process them correctly. */ } /* Handle key chords including any modifiers other than shift directly, in order to preserve as much modifier information as possible. */ else if (event->dwControlKeyState & ( RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED | (!NILP (Vw32_lwindow_modifier) ? LEFT_WIN_PRESSED : 0) | (!NILP (Vw32_rwindow_modifier) ? RIGHT_WIN_PRESSED : 0) | (!NILP (Vw32_apps_modifier) ? APPS_PRESSED : 0) | (!NILP (Vw32_scroll_lock_modifier) ? SCROLLLOCK_ON : 0))) { /* Don't translate modified alphabetic keystrokes, so the user doesn't need to constantly switch layout to type control or meta keystrokes when the normal layout translates alphabetic characters to non-ascii characters. */ if ('A' <= event->wVirtualKeyCode && event->wVirtualKeyCode <= 'Z') { event->uChar.AsciiChar = event->wVirtualKeyCode; if ((event->dwControlKeyState & SHIFT_PRESSED) == 0) event->uChar.AsciiChar += ('a' - 'A'); } /* Try to handle unrecognized keystrokes by determining the base character (ie. translating the base key plus shift modifier). */ else if (event->uChar.AsciiChar == 0) w32_kbd_patch_key (event, -1); } if (event->uChar.AsciiChar == 0) { emacs_ev->kind = NO_EVENT; return 0; } else if (event->uChar.AsciiChar > 0) { /* Pure ASCII characters < 128. */ emacs_ev->kind = ASCII_KEYSTROKE_EVENT; emacs_ev->code = event->uChar.AsciiChar; } else if (event->uChar.UnicodeChar > 0 && w32_console_unicode_input) { /* Unicode codepoint; only valid if we are using Unicode console input mode. */ emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; emacs_ev->code = event->uChar.UnicodeChar; } else { /* Fallback handling of non-ASCII characters for non-Unicode versions of Windows, and for non-Unicode input on NT family of Windows. Only characters in the current console codepage are supported by this fallback. */ wchar_t code; char dbcs[2]; int cpId; /* Get the current console input codepage to interpret this key with. Note that the system defaults for the OEM codepage could have been changed by calling SetConsoleCP or w32-set-console-codepage, so using GetLocaleInfo to get LOCALE_IDEFAULTCODEPAGE is not TRT here. */ cpId = GetConsoleCP (); dbcs[0] = dbcs_lead; dbcs[1] = event->uChar.AsciiChar; if (dbcs_lead) { dbcs_lead = 0; if (!MultiByteToWideChar (cpId, 0, dbcs, 2, &code, 1)) { /* Garbage */ DebPrint (("Invalid DBCS sequence: %d %d\n", dbcs[0], dbcs[1])); emacs_ev->kind = NO_EVENT; } } else if (IsDBCSLeadByteEx (cpId, dbcs[1])) { dbcs_lead = dbcs[1]; emacs_ev->kind = NO_EVENT; } else { if (!MultiByteToWideChar (cpId, 0, &dbcs[1], 1, &code, 1)) { /* Garbage */ DebPrint (("Invalid character: %d\n", dbcs[1])); emacs_ev->kind = NO_EVENT; } } emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; emacs_ev->code = code; } } else { /* Function keys and other non-character keys. */ emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT; emacs_ev->code = event->wVirtualKeyCode; } XSETFRAME (emacs_ev->frame_or_window, get_frame ()); emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, event->wVirtualKeyCode); emacs_ev->timestamp = GetTickCount (); return 1; }
void * mmap_realloc (void **var, size_t nbytes) { MEMORY_BASIC_INFORMATION memInfo, m2; void *old_ptr; if (*var == NULL) return mmap_alloc (var, nbytes); /* This case happens in init_buffer(). */ if (nbytes == 0) { mmap_free (var); return mmap_alloc (var, nbytes); } memset (&memInfo, 0, sizeof (memInfo)); if (VirtualQuery (*var, &memInfo, sizeof (memInfo)) == 0) DebPrint (("mmap_realloc: VirtualQuery error = %ld\n", GetLastError ())); /* We need to enlarge the block. */ if (memInfo.RegionSize < nbytes) { memset (&m2, 0, sizeof (m2)); if (VirtualQuery ((char *)*var + memInfo.RegionSize, &m2, sizeof(m2)) == 0) DebPrint (("mmap_realloc: VirtualQuery error = %ld\n", GetLastError ())); /* If there is enough room in the current reserved area, then commit more pages as needed. */ if (m2.State == MEM_RESERVE && m2.AllocationBase == memInfo.AllocationBase && nbytes <= memInfo.RegionSize + m2.RegionSize) { void *p; p = VirtualAlloc (*var, nbytes, MEM_COMMIT, PAGE_READWRITE); if (!p /* && GetLastError() != ERROR_NOT_ENOUGH_MEMORY */) { DebPrint (("realloc enlarge: VirtualAlloc (%p + %I64x, %I64x) error %ld\n", *var, (uint64_t)memInfo.RegionSize, (uint64_t)(nbytes - memInfo.RegionSize), GetLastError ())); DebPrint (("next region: %p %p %I64x %x\n", m2.BaseAddress, m2.AllocationBase, (uint64_t)m2.RegionSize, m2.AllocationProtect)); } else return *var; } /* Else we must actually enlarge the block by allocating a new one and copying previous contents from the old to the new one. */ old_ptr = *var; if (mmap_alloc (var, nbytes)) { CopyMemory (*var, old_ptr, memInfo.RegionSize); mmap_free (&old_ptr); return *var; } else { /* We failed to reallocate the buffer. */ *var = old_ptr; return NULL; } } /* If we are shrinking by more than one page... */ if (memInfo.RegionSize > nbytes + getpagesize()) { /* If we are shrinking a lot... */ if ((memInfo.RegionSize / 2) > nbytes) { /* Let's give some memory back to the system and release some pages. */ old_ptr = *var; if (mmap_alloc (var, nbytes)) { CopyMemory (*var, old_ptr, nbytes); mmap_free (&old_ptr); return *var; } else { /* In case we fail to shrink, try to go on with the old block. But that means there is a lot of memory pressure. We could also decommit pages. */ *var = old_ptr; return *var; } } /* We still can decommit pages. */ if (VirtualFree ((char *)*var + nbytes + get_page_size(), memInfo.RegionSize - nbytes - get_page_size(), MEM_DECOMMIT) == 0) DebPrint (("mmap_realloc: VirtualFree error %ld\n", GetLastError ())); return *var; } /* Not enlarging, not shrinking by more than one page. */ return *var; }
void init_heap (bool use_dynamic_heap) { /* FIXME: Remove the condition, the 'else' branch below, and all the related definitions and code, including dumped_data[], when unexec support is removed from Emacs. */ if (use_dynamic_heap) { /* After dumping, use a new private heap. We explicitly enable the low fragmentation heap (LFH) here, for the sake of pre Vista versions. Note: this will harmlessly fail on Vista and later, where the low-fragmentation heap is enabled by default. It will also fail on pre-Vista versions when Emacs is run under a debugger; set _NO_DEBUG_HEAP=1 in the environment before starting GDB to get low fragmentation heap on XP and older systems, for the price of losing "certain heap debug options"; for the details see http://msdn.microsoft.com/en-us/library/windows/desktop/aa366705%28v=vs.85%29.aspx. */ data_region_end = data_region_base; /* Create the private heap. */ heap = HeapCreate (0, 0, 0); #ifndef MINGW_W64 unsigned long enable_lfh = 2; /* Set the low-fragmentation heap for OS before Vista. */ HMODULE hm_kernel32dll = LoadLibrary ("kernel32.dll"); HeapSetInformation_Proc s_pfn_Heap_Set_Information = (HeapSetInformation_Proc) get_proc_addr (hm_kernel32dll, "HeapSetInformation"); if (s_pfn_Heap_Set_Information != NULL) { if (s_pfn_Heap_Set_Information ((PVOID) heap, HeapCompatibilityInformation, &enable_lfh, sizeof(enable_lfh)) == 0) DebPrint (("Enabling Low Fragmentation Heap failed: error %ld\n", GetLastError ())); } #endif if (os_subtype == OS_9X) { the_malloc_fn = malloc_after_dump_9x; the_realloc_fn = realloc_after_dump_9x; the_free_fn = free_after_dump_9x; } else { the_malloc_fn = malloc_after_dump; the_realloc_fn = realloc_after_dump; the_free_fn = free_after_dump; } } else /* Before dumping with unexec: use static heap. */ { /* Find the RtlCreateHeap function. Headers for this function are provided with the w32 DDK, but the function is available in ntdll.dll since XP. */ HMODULE hm_ntdll = LoadLibrary ("ntdll.dll"); RtlCreateHeap_Proc s_pfn_Rtl_Create_Heap = (RtlCreateHeap_Proc) get_proc_addr (hm_ntdll, "RtlCreateHeap"); /* Specific parameters for the private heap. */ RTL_HEAP_PARAMETERS params; ZeroMemory (¶ms, sizeof(params)); params.Length = sizeof(RTL_HEAP_PARAMETERS); data_region_base = (unsigned char *)ROUND_UP (dumped_data, 0x1000); data_region_end = bc_limit = dumped_data + DUMPED_HEAP_SIZE; params.InitialCommit = committed = 0x1000; params.InitialReserve = sizeof(dumped_data); /* Use our own routine to commit memory from the dumped_data array. */ params.CommitRoutine = &dumped_data_commit; /* Create the private heap. */ if (s_pfn_Rtl_Create_Heap == NULL) { fprintf (stderr, "Cannot build Emacs without RtlCreateHeap being available; exiting.\n"); exit (-1); } heap = s_pfn_Rtl_Create_Heap (0, data_region_base, 0, 0, NULL, ¶ms); if (os_subtype == OS_9X) { fprintf (stderr, "Cannot dump Emacs on Windows 9X; exiting.\n"); exit (-1); } else { the_malloc_fn = malloc_before_dump; the_realloc_fn = realloc_before_dump; the_free_fn = free_before_dump; } } /* Update system version information to match current system. */ cache_system_info (); }
static int add_menu_item (HMENU menu, widget_value *wv, HMENU item) { UINT fuFlags; char *out_string, *p, *q; int return_value; size_t nlen, orig_len; USE_SAFE_ALLOCA; if (menu_separator_name_p (wv->name)) { fuFlags = MF_SEPARATOR; out_string = NULL; } else { if (wv->enabled) fuFlags = MF_STRING; else fuFlags = MF_STRING | MF_GRAYED; if (wv->key != NULL) { out_string = SAFE_ALLOCA (strlen (wv->name) + strlen (wv->key) + 2); p = stpcpy (out_string, wv->name); p = stpcpy (p, "\t"); strcpy (p, wv->key); } else out_string = (char *)wv->name; /* Quote any special characters within the menu item's text and key binding. */ nlen = orig_len = strlen (out_string); if (unicode_append_menu) { /* With UTF-8, & cannot be part of a multibyte character. */ for (p = out_string; *p; p++) { if (*p == '&') nlen++; } } #ifndef NTGUI_UNICODE else { /* If encoded with the system codepage, use multibyte string functions in case of multibyte characters that contain '&'. */ for (p = out_string; *p; p = _mbsinc (p)) { if (_mbsnextc (p) == '&') nlen++; } } #endif /* !NTGUI_UNICODE */ if (nlen > orig_len) { p = out_string; out_string = SAFE_ALLOCA (nlen + 1); q = out_string; while (*p) { if (unicode_append_menu) { if (*p == '&') *q++ = *p; *q++ = *p++; } #ifndef NTGUI_UNICODE else { if (_mbsnextc (p) == '&') { _mbsncpy (q, p, 1); q = _mbsinc (q); } _mbsncpy (q, p, 1); p = _mbsinc (p); q = _mbsinc (q); } #endif /* !NTGUI_UNICODE */ } *q = '\0'; } if (item != NULL) fuFlags = MF_POPUP; else if (wv->title || wv->call_data == 0) { /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since we can't deallocate the memory otherwise. */ if (get_menu_item_info) { out_string = (char *) local_alloc (strlen (wv->name) + 1); strcpy (out_string, wv->name); #ifdef MENU_DEBUG DebPrint ("Menu: allocating %ld for owner-draw", out_string); #endif fuFlags = MF_OWNERDRAW | MF_DISABLED; } else fuFlags = MF_DISABLED; } /* Draw radio buttons and tickboxes. */ else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE || wv->button_type == BUTTON_TYPE_RADIO)) fuFlags |= MF_CHECKED; else fuFlags |= MF_UNCHECKED; } if (unicode_append_menu && out_string) { /* Convert out_string from UTF-8 to UTF-16-LE. */ int utf8_len = strlen (out_string); WCHAR * utf16_string; if (fuFlags & MF_OWNERDRAW) utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR)); else utf16_string = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR)); utf8to16 ((unsigned char *)out_string, utf8_len, utf16_string); return_value = unicode_append_menu (menu, fuFlags, item != NULL ? (UINT_PTR) item : (UINT_PTR) wv->call_data, utf16_string); #ifndef NTGUI_UNICODE /* Fallback does not apply when always UNICODE */ if (!return_value) { /* On W9x/ME, Unicode menus are not supported, though AppendMenuW apparently does exist at least in some cases and appears to be stubbed out to do nothing. out_string is UTF-8, but since our standard menus are in English and this is only going to happen the first time a menu is used, the encoding is of minor importance compared with menus not working at all. */ return_value = AppendMenu (menu, fuFlags, item != NULL ? (UINT_PTR) item: (UINT_PTR) wv->call_data, out_string); /* Don't use Unicode menus in future, unless this is Windows NT or later, where a failure of AppendMenuW does NOT mean Unicode menus are unsupported. */ if (osinfo_cache.dwPlatformId != VER_PLATFORM_WIN32_NT) unicode_append_menu = NULL; } #endif /* NTGUI_UNICODE */ if (unicode_append_menu && (fuFlags & MF_OWNERDRAW)) local_free (out_string); } else { return_value = AppendMenu (menu, fuFlags, item != NULL ? (UINT_PTR) item : (UINT_PTR) wv->call_data, out_string ); } /* This must be done after the menu item is created. */ if (!wv->title && wv->call_data != 0) { if (set_menu_item_info) { MENUITEMINFO info; memset (&info, 0, sizeof (info)); info.cbSize = sizeof (info); info.fMask = MIIM_DATA; /* Set help string for menu item. Leave it as a pointer to a Lisp_String until it is ready to be displayed, since GC can happen while menus are active. */ if (!NILP (wv->help)) { /* We use XUNTAG below because in a 32-bit build --with-wide-int we cannot pass a Lisp_Object via a DWORD member of MENUITEMINFO. */ /* As of Jul-2012, w32api headers say that dwItemData has DWORD type, but that's a bug: it should actually be ULONG_PTR, which is correct for 32-bit and 64-bit Windows alike. MSVC headers get it right; hopefully, MinGW headers will, too. */ eassert (STRINGP (wv->help)); info.dwItemData = (ULONG_PTR) XUNTAG (wv->help, Lisp_String); } if (wv->button_type == BUTTON_TYPE_RADIO) { /* CheckMenuRadioItem allows us to differentiate TOGGLE and RADIO items, but is not available on NT 3.51 and earlier. */ info.fMask |= MIIM_TYPE | MIIM_STATE; info.fType = MFT_RADIOCHECK | MFT_STRING; info.dwTypeData = out_string; info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED; } set_menu_item_info (menu, item != NULL ? (UINT_PTR) item : (UINT_PTR) wv->call_data, FALSE, &info); } } SAFE_FREE (); return return_value; }
VOID CALLBACK watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info) { struct notification *dirwatch; DWORD _bytes; struct notifications_set *ns = NULL; BOOL terminate = FALSE; /* Who knows what happened? Perhaps the OVERLAPPED structure was freed by someone already? In any case, we cannot do anything with this request, so just punt and skip it. FIXME: should we raise the 'terminate' flag in this case? */ if (!io_info) { DebPrint(("watch_completion: io_info is null.\n")); return; } /* We have a pointer to our dirwatch structure conveniently stashed away in the hEvent member of the OVERLAPPED struct. According to MSDN documentation of ReadDirectoryChangesW: "The hEvent member of the OVERLAPPED structure is not used by the system, so you can use it yourself." */ dirwatch = (struct notification *)io_info->hEvent; if (status == ERROR_OPERATION_ABORTED) { /* We've been called because the main thread told us to issue CancelIo on the directory we watch, and watch_end did so. We must exit, without issuing another call to ReadDirectoryChangesW. */ return; } /* We allocate a new set of notifications to be linked to the linked list of notifications set. This will be processed by Emacs event loop in the main thread. We need to duplicate the notifications buffer, but not the dirwatch structure. */ /* Implementation note: In general, allocating memory in non-main threads is a no-no in Emacs. We certainly cannot call xmalloc and friends, because it can longjmp when allocation fails, which will crash Emacs because the jmp_buf is set up to a location on the main thread's stack. However, we can call 'malloc' directly, since that is redirected to HeapAlloc that uses our private heap, see w32heap.c, and that is thread-safe. */ ns = malloc (sizeof(struct notifications_set)); if (ns) { memset (ns, 0, sizeof(struct notifications_set)); ns->notifications = malloc (bytes_ret); if (ns->notifications) { memcpy (ns->notifications, dirwatch->buf, bytes_ret); ns->size = bytes_ret; ns->desc = dirwatch; } else { free (ns); ns = NULL; } } if (ns == NULL) DebPrint(("Out of memory. Notifications lost.")); /* Calling ReadDirectoryChangesW quickly to watch again for new notifications. */ if (!ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, DIRWATCH_BUFFER_SIZE, dirwatch->subtree, dirwatch->filter, &_bytes, dirwatch->io_info, watch_completion)) { DebPrint (("ReadDirectoryChangesW error: %lu\n", GetLastError ())); /* If this call fails, it means that the directory is not watchable any more. We need to terminate the worker thread. Still, we will wait until the current notifications have been sent to the main thread. */ terminate = TRUE; } if (ns) send_notifications(ns); /* If we were asked to terminate the thread, then fire the event. */ if (terminate) SetEvent(dirwatch->terminate); }
void cGameWorld::RunCollisionTests() { list< cGameEnt* >::iterator iter1, iter2; list< cGameEnt* >::iterator temp; for( iter1 = m_entList.begin(); iter1 != m_entList.end(); ++iter1 ) { /** * test each object against all of the objects above it. * This is a sucky way to do things ( O(n^2) ). A better * way would be to test each object only against the list * objects of the nearby cells. This wouldn't be too hard * to do, but is left as an exercise to the reader. Anyway, * since n will typically be < 10, we can waste a little time. */ /** * Early-out if iter1 doesn't hit objects. */ if( !(*iter1)->HitsObjects() ) { continue; } iter2 = iter1; iter2++; for( ; iter2 != m_entList.end(); ++iter2 ) { /** * Early-out if iter2 doesn't hit objects. */ if( !(*iter2)->HitsObjects() ) { continue; } /** * Do the objects collide? */ if( bSphere3::Intersect( (bSphere3&)(*iter1)->GetSphere(), (bSphere3&)(*iter2)->GetSphere() ) ) { // handle the collision. DebPrint("We had a collision!"); temp = iter1; temp--; if( 0 == (*iter1)->RespondToCollision( (*iter2) ) ) { // if we get in here, iter1 destroyed itself as a result // of the collision. (a rocket that hit a player, for // example). // fix iter1 and jump to the next iter1 step. iter1 = temp; goto iter1Died; } temp = iter2; temp--; if( 0 == (*iter2)->RespondToCollision( (*iter1) ) ) { // if we get in here, iter2 destroyed itself as a result // of the collision. (a rocket that hit a player, for // example). // fix iter2 and continue on. iter2 = temp; } } } // We jump to this label when iter1 kills itself in a collision. iter1Died: ; // sigh... } }