static ACODEC_TABLE *find_acodec_table_entry(const char *ext) { ACODEC_TABLE *ent; unsigned i; acodec_ensure_init(); for (i = 0; i < _al_vector_size(&acodec_table); i++) { ent = _al_vector_ref(&acodec_table, i); if (0 == stricmp(ent->ext, ext)) { return ent; } } return NULL; }
/* Tries to find the menu that has a child with the given id. If display * is not NULL, then it must also match. The first match is returned. */ _AL_MENU_ID *_al_find_parent_menu_by_id(ALLEGRO_DISPLAY *display, uint16_t unique_id) { _AL_MENU_ID *menu_id; size_t i; for (i = 0; i < _al_vector_size(&menu_ids); ++i) { menu_id = (_AL_MENU_ID *) _al_vector_ref(&menu_ids, i); if (menu_id->unique_id == unique_id) { if (!display || menu_id->menu->display == display) { return menu_id; } } } return NULL; }
static void shutdown_system_driver(void) { if (active_sysdrv) { if (active_sysdrv->user_exe_path) al_destroy_path(active_sysdrv->user_exe_path); if (active_sysdrv->vt && active_sysdrv->vt->shutdown_system) active_sysdrv->vt->shutdown_system(); active_sysdrv = NULL; while (!_al_vector_is_empty(&_al_system_interfaces)) _al_vector_delete_at(&_al_system_interfaces, _al_vector_size(&_al_system_interfaces)-1); _al_vector_free(&_al_system_interfaces); _al_vector_init(&_al_system_interfaces, sizeof(ALLEGRO_SYSTEM_INTERFACE *)); } al_destroy_config(sys_config); sys_config = NULL; }
static void recreate_textures(ALLEGRO_DISPLAY *display) { unsigned int i; for (i = 0; i < _al_vector_size(&display->bitmaps); i++) { ALLEGRO_BITMAP **bptr = _al_vector_ref(&display->bitmaps, i); ALLEGRO_BITMAP *bitmap = *bptr; int bitmap_flags = al_get_bitmap_flags(bitmap); if (bitmap->parent) continue; if (bitmap_flags & ALLEGRO_MEMORY_BITMAP) continue; if (bitmap_flags & ALLEGRO_NO_PRESERVE_TEXTURE) continue; _al_ogl_upload_bitmap_memory(bitmap, _al_get_bitmap_memory_format( bitmap), bitmap->memory); } }
/* Returns false if the glyph is invalid. */ static bool get_glyph(ALLEGRO_TTF_FONT_DATA *data, int ft_index, ALLEGRO_TTF_GLYPH_DATA **glyph) { ALLEGRO_TTF_GLYPH_RANGE *range; int32_t range_start; int lo, hi, mid; ASSERT(glyph); range_start = ft_index - (ft_index % RANGE_SIZE); /* Binary search for the range. */ lo = 0; hi = _al_vector_size(&data->glyph_ranges); mid = (hi + lo)/2; range = NULL; while (lo < hi) { ALLEGRO_TTF_GLYPH_RANGE *r = _al_vector_ref(&data->glyph_ranges, mid); if (r->range_start == range_start) { range = r; break; } else if (r->range_start < range_start) { lo = mid + 1; } else { hi = mid; } mid = (hi + lo)/2; } if (!range) { range = _al_vector_alloc_mid(&data->glyph_ranges, mid); range->range_start = range_start; range->glyphs = al_calloc(RANGE_SIZE, sizeof(ALLEGRO_TTF_GLYPH_DATA)); } *glyph = &range->glyphs[ft_index - range_start]; /* If we're skipping cache misses and it isn't already cached, return it as invalid. */ if (data->skip_cache_misses && !(*glyph)->page_bitmap && (*glyph)->region.x >= 0) { return false; } return ft_index != 0; }
static ALLEGRO_JOYSTICK_LINUX *ljoy_allocate_structure(void) { ALLEGRO_JOYSTICK_LINUX **slot; ALLEGRO_JOYSTICK_LINUX *joy; unsigned i; for (i = 0; i < _al_vector_size(&joysticks); i++) { slot = _al_vector_ref(&joysticks, i); joy = *slot; if (joy->config_state == LJOY_STATE_UNUSED) return joy; } joy = al_calloc(1, sizeof *joy); slot = _al_vector_alloc_back(&joysticks); *slot = joy; return joy; }
static ACODEC_TABLE *find_acodec_table_entry(const char *ext) { ACODEC_TABLE *ent; unsigned i; if (!acodec_inited) { acodec_inited = true; _al_add_exit_func(acodec_shutdown, "acodec_shutdown"); } for (i = 0; i < _al_vector_size(&acodec_table); i++) { ent = _al_vector_ref(&acodec_table, i); if (0 == _al_stricmp(ent->ext, ext)) { return ent; } } return NULL; }
static void xglx_shutdown_system(void) { ALLEGRO_SYSTEM *s = al_get_system_driver(); ALLEGRO_SYSTEM_XGLX *sx = (void *)s; ALLEGRO_INFO("shutting down.\n"); if (sx->x11display) { /* Events thread only runs if we are connected to an X server. */ _al_thread_join(&sx->thread); } /* Close all open displays. */ while (_al_vector_size(&s->displays) > 0) { ALLEGRO_DISPLAY **dptr = _al_vector_ref(&s->displays, 0); ALLEGRO_DISPLAY *d = *dptr; _al_destroy_display_bitmaps(d); al_destroy_display(d); } _al_vector_free(&s->displays); // Makes sure we wait for any commands sent to the X server when destroying the displays. // Should make sure we don't shutdown before modes are restored. if (sx->x11display) { XSync(sx->x11display, False); } _al_xsys_mmon_exit(sx); if (sx->x11display) { XCloseDisplay(sx->x11display); sx->x11display = None; ALLEGRO_DEBUG("xsys: close x11display.\n"); } if (sx->gfxdisplay) { /* XXX for some reason, crashes if both XCloseDisplay calls are made */ /* XCloseDisplay(sx->gfxdisplay); */ sx->gfxdisplay = None; } al_free(sx); }
/* Internal function: _al_register_destructor * Register OBJECT to be destroyed by FUNC during Allegro shutdown. * This would be done in the object's constructor function. * * [thread-safe] */ void _al_register_destructor(_AL_DTOR_LIST *dtors, char const *name, void *object, void (*func)(void*)) { int *dtor_owner_count; ASSERT(object); ASSERT(func); dtor_owner_count = _al_tls_get_dtor_owner_count(); if (*dtor_owner_count > 0) return; _al_mutex_lock(&dtors->mutex); { #ifdef DEBUGMODE /* make sure the object is not registered twice */ { unsigned int i; for (i = 0; i < _al_vector_size(&dtors->dtors); i++) { DTOR *dtor = _al_vector_ref(&dtors->dtors, i); ASSERT(dtor->object != object); } } #endif /* DEBUGMODE */ /* add the destructor to the list */ { DTOR *new_dtor = _al_vector_alloc_back(&dtors->dtors); if (new_dtor) { new_dtor->object = object; new_dtor->func = func; new_dtor->name = name; ALLEGRO_DEBUG("added dtor for %s %p, func %p\n", name, object, func); } else { ALLEGRO_WARN("failed to add dtor for %s %p\n", name, object); } } } _al_mutex_unlock(&dtors->mutex); }
/* Function: al_emit_user_event */ bool al_emit_user_event(ALLEGRO_EVENT_SOURCE *src, ALLEGRO_EVENT *event, void (*dtor)(ALLEGRO_USER_EVENT *)) { size_t num_queues; bool rc; ASSERT(src); ASSERT(event); ASSERT(ALLEGRO_EVENT_TYPE_IS_USER(event->any.type)); if (dtor) { ALLEGRO_USER_EVENT_DESCRIPTOR *descr = al_malloc(sizeof(*descr)); descr->refcount = 0; descr->dtor = dtor; event->user.__internal__descr = descr; } else { event->user.__internal__descr = NULL; } _al_event_source_lock(src); { ALLEGRO_EVENT_SOURCE_REAL *rsrc = (ALLEGRO_EVENT_SOURCE_REAL *)src; num_queues = _al_vector_size(&rsrc->queues); if (num_queues > 0) { event->user.timestamp = al_get_time(); _al_event_source_emit_event(src, event); rc = true; } else { rc = false; } } _al_event_source_unlock(src); if (dtor && !rc) { dtor(&event->user); al_free(event->user.__internal__descr); } return rc; }
/* Internal function: _al_event_source_emit_event * After an event structure has been filled in, it is time for the * event source to tell the event queues it knows of about the new * event. Afterwards, the caller of this function should not touch * the event any more. * * The event source must be _locked_ before calling this function. * * [runs in background threads] */ void _al_event_source_emit_event(ALLEGRO_EVENT_SOURCE *es, ALLEGRO_EVENT *event) { ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es; event->any.source = es; /* Push the event to all the queues that this event source is * registered to. */ { size_t num_queues = _al_vector_size(&this->queues); unsigned int i; ALLEGRO_EVENT_QUEUE **slot; for (i = 0; i < num_queues; i++) { slot = _al_vector_ref(&this->queues, i); _al_event_queue_push_event(*slot, event); } } }
/* Recursively walks over the entire menu structure, calling the user proc once per menu item, * and once per menu. The deepest menu is called first. If the proc returns true, then the * process terminates. It is not safe for the proc to modify the structure (add/remove items). */ bool _al_walk_over_menu(ALLEGRO_MENU *menu, bool (*proc)(ALLEGRO_MENU *menu, ALLEGRO_MENU_ITEM *item, int index, void *extra), void *extra) { ALLEGRO_MENU_ITEM **slot; size_t i; ASSERT(menu); ASSERT(proc); for (i = 0; i < _al_vector_size(&menu->items); ++i) { slot = _al_vector_ref(&menu->items, i); if ((*slot)->popup && _al_walk_over_menu((*slot)->popup, proc, extra)) return true; if (proc(menu, *slot, i, extra)) return true; } return proc(menu, NULL, -1, extra); }
static void xglx_shutdown_system(void) { ALLEGRO_SYSTEM *s = al_get_system_driver(); ALLEGRO_SYSTEM_XGLX *sx = (void *)s; ALLEGRO_INFO("shutting down.\n"); if (sx->have_xevents_thread) { _al_thread_join(&sx->xevents_thread); sx->have_xevents_thread = false; } /* Close all open displays. */ while (_al_vector_size(&s->displays) > 0) { ALLEGRO_DISPLAY **dptr = _al_vector_ref(&s->displays, 0); ALLEGRO_DISPLAY *d = *dptr; al_destroy_display(d); } _al_vector_free(&s->displays); // Makes sure we wait for any commands sent to the X server when destroying the displays. // Should make sure we don't shutdown before modes are restored. if (sx->x11display) { XSync(sx->x11display, False); } _al_xsys_mmon_exit(sx); if (sx->x11display) { XCloseDisplay(sx->x11display); sx->x11display = None; ALLEGRO_DEBUG("xsys: close x11display.\n"); } if (sx->gfxdisplay) { XCloseDisplay(sx->gfxdisplay); sx->gfxdisplay = None; } al_free(sx); }
void _al_sdl_display_event(SDL_Event *e) { ALLEGRO_EVENT event; event.display.timestamp = al_get_time(); ALLEGRO_DISPLAY *d = NULL; if (e->type == SDL_WINDOWEVENT) { d = _al_sdl_find_display(e->window.windowID); if (e->window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_IN; } if (e->window.event == SDL_WINDOWEVENT_FOCUS_LOST) { event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_OUT; } if (e->window.event == SDL_WINDOWEVENT_CLOSE) { event.display.type = ALLEGRO_EVENT_DISPLAY_CLOSE; } if (e->window.event == SDL_WINDOWEVENT_RESIZED) { event.display.type = ALLEGRO_EVENT_DISPLAY_RESIZE; event.display.width = e->window.data1; event.display.height = e->window.data2; } } if (e->type == SDL_QUIT) { event.display.type = ALLEGRO_EVENT_DISPLAY_CLOSE; /* Use the first display as event source if we have any displays. */ ALLEGRO_SYSTEM *s = al_get_system_driver(); if (_al_vector_size(&s->displays) > 0) { void **v = (void **)_al_vector_ref(&s->displays, 0); d = *v; } } if (!d) return; ALLEGRO_EVENT_SOURCE *es = &d->es; _al_event_source_lock(es); _al_event_source_emit_event(es, &event); _al_event_source_unlock(es); }
/* _al_kcm_stream_set_mutex: * This function sets a sample's mutex pointer to the specified value. It is * ALLEGRO_MIXER aware, and will recursively set any attached streams' mutex * to the same value. */ void _al_kcm_stream_set_mutex(ALLEGRO_SAMPLE_INSTANCE *stream, ALLEGRO_MUTEX *mutex) { ASSERT(stream); if (stream->mutex == mutex) return; stream->mutex = mutex; /* If this is a mixer, we need to make sure all the attached streams also * set the same mutex. */ if (stream->is_mixer) { ALLEGRO_MIXER *mixer = (ALLEGRO_MIXER *)stream; int i; for (i = _al_vector_size(&mixer->streams) - 1; i >= 0; i--) { ALLEGRO_SAMPLE_INSTANCE **slot = _al_vector_ref(&mixer->streams, i); ALLEGRO_SAMPLE_INSTANCE *spl = *slot; _al_kcm_stream_set_mutex(spl, mutex); } } }
/* Function: al_clone_path */ ALLEGRO_PATH *al_clone_path(const ALLEGRO_PATH *path) { ALLEGRO_PATH *clone; unsigned int i; ASSERT(path); clone = al_create_path(NULL); if (!clone) { return NULL; } al_ustr_assign(clone->drive, path->drive); al_ustr_assign(clone->filename, path->filename); for (i = 0; i < _al_vector_size(&path->segments); i++) { ALLEGRO_USTR **slot = _al_vector_alloc_back(&clone->segments); (*slot) = al_ustr_dup(get_segment(path, i)); } return clone; }
/* A helper function for al_clone_menu() and al_clone_menu_for_popup(). * Note that only the root menu is created as a "popup" (if popup == TRUE). */ static ALLEGRO_MENU *clone_menu(ALLEGRO_MENU *menu, bool popup) { ALLEGRO_MENU *clone = NULL; size_t i; if (menu) { clone = popup ? al_create_popup_menu() : al_create_menu(); for (i = 0; i < _al_vector_size(&menu->items); ++i) { const ALLEGRO_MENU_ITEM *item = *(ALLEGRO_MENU_ITEM **)_al_vector_ref(&menu->items, i); ALLEGRO_BITMAP *icon = item->icon; if (icon) icon = al_clone_bitmap(icon); al_append_menu_item(clone, item->caption ? al_cstr(item->caption) : NULL, item->id, item->flags, icon, al_clone_menu(item->popup)); } } return clone; }
/* _al_kcm_detach_from_parent: * This detaches the sample, stream, or mixer from anything it may be attached * to. */ void _al_kcm_detach_from_parent(ALLEGRO_SAMPLE_INSTANCE *spl) { ALLEGRO_MIXER *mixer; int i; if (!spl || !spl->parent.u.ptr) return; if (spl->parent.is_voice) { al_detach_voice(spl->parent.u.voice); return; } mixer = spl->parent.u.mixer; /* Search through the streams and check for this one */ for (i = _al_vector_size(&mixer->streams) - 1; i >= 0; i--) { ALLEGRO_SAMPLE_INSTANCE **slot = _al_vector_ref(&mixer->streams, i); if (*slot == spl) { maybe_lock_mutex(mixer->ss.mutex); _al_vector_delete_at(&mixer->streams, i); spl->parent.u.mixer = NULL; _al_kcm_stream_set_mutex(spl, NULL); if (spl->spl_read != _al_kcm_mixer_read) spl->spl_read = NULL; maybe_unlock_mutex(mixer->ss.mutex); break; } } free(spl->matrix); spl->matrix = NULL; }
static ALLEGRO_TTF_GLYPH_DATA *get_glyph(ALLEGRO_TTF_FONT_DATA *data, int ft_index) { ALLEGRO_TTF_GLYPH_RANGE *range; int32_t range_start; int lo, hi, mid; range_start = ft_index - (ft_index % RANGE_SIZE); /* Binary search for the range. */ lo = 0; hi = _al_vector_size(&data->glyph_ranges); mid = (hi + lo)/2; range = NULL; while (lo < hi) { ALLEGRO_TTF_GLYPH_RANGE *r = _al_vector_ref(&data->glyph_ranges, mid); if (r->range_start == range_start) { range = r; break; } else if (r->range_start < range_start) { lo = mid + 1; } else { hi = mid; } mid = (hi + lo)/2; } if (!range) { range = _al_vector_alloc_mid(&data->glyph_ranges, mid); range->range_start = range_start; range->glyphs = al_calloc(RANGE_SIZE, sizeof(ALLEGRO_TTF_GLYPH_DATA)); } return &range->glyphs[ft_index - range_start]; }
void _al_win_destroy_mouse_cursor(ALLEGRO_MOUSE_CURSOR *cursor) { ALLEGRO_MOUSE_CURSOR_WIN *win_cursor = (ALLEGRO_MOUSE_CURSOR_WIN *) cursor; ALLEGRO_SYSTEM *sys = al_get_system_driver(); unsigned i; ASSERT(win_cursor); /* XXX not at all thread safe */ for (i = 0; i < _al_vector_size(&sys->displays); i++) { ALLEGRO_DISPLAY_WIN **slot = _al_vector_ref(&sys->displays, i); ALLEGRO_DISPLAY_WIN *win_display = *slot; if (win_cursor->hcursor == win_display->mouse_selected_hcursor) { _al_win_set_system_mouse_cursor((ALLEGRO_DISPLAY *)win_display, ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW); } } DestroyIcon(win_cursor->hcursor); al_free(win_cursor); }
/* Function: al_join_paths */ bool al_join_paths(ALLEGRO_PATH *path, const ALLEGRO_PATH *tail) { unsigned i; ASSERT(path); ASSERT(tail); /* Don't bother concating if the tail is an absolute path. */ if (path_is_absolute(tail)) { return false; } /* We ignore tail->drive. The other option is to do nothing if tail * contains a drive letter. */ al_ustr_assign(path->filename, tail->filename); for (i = 0; i < _al_vector_size(&tail->segments); i++) { al_append_path_component(path, get_segment_cstr(tail, i)); } return true; }
/* Internal function: _al_unregister_destructor * Unregister a previously registered object. This must be called * in the normal object destroyer routine, e.g. al_destroy_timer. * * [thread-safe] */ void _al_unregister_destructor(_AL_DTOR_LIST *dtors, void *object) { ASSERT(object); _al_mutex_lock(&dtors->mutex); { unsigned int i; for (i = 0; i < _al_vector_size(&dtors->dtors); i++) { DTOR *dtor = _al_vector_ref(&dtors->dtors, i); if (dtor->object == object) { _al_vector_delete_at(&dtors->dtors, i); ALLEGRO_DEBUG("removed dtor for object %p\n", object); break; } } /* We cannot assert that the destructor was found because it might not * have been registered if the owner count was non-zero at the time. */ } _al_mutex_unlock(&dtors->mutex); }
static void xglx_shutdown_system(void) { /* Close all open displays. */ ALLEGRO_SYSTEM *s = al_get_system_driver(); ALLEGRO_SYSTEM_XGLX *sx = (void *)s; ALLEGRO_INFO("shutting down.\n"); _al_thread_join(&sx->thread); while (_al_vector_size(&s->displays) > 0) { ALLEGRO_DISPLAY **dptr = _al_vector_ref(&s->displays, 0); ALLEGRO_DISPLAY *d = *dptr; _al_destroy_display_bitmaps(d); al_destroy_display(d); } _al_vector_free(&s->displays); _al_xglx_free_mode_infos(sx); #ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA _al_xsys_xinerama_exit(sx); #endif if (sx->x11display) { XCloseDisplay(sx->x11display); sx->x11display = None; } if (sx->gfxdisplay) { /* XXX for some reason, crashes if both XCloseDisplay calls are made */ /* XCloseDisplay(sx->gfxdisplay); */ sx->gfxdisplay = None; } _AL_FREE(sx); }
/* Function: al_set_default_mixer */ bool al_set_default_mixer(ALLEGRO_MIXER *mixer) { ASSERT(mixer != NULL); if (mixer != default_mixer) { int i; default_mixer = mixer; /* Destroy all current sample instances, recreate them, and * attach them to the new mixer */ for (i = 0; i < (int) _al_vector_size(&auto_samples); i++) { ALLEGRO_SAMPLE_INSTANCE **slot = _al_vector_ref(&auto_samples, i); int *id = _al_vector_ref(&auto_sample_ids, i); *id = 0; al_destroy_sample_instance(*slot); *slot = al_create_sample_instance(NULL); if (!*slot) { ALLEGRO_ERROR("al_create_sample failed\n"); goto Error; } if (!al_attach_sample_instance_to_mixer(*slot, default_mixer)) { ALLEGRO_ERROR("al_attach_mixer_to_sample failed\n"); goto Error; } } } return true; Error: free_sample_vector(); default_mixer = NULL; return false; }
static bool wgl_resize_helper(ALLEGRO_DISPLAY *d, int width, int height) { ALLEGRO_DISPLAY_WGL *wgl_disp = (ALLEGRO_DISPLAY_WGL *)d; ALLEGRO_DISPLAY *ogl_disp = (ALLEGRO_DISPLAY *)d; ALLEGRO_DISPLAY_WIN *win_disp = (ALLEGRO_DISPLAY_WIN *)d; int full_w, full_h; ALLEGRO_MONITOR_INFO mi; int adapter = al_get_new_display_adapter(); if (adapter < 0) adapter = 0; al_get_monitor_info(adapter, &mi); full_w = mi.x2 - mi.x1; full_h = mi.y2 - mi.y1; if ((d->flags & ALLEGRO_FULLSCREEN_WINDOW) && (full_w != width || full_h != height)) { win_disp->toggle_w = width; win_disp->toggle_h = height; return true; } win_disp->can_acknowledge = false; if (d->flags & ALLEGRO_FULLSCREEN) { ALLEGRO_BITMAP *target_bmp; _AL_VECTOR disp_bmps; bool was_backbuffer = false; size_t i; target_bmp = al_get_target_bitmap(); if (target_bmp->vt) was_backbuffer = ((ALLEGRO_BITMAP_OGL*)target_bmp)->is_backbuffer; /* Remeber display bitmaps. */ _al_vector_init(&disp_bmps, sizeof(ALLEGRO_BITMAP*)); for (i = 0; i < _al_vector_size(&d->bitmaps); i++) { ALLEGRO_BITMAP **dis = _al_vector_ref(&d->bitmaps, i); ALLEGRO_BITMAP **mem = _al_vector_alloc_back(&disp_bmps); *mem = *dis; } /* This flag prevents from switching to desktop resolution in between. */ _wgl_do_not_change_display_mode = true; destroy_display_internals(wgl_disp); _wgl_do_not_change_display_mode = false; d->w = width; d->h = height; if (!create_display_internals(wgl_disp)) return false; /* Reupload bitmaps. */ while (_al_vector_is_nonempty(&disp_bmps)) { ALLEGRO_BITMAP **back = _al_vector_ref_back(&disp_bmps); _al_convert_to_display_bitmap(*back); _al_vector_delete_at(&disp_bmps, _al_vector_size(&disp_bmps) - 1); } /* We have a new backbuffer now. */ if (was_backbuffer) al_set_target_bitmap(al_get_backbuffer(d)); } else { RECT win_size; WINDOWINFO wi; win_size.left = 0; win_size.top = 0; win_size.right = width; win_size.bottom = height; wi.cbSize = sizeof(WINDOWINFO); GetWindowInfo(win_disp->window, &wi); AdjustWindowRectEx(&win_size, wi.dwStyle, false, wi.dwExStyle); if (!SetWindowPos(win_disp->window, HWND_TOP, 0, 0, win_size.right - win_size.left, win_size.bottom - win_size.top, SWP_NOMOVE|SWP_NOZORDER)) return false; PostMessage(win_disp->window, WM_USER+0, 0, 0); d->w = width; d->h = height; if (!(d->flags & ALLEGRO_FULLSCREEN_WINDOW)) { win_disp->toggle_w = width; win_disp->toggle_h = height; } _al_ogl_resize_backbuffer(ogl_disp->ogl_extras->backbuffer, width, height); setup_gl(d); } return true; }
/* circ_array_next: * Return the next index in a circular array. */ static unsigned int circ_array_next(const _AL_VECTOR *vector, unsigned int i) { return (i + 1) % _al_vector_size(vector); }
static void ljoy_scan(bool configure) { int fd; ALLEGRO_JOYSTICK_LINUX *joy, **joypp; int num; ALLEGRO_USTR *device_name; unsigned i; /* Clear mark bits. */ for (i = 0; i < _al_vector_size(&joysticks); i++) { joypp = _al_vector_ref(&joysticks, i); joy = *joypp; joy->marked = false; } device_name = al_ustr_new(""); /* This is a big number, but there can be gaps and other unrelated event * device files. Perhaps it would be better to use glob() here. */ for (num = 0; num < 32; num++) { if (!ljoy_detect_device_name(num, device_name)) continue; joy = ljoy_by_device_name(device_name); if (joy) { ALLEGRO_DEBUG("Device %s still exists\n", al_cstr(device_name)); joy->marked = true; continue; } /* Try to open the device. The device must be opened in O_RDWR mode to * allow writing of haptic effects! The haptic driver for linux * reuses the joystick driver's fd. */ fd = open(al_cstr(device_name), O_RDWR|O_NONBLOCK); if (fd == -1) { ALLEGRO_WARN("Failed to open device %s\n", al_cstr(device_name)); continue; } /* The device must have at least one joystick-related axis, and one * joystick-related button. Some devices, such as mouse pads, have ABS_X * and ABS_Y axes like a joystick but not joystick-related buttons. By * checking for both axes and buttons, such devices can be excluded. */ if (!have_joystick_button(fd) || !have_joystick_axis(fd)) { ALLEGRO_DEBUG("Device %s not a joystick\n", al_cstr(device_name)); close(fd); continue; } ALLEGRO_DEBUG("Device %s is new\n", al_cstr(device_name)); joy = ljoy_allocate_structure(); joy->fd = fd; joy->device_name = al_ustr_dup(device_name); joy->config_state = LJOY_STATE_BORN; joy->marked = true; config_needs_merging = true; if (ioctl(fd, EVIOCGNAME(sizeof(joy->name)), joy->name) < 0) strcpy(joy->name, "Unknown"); /* Map Linux input API axis and button numbers to ours, and fill in * information. */ if (!fill_joystick_axes(joy, fd) || !fill_joystick_buttons(joy, fd)) { ALLEGRO_ERROR("fill_joystick_info failed %s\n", al_cstr(device_name)); inactivate_joy(joy); close(fd); continue; } /* Register the joystick with the fdwatch subsystem. */ _al_unix_start_watching_fd(joy->fd, ljoy_process_new_data, joy); } al_ustr_free(device_name); /* Schedule unmarked structures to be inactivated. */ for (i = 0; i < _al_vector_size(&joysticks); i++) { joypp = _al_vector_ref(&joysticks, i); joy = *joypp; if (joy->config_state == LJOY_STATE_ALIVE && !joy->marked) { ALLEGRO_DEBUG("Device %s to be inactivated\n", al_cstr(joy->device_name)); joy->config_state = LJOY_STATE_DYING; config_needs_merging = true; } } /* Generate a configure event if necessary. * Even if we generated one before that the user hasn't responded to, * we don't know if the user received it so always generate it. */ if (config_needs_merging && configure) { ljoy_generate_configure_event(); } }
/* Function: al_insert_menu_item */ int al_insert_menu_item(ALLEGRO_MENU *parent, int pos, char const *title, uint16_t id, int flags, ALLEGRO_BITMAP *icon, ALLEGRO_MENU *submenu) { ALLEGRO_MENU_ITEM *item; ALLEGRO_MENU_ITEM **slot; _AL_MENU_ID *menu_id; size_t i; ASSERT(parent); /* If not found, then treat as an append. */ if (!interpret_menu_id_param(&parent, &pos)) pos = _al_vector_size(&parent->items); /* At this point pos == the _index_ of where to insert */ /* The sub-menu must not already be in use. */ if (submenu && (submenu->display || submenu->parent || submenu->is_popup_menu)) return -1; item = create_menu_item(title, id, flags, submenu); if (!item) return -1; item->parent = parent; set_item_icon(item, icon); i = (size_t) pos; if (i >= _al_vector_size(&parent->items)) { /* Append */ i = _al_vector_size(&parent->items); slot = _al_vector_alloc_back(&parent->items); } else { /* Insert */ slot = _al_vector_alloc_mid(&parent->items, i); } if (!slot) { destroy_menu_item(item); return -1; } *slot = item; if (submenu) { submenu->parent = item; if (parent->display) _al_walk_over_menu(submenu, set_menu_display_r, parent->display); } _al_insert_menu_item_at(item, (int) i); if (id) { /* Append the menu's ID to the search vector */ menu_id = (_AL_MENU_ID *) _al_vector_alloc_back(&menu_ids); menu_id->unique_id = item->unique_id; menu_id->id = id; menu_id->menu = parent; } return (int) i; }
/* Function: al_set_display_menu */ bool al_set_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu) { DISPLAY_MENU *dm = NULL; size_t i; int menu_height = _al_get_menu_display_height(); bool automatic_menu_display_resize = true; const char* automatic_menu_display_resize_value = al_get_config_value(al_get_system_config(), "compatibility", "automatic_menu_display_resize"); if (automatic_menu_display_resize_value && strcmp(automatic_menu_display_resize_value, "false") == 0) automatic_menu_display_resize = false; ASSERT(display); /* Check if this display has a menu associated with it */ for (i = 0; i < _al_vector_size(&display_menus); ++i) { dm = (DISPLAY_MENU *) _al_vector_ref(&display_menus, i); if (dm->display == display) break; } /* If no display was found, reset dm to NULL */ if (i == _al_vector_size(&display_menus)) dm = NULL; if (!menu) { /* Removing the menu */ if (!dm) return false; _al_hide_display_menu(display, dm->menu); _al_walk_over_menu(dm->menu, set_menu_display_r, NULL); _al_vector_delete_at(&display_menus, i); if (automatic_menu_display_resize && menu_height > 0) { display->extra_resize_height = 0; al_resize_display(display, al_get_display_width(display), al_get_display_height(display)); } } else { /* Setting the menu. It must not currently be attached to any * display, and it cannot have a parent menu. */ if (menu->display || menu->parent) return false; if (dm) { /* hide the existing menu */ _al_hide_display_menu(display, dm->menu); _al_walk_over_menu(dm->menu, set_menu_display_r, NULL); } if (!_al_show_display_menu(display, menu)) { /* Unable to set the new menu, but already have hidden the * previous one, so delete the display_menus slot. */ if (dm) _al_vector_delete_at(&display_menus, i); return false; } /* Set the entire menu tree as owned by the display */ _al_walk_over_menu(menu, set_menu_display_r, display); if (!dm) dm = _al_vector_alloc_back(&display_menus); if (automatic_menu_display_resize && menu_height > 0) { /* Temporarily disable the constraints so we don't send a RESIZE_EVENT. */ bool old_constraints = display->use_constraints; display->use_constraints = false; display->extra_resize_height = menu_height; al_resize_display(display, al_get_display_width(display), al_get_display_height(display)); display->use_constraints = old_constraints; } dm->display = display; dm->menu = menu; } return true; }
/* joydx_init_joystick: [primary thread] * * Initialises the DirectInput joystick devices. * * To avoid enumerating the the joysticks over and over, this does * the enumeration once and does almost all the setting up required * of the devices. joydx_get_joystick() is left with very little work * to do. */ static bool joydx_init_joystick(void) { HRESULT hr; ALLEGRO_SYSTEM *system; size_t i; MAKE_UNION(&joystick_dinput, LPDIRECTINPUT *); ASSERT(!joystick_dinput); ASSERT(!joydx_num_joysticks); ASSERT(!joydx_thread); ASSERT(!STOP_EVENT); /* load DirectInput module */ _al_dinput_module = _al_win_safe_load_library(_al_dinput_module_name); if (_al_dinput_module == NULL) { ALLEGRO_ERROR("Failed to open '%s' library\n", _al_dinput_module_name); joystick_dinput = NULL; return false; } /* import DirectInput create proc */ _al_dinput_create = (DIRECTINPUT8CREATEPROC)GetProcAddress(_al_dinput_module, "DirectInput8Create"); if (_al_dinput_create == NULL) { ALLEGRO_ERROR("DirectInput8Create not in %s\n", _al_dinput_module_name); FreeLibrary(_al_dinput_module); joystick_dinput = NULL; return false; } /* get the DirectInput interface */ hr = _al_dinput_create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, &__al_IID_IDirectInput8A, u.v, NULL); if (FAILED(hr)) { ALLEGRO_ERROR("Failed to create DirectInput interface\n"); FreeLibrary(_al_dinput_module); joystick_dinput = NULL; return false; } /* initialise the lock for the background thread */ InitializeCriticalSection(&joydx_thread_cs); // This initializes present joystick state joydx_scan(false); // This copies present state to user state joydx_merge(); /* create the dedicated thread stopping event */ STOP_EVENT = CreateEvent(NULL, false, false, NULL); /* If one of our windows is the foreground window make it grab the input. */ system = al_get_system_driver(); for (i = 0; i < _al_vector_size(&system->displays); i++) { ALLEGRO_DISPLAY_WIN **pwin_disp = _al_vector_ref(&system->displays, i); ALLEGRO_DISPLAY_WIN *win_disp = *pwin_disp; if (win_disp->window == GetForegroundWindow()) { _al_win_wnd_call_proc(win_disp->window, _al_win_joystick_dinput_grab, win_disp); } } /* start the background thread */ joydx_thread = (HANDLE) _beginthreadex(NULL, 0, joydx_thread_proc, NULL, 0, NULL); return true; }