Пример #1
0
/**
 * \brief Draws a string to the display
 *
 * This function will draw a string located in memory to the display.
 *
 * \param str         Pointer to string
 * \param x           X coordinate on screen.
 * \param y           Y coordinate on screen.
 * \param font        Font to draw string in
 * \param bg_color    Background color to draw behind the text string
 * \param text_color  Foreground color to draw the text string in
 */
void gfx_draw_string(const char *str, gfx_coord_t x, gfx_coord_t y,
		const struct font *font, const gfx_color_t bg_color,
		const gfx_color_t text_color)
{
	gfx_draw_string_aligned(str, x, y, font, bg_color, text_color,
			TEXT_POS_LEFT, TEXT_ALIGN_LEFT);
}
Пример #2
0
/**
 * \brief Draws the special function pallet entry text labels
 *
 * This function draws the special function pallet entry text labels to the
 * appropriate positions on the display.
 *
 * \param clearing_display   True if the display is currently being cleared
 */
static void draw_pallet_labels(const bool clearing_display)
{
	/* Draw multi-color mode text label to the appropriate pallet entry */
	gfx_draw_string_aligned("MUL",
			PALLET_COLOR_WIDTH / 2,
			gfx_get_height() - (PALLET_HEIGHT / 2), &sysfont,
			GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE,
			TEXT_POS_CENTER, TEXT_ALIGN_LEFT);

	/* Draw display clear text label to the appropriate pallet entry */
	gfx_draw_string_aligned("CLR",
			(PALLET_COLOR_WIDTH * NUM_PALLET_COLORS) - (PALLET_COLOR_WIDTH / 2),
			gfx_get_height() - (PALLET_HEIGHT / 2), &sysfont,
			GFX_COLOR_TRANSPARENT,
			clearing_display ? GFX_COLOR_RED : GFX_COLOR_WHITE,
			TEXT_POS_CENTER, TEXT_ALIGN_LEFT);
}
Пример #3
0
void draw_time() {
    unsigned long ts = rtc_get_time();
    struct calendar_date rtc_date;
    uint8_t hour[] = {12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
    // might need to build in something for daylight savings time
    calendar_timestamp_to_date_tz(ts, -6, 0, &rtc_date);
    char string_buf[15];

    snprintf(string_buf, sizeof(string_buf),"%d:%.2d", hour[rtc_date.hour], rtc_date.minute);
    gfx_draw_string_aligned(string_buf, gfx_get_width()-35, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_CENTER_X, TEXT_ALIGN_LEFT);
}
Пример #4
0
/**
 * \brief Show an out of memory error on the display
 *
 * Shows a full screen error when called, signaling that the system
 * ran out of memory when initializing a WTK application.
 */
static void show_out_of_memory_error(void)
{
	const char memory_string[] = "OUT OF MEMORY";
	gfx_coord_t disp_width, disp_height;

	/* Get the display width and height */
	disp_width  = gfx_get_width();
	disp_height = gfx_get_height();

	/* Blank display */
	gfx_set_clipping(0, 0, disp_width, disp_height);
	gfx_draw_filled_rect(0, 0, disp_width, disp_height, GFX_COLOR_BLACK);

	/* Show centered out of memory error text */
	gfx_draw_string_aligned(memory_string,
		disp_width / 2, disp_height / 2,
		&sysfont,
		GFX_COLOR_TRANSPARENT, GFX_COLOR_RED,
		TEXT_POS_CENTER, TEXT_ALIGN_CENTER);
}
Пример #5
0
/**
 * \brief Main application loop
 *
 * This is the main application function, which runs all the initialization
 * code, clears the display and enters a loop in which it continuously polls
 * for new messages from the maXTouch device. If one or more messages are
 *  pending, the maXTouch message handler is invoked.
 */
int main(void)
{
	/* maXTouch data structure */
	static struct mxt_device device;

	/* Basic init routines */
	board_init();
	sysclk_init();
	gfx_init();
	mxt_init(&device);

	/* Draw the paint pallet to the display */
	draw_paint_pallet();

	/* Draw instructions to the display */
	gfx_draw_string_aligned(
			"Select a color from the pallet below, and\n"
			"use your finger(s) to draw onto the display.\n\n"
			"Multiple simultaneous fingers are supported,\n"
			"and the drawing size varies according to the\n"
			"pressure of the touch.\n\n"
			"Select MUL to draw using multiple colors.\n\n"
			"Select CLR to clear the display.",
			gfx_get_width() / 2,
			(gfx_get_height() - PALLET_HEIGHT) / 2,
			&sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE,
			TEXT_POS_CENTER, TEXT_ALIGN_LEFT);

	while (true) {
		/* Check for any pending messages and run message handler if any
		 * message is found in the queue */
		if (mxt_is_message_pending(&device)) {
			mxt_handler(&device);
		}
	}
}
Пример #6
0
void network_application() {
	draw_background();
    gfx_draw_filled_rect(5, 26, 310, 182, GFX_COLOR(20, 20, 20));

    if(!wifi_ready && wifi_error) {
        gfx_draw_string_aligned(SYMFONT_WIFI, gfx_get_width() / 2, 120, &symbol_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_RED, TEXT_POS_CENTER_X, TEXT_ALIGN_CENTER);
        gfx_draw_string_aligned("Not Connected", gfx_get_width() / 2, 155, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_RED, TEXT_POS_CENTER_X, TEXT_ALIGN_CENTER);
    } else {
        gfx_draw_string_aligned(SYMFONT_WIFI, gfx_get_width() / 2, 120, &symbol_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_GREEN, TEXT_POS_CENTER_X, TEXT_ALIGN_CENTER);
        gfx_draw_string_aligned("Connected", gfx_get_width() / 2, 155, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_GREEN, TEXT_POS_CENTER_X, TEXT_ALIGN_CENTER);
    }

    uint8_t ram_buf[AT45DBX_SECTOR_SIZE];
    
    at45dbx_read_sector_open(0x0007);
    at45dbx_read_sector_to_ram(ram_buf);
    at45dbx_read_close();
    char mac_string[128];
    snprintf(mac_string, sizeof(mac_string), "MAC: %s", ram_buf);
    gfx_draw_string_aligned(mac_string, 11, 27, &small_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);

    if (wifi_error) {
         gfx_draw_string_aligned(esp_error, 11, 47, &small_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);
    }

	struct keyboard_event input;
    while(mma8451_orientation() != 6) {
        esp8266_check_buffer();

        keyboard_get_key_state(&input);
        if (input.type == KEYBOARD_RELEASE) {
            if (input.keycode == KEYBOARD_B) {
                break;
            }
        }
        if(mma8451_clear_interrupt() && is_low_power()) {
            exit_low_power();
        }
    }
}
Пример #7
0
void draw_event() {
    draw_background();
    draw_time();
    gfx_draw_filled_rect(5, 26, 310, 182, GFX_COLOR(8, 8, 8));
    draw_button_hints();

    switch(event_track) {
        case 0:
            gfx_draw_string_aligned("Schedule - KEYNOTES",    11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);
            break;
        case 1:
            gfx_draw_string_aligned("Schedule - TRACK 1",    11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);
            break;
        case 2:
            gfx_draw_string_aligned("Schedule - TRACK 2",    11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);
            break;
        case 3:
            gfx_draw_string_aligned("Schedule - TRACK 3",    11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);
            break;
        case 4:
            gfx_draw_string_aligned("Schedule - TRACK 4",    11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);
            break;
        case 5:
            gfx_draw_string_aligned("Schedule - TRACK 5",    11, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);
            break;
    }
    
    uint16_t keynote = 0x0100;
    uint16_t track1 = 0x0200;
    uint16_t track2 = 0x0300;
    uint16_t track3 = 0x0400;
    uint16_t track4 = 0x0500;
    uint16_t track5 = 0x0600;

    uint16_t addresses[] = {keynote, track1, track2, track3, track4, track5};
    //uint16_t max_event[] = {5, 22, 22, 15, 23};

    uint8_t ram_buf[AT45DBX_SECTOR_SIZE];
    at45dbx_read_sector_open(addresses[event_track] + event_index);
    at45dbx_read_sector_to_ram(ram_buf);
    at45dbx_read_close();

    char *array[6];
    uint8_t i = 0;
    array[i] = strtok(ram_buf,";");
    while(array[i] != NULL) {
        array[++i] = strtok(NULL, ";");
    }

    char *title[256];
    uint8_t a = word_wrap(&title, array[0], 30);

    gfx_draw_string_aligned(title, 11, 27, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);

    char event_time[36];
    snprintf(event_time, sizeof(event_time),"%s - %s", array[1], array[2]);
        
    char *names[256];
    uint8_t n = word_wrap(&names, array[3], 33);

        gfx_draw_string_aligned(names, 11, 60+(a*20), &small_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_RED, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);

        gfx_draw_string_aligned(array[4], 11, 85+(a*20)+(n*20), &tiny_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_YELLOW, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);
        gfx_draw_string_aligned(event_time, 11, 100+(a*20)+(n*20), &tiny_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);
        
        
    // }
}
/**
 * \brief Main application function
 *
 * This function ensures that the hardware and drivers are initialized before
 * entering an infinite work loop.
 *
 * In the work loop, the maXTouch device is polled for new touch events and any
 * new event is passed on to the user interface implementation for processing.
 * The loop then attempts to enter sleep.
 *
 * The user interface processing itself is not started by the work loop, but by
 * the USB callback function for start of frame.
 */
int main(void)
{
#ifdef USB_DEVICE_LOW_SPEED
	uint16_t virtual_sof_sub;
	uint16_t virtual_sof;
#endif

	/* maXTouch data structure */
	static struct mxt_device device;

	/* Initialize system clocks */
	sysclk_init();

	/* Initialize interrupt vectors */
	irq_initialize_vectors();

	/* Enable interrupts */
	cpu_irq_enable();

	/* Initialize the sleep manager */
	sleepmgr_init();

	/* Initialize the board */
	board_init();

	/* Initialize the mXT touch device */
	mxt_init(&device);

	/* Initialize the graphical library */
	gfx_init();

	/* Set correct landscape orientation */
	gfx_set_orientation(GFX_SWITCH_XY | GFX_FLIP_Y);

	/* Set background color */
	gfx_draw_filled_rect(0, 0, gfx_get_width(), gfx_get_height(),
			COLOR_BACKGROUND);

	/* Draw the help text */
	gfx_draw_string_aligned(
			"Middle finger to move cursor\n"
			"Index finger to left click\n"
			"Ring finger to right click",
			gfx_get_width() / 2, gfx_get_height() / 2,
			&sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE,
			TEXT_POS_CENTER, TEXT_ALIGN_CENTER);

	/* Initialize the user interface */
	ui_init();
	ui_powerdown();

	/* Start USB stack to authorize VBus monitoring */
	udc_start();

	/* Check if there are any new touch data pending */
	while (true) {
		if (mxt_is_message_pending(&device)) {
			if (mxt_read_touch_event(&device, &ui_touch_event) == STATUS_OK) {
				ui_flag_new_touch_event();
			}
		}

		/* Try to sleep */
		sleepmgr_enter_sleep();

#ifdef USB_DEVICE_LOW_SPEED
		/* No USB "Keep alive" interrupt available in low speed
		 * to scan mouse interface then use main loop */
		if (main_b_mouse_enable) {
			virtual_sof_sub = 0;
			virtual_sof = 0;
			if (virtual_sof_sub++ == 700) {
				virtual_sof_sub = 0;
				ui_process(virtual_sof++);
			}
		}
#endif
	}
}
Пример #9
0
void battery_application() {
    draw_background();



    gfx_draw_string_aligned("Power Info", gfx_get_width() / 2, 2, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_CENTER_X, TEXT_ALIGN_LEFT);

    uint8_t battery = max1704x_bat();
    char batlvl[5];
    if (battery > 100) {
        battery = 100;
    }
    //battery = 19;
    uint16_t x =  75;
    uint16_t y = 40;

    gfx_draw_rect(x, y,  164, 54, GFX_COLOR_WHITE);
    gfx_draw_filled_rect(x+164, y+15, 3, 20, GFX_COLOR_WHITE);

    if (battery < 20) {
        gfx_draw_filled_rect(x+2, y+2, battery/6 * 10, 50, GFX_COLOR_RED);
    } else {
        gfx_draw_filled_rect(x+2, y+2, battery/6 * 10, 50, GFX_COLOR_GREEN);
    }


    snprintf(batlvl, sizeof(batlvl), "%d%%", battery);
    if (battery > 20) {
        gfx_draw_string_aligned(batlvl, gfx_get_width() /2, 50, &large_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_CENTER_X, TEXT_ALIGN_LEFT);
    } else {
        gfx_draw_string_aligned(batlvl, gfx_get_width() /2, 50, &large_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_CENTER_X, TEXT_ALIGN_LEFT);
    }

    char atime[32];
    snprintf(atime, sizeof(atime), "Seconds Awake:    %lu", get_time_awake());
    gfx_draw_string_aligned(atime, 70, 100, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);

    char stime[32];
    snprintf(stime, sizeof(stime), "Seconds Sleeping: %lu", get_time_sleep());
    gfx_draw_string_aligned(stime, 70, 120, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_LEFT, TEXT_ALIGN_LEFT);

    gfx_draw_filled_circle(gfx_get_width() /2,  80+80+10+10, 25, GFX_COLOR_WHITE, GFX_WHOLE);
    gfx_draw_string_aligned(SYMFONT_MOON, gfx_get_width() /2, 152+10, &symbol_sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR(200, 101, 18), TEXT_POS_CENTER_X, TEXT_ALIGN_CENTER);
    gfx_draw_string_aligned("Enter Sleep Mode", gfx_get_width() / 2, 152+15+30+15, &sysfont, GFX_COLOR_TRANSPARENT, GFX_COLOR_WHITE, TEXT_POS_CENTER_X, TEXT_ALIGN_LEFT);


	struct keyboard_event input;
    while(mma8451_orientation() != 6) {
        esp8266_check_buffer();
        if(mma8451_clear_interrupt() && is_low_power()) {
            exit_low_power();
        }

        keyboard_get_key_state(&input);
        if (input.type == KEYBOARD_RELEASE) {
            if (input.keycode == KEYBOARD_B) {
                break;
            } else if (input.keycode == KEYBOARD_A) {
                esp8266_enter_standby();
                enter_low_power();
                break;
            }
        }
    }
}
Пример #10
0
/**
 * \brief Starts the calibration routines and displays user instructions on screen.
 *
 * \return 0 if calibration is successful, else 1.
 */
uint32_t rtouch_calibrate(void)
{
	uint32_t i;
	uint32_t x, y;
	/* Fill the whole screen with the background color */
	gfx_draw_filled_rect(0, 0, gfx_get_width(), gfx_get_height(), BGCOLOR);
	/* Print user instructions */
	/* Write center-aligned text string to the top of the display */
	gfx_draw_string_aligned(string_calib_name,
			gfx_get_width() / 2, 60, &sysfont,
			GFX_COLOR_WHITE, TXTCOLOR,
			TEXT_POS_CENTER, TEXT_ALIGN_LEFT);

	gfx_draw_string_aligned(string_calib_instruction,
		gfx_get_width() / 2, 190, &sysfont,
		GFX_COLOR_WHITE, TXTCOLOR,
		TEXT_POS_CENTER, TEXT_ALIGN_LEFT);

	/* Calibration points */
	for (i = 0; i < NUM_TOUCH_POINTS; i++) {
		draw_calibration_point(&gs_calibration_points[i].panel);

		/* Wait for touch & end of conversion */
		rtouch_wait_pressed();

		rtouch_get_raw_point(&x, &y);
		gs_calibration_points[i].raw.x = x;
		gs_calibration_points[i].raw.y = y;
		clear_calibration_point(&gs_calibration_points[i].panel);

		/* Wait for contact loss */
		rtouch_wait_released();
	}

	/* Check if the points acceptable */
	if (rtouch_compute_calibration((rtouch_calibration_point_t *) &gs_calibration_points) == 0) {

		for (i=0;i<NUM_TOUCH_POINTS;i++) {
			g_demo_parameters.calib_points[i].raw.x = gs_calibration_points[i].raw.x;
			g_demo_parameters.calib_points[i].raw.y = gs_calibration_points[i].raw.y;
		}

		/* Commit changes to the parameter area */
		demo_parameters_commit_changes();

		/* Display calibration done string */
		gfx_draw_string_aligned(string_calib_done,
				gfx_get_width() / 2, 130, &sysfont,
				GFX_COLOR_WHITE, TXTCOLOR,
				TEXT_POS_CENTER, TEXT_ALIGN_LEFT);

		return 0;

	} else {
		/* Clear instruction string first */
		gfx_draw_string_aligned(string_calib_instruction,
			gfx_get_width() / 2, 190, &sysfont,
			GFX_COLOR_WHITE, GFX_COLOR_WHITE,
			TEXT_POS_CENTER, TEXT_ALIGN_LEFT);

		/* Show up failed string */
		gfx_draw_string_aligned(string_calib_failed,
			gfx_get_width() / 2, 100, &sysfont,
			GFX_COLOR_WHITE, TXTCOLOR,
			TEXT_POS_CENTER, TEXT_ALIGN_LEFT);

		/* Display retry string */
		gfx_draw_string_aligned(string_calib_retry,
			gfx_get_width() / 2, 190, &sysfont,
			GFX_COLOR_WHITE, TXTCOLOR,
			TEXT_POS_CENTER, TEXT_ALIGN_LEFT);

		/* Wait for contact loss */
		rtouch_wait_released();
		return 1;
	}
}
Пример #11
0
/**
 * This function is the window event handler for button widgets.
 * It handles all events sent to the windows composing the widget.
 *
 * \param win Window receiving the event.
 * \param type The event type.
 * \param data Custom data, depending on event type.
 *
 * \return True if the event was recognized and accepted.
 */
static bool wtk_button_handler(struct win_window *win,
		enum win_event_type type, void const *data)
{
	/* Custom data for windows of a widget points back to the widget itself. */
	struct wtk_button *button
		= (struct wtk_button *)win_get_custom_data(win);

	switch (type) {
	case WIN_EVENT_DRAW:
	{
		/* For DRAW events, the data parameter points to the
		 * clipping region. */
		struct win_clip_region const *clip
			= (struct win_clip_region const *)data;
		struct win_area const *area = win_get_area(win);

		/* Preare background and caption colors depending on state of
		 * button. If pressed/highlighted, the colors are inverted. */
		gfx_color_t background_color;
		gfx_color_t caption_color;

		/* There should not be other windows in this widget. */
		Assert(win == button->container);

		switch (button->state) {
		case WTK_BUTTON_NORMAL:
			background_color = WTK_BUTTON_BACKGROUND_COLOR;
			caption_color = WTK_BUTTON_CAPTION_COLOR;
			break;

		case WTK_BUTTON_PRESSED:
			background_color = WTK_BUTTON_CAPTION_COLOR;
			caption_color = WTK_BUTTON_BACKGROUND_COLOR;
			break;

		default:
			Assert(false);
			background_color = WTK_BUTTON_BACKGROUND_COLOR;
			caption_color = WTK_BUTTON_CAPTION_COLOR;
		}

		/* Draw background. */
		gfx_draw_filled_rect(clip->origin.x, clip->origin.y,
				area->size.x, area->size.y,
				background_color);

		/* Draw border. */
		gfx_draw_rect(clip->origin.x, clip->origin.y,
				area->size.x, area->size.y,
				WTK_BUTTON_BORDER_COLOR);

		/* Draw caption. */
		gfx_draw_string_aligned(button->caption,
				clip->origin.x + (area->size.x / 2),
				clip->origin.y + (area->size.y / 2),
				&sysfont, GFX_COLOR_TRANSPARENT, caption_color,
				TEXT_POS_CENTER, TEXT_ALIGN_CENTER);

		/* Always accept DRAW events, as the return value is
		 * ignored anyway for that event type.
		 */
		return true;
	}

	case WIN_EVENT_POINTER:
	{
		/* There should not be other windows in this widget. */
		Assert(win == button->container);

		/* For POINTER events, the data parameter points to the
		 * pointer event information.
		 */
		struct win_pointer_event const *event
			= (struct win_pointer_event const *)data;

		switch (event->type) {
		case WIN_POINTER_PRESS:

			/* When button pressed, grab pointer and wait
			 * for release inside button borders. Other
			 * widgets won't get pointer events before it
			 * is released, and the pointer ungrabbed by
			 * us.
			 */
			if (button->state == WTK_BUTTON_NORMAL) {
				win_grab_pointer(button->container);
				button->state = WTK_BUTTON_PRESSED;
				win_redraw(button->container);
			}

			break;

		case WIN_POINTER_RELEASE:

			/* When button released, take action only if
			 * released inside widget extents.
			 */
			if (button->state == WTK_BUTTON_PRESSED) {
				/* Ungrab pointer. */
				win_grab_pointer(NULL);
				button->state = WTK_BUTTON_NORMAL;
				win_redraw(button->container);

				/* Check release position. */
				bool isInside = win_is_inside_window
							(button->container,
							&(event->pos));

				/* Send command event if inside. */
				if (isInside) {
					struct win_command_event
							command;
					command.sender = button->
							container;
					command.recipient
						= button->
							container;
					command.data = button->
							command;
					win_queue_command_event
						(&command);
				}
			}

			break;

		default:
			break;
		}

		/* Accept all POINTER events since all acitivity inside
		 * the widget extents is relevant to us.
		 */
		return true;
	}

	case WIN_EVENT_DESTROY:
	{
		/* There should not be other windows in this widget. */
		Assert(win == button->container);

		/* Memory allocated for windows will be automatically
		 * destroyed by the window system. We must destroy
		 * other allocations.
		 */
		membag_free(button->caption);
		membag_free(button);

		/* Always accept DESTROY events, as the return value is
		 * ignored anyway for that event type.
		 */
		return true;
	}

	default:
		/* Reject unknown event types. */
		return false;
	}
}