Purple Martians
Technical Code Descriptions

Display
Global variables Creating the display Process screen change Display transform double Detecting window move
Global variables I use these global variables for the display:
ALLEGRO_DISPLAY *display;
int fullscreen;

// current size and position
int disp_x_curr; 
int disp_y_curr;
int disp_w_curr;
int disp_h_curr;

// size and position of windowed mode
int disp_x_wind;
int disp_y_wind;
int disp_w_wind;
int disp_h_wind;

// In windowed mode current values are same as windowed values.
// In fullscreen mode, they are read from the display struct.

int display_transform_double = 2;
int SCREEN_W;
int SCREEN_H;
These values are also saved in the config file:
int fullscreen;
int disp_x_wind;
int disp_y_wind;
int disp_w_wind;
int disp_h_wind;

Creating the display
int init_screen(void)
{
   al_set_new_display_option(ALLEGRO_COLOR_SIZE, 16, ALLEGRO_SUGGEST);
   // (most of the time I get a 32 bit anyway, but if I get 16, it can be faster)

   int flags = ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE;
   if (fullscreen) flags = ALLEGRO_FULLSCREEN_WINDOW | ALLEGRO_RESIZABLE;
   al_set_new_display_flags(flags);

   display = al_create_display(disp_w_wind, disp_h_wind);
   if(!display)
   {
      sprintf(msg, "Error creating display\n");
      m_err(msg);
      exit(0);
   }

   if (!fullscreen)
   {
      disp_x_curr = disp_x_wind;
      disp_y_curr = disp_y_wind;
      al_set_window_position(display, disp_x_curr, disp_y_curr);
   }

   disp_w_curr = al_get_display_width(display);
   disp_h_curr = al_get_display_height(display);
   al_get_window_position(display, &disp_x_curr, &disp_y_curr);

   auto_set_display_transform_double();
   return 1;
}

Process screen change This function is called when: - an event 'ALLEGRO_EVENT_DISPLAY_RESIZE' is received - F12 is used to toggle fullscreen - proc_controllers() detects the window has been moved
void proc_screen_change(int new_sw, int new_sh, int new_sx, int new_sy, int new_fs)
{
   if ((!fullscreen) && (new_fs)) //  changing to fullscreen
   {
      fullscreen = 1;
      al_set_display_flag(display, ALLEGRO_FULLSCREEN_WINDOW, 1);
      al_get_window_position(display, &disp_x_curr, &disp_y_curr);
      disp_w_curr = al_get_display_width(display);
      disp_h_curr = al_get_display_height(display);
      auto_set_display_transform_double();
      rebuild_bitmaps();
      save_config();
      Redraw = 1;
   }
   else if ((fullscreen) && (!new_fs)) //  changing away from fullscreen
   {
      fullscreen = 0;
      al_resize_display(display, disp_w_wind, disp_h_wind);
      al_set_display_flag(display, ALLEGRO_FULLSCREEN_WINDOW, 0);
      al_set_window_position(display, disp_x_wind, disp_y_wind);
      al_get_window_position(display, &disp_x_curr, &disp_y_curr);
      disp_w_curr = al_get_display_width(display);
      disp_h_curr = al_get_display_height(display);
      auto_set_display_transform_double();
      rebuild_bitmaps();
      save_config();
      Redraw = 1;
   }
   else if (!fullscreen)
   {
      if ((new_sw != disp_w_curr) || (new_sh != disp_h_curr)) // window has been resized
      {
         al_acknowledge_resize(display);
         disp_w_curr = disp_w_wind = al_get_display_width(display);
         disp_h_curr = disp_h_wind = al_get_display_height(display);
         auto_set_display_transform_double();
         rebuild_bitmaps();
         save_config();
         Redraw = 1;
     }
     if ((new_sx != disp_x_curr) || (new_sy != disp_y_curr)) // window has been moved
     {
        disp_x_curr = disp_x_wind = new_sx;;
        disp_y_curr = disp_y_wind = new_sy;;
        save_config();
     }
  }
}

Display transform double I also use an orthographic transform to double or triple the screen size. This was implemented to address large screen sizes and small text on menus and overlays.
void set_display_transform(void)
{
   al_set_target_backbuffer(display);
   SCREEN_W = disp_w_curr/display_transform_double;
   SCREEN_H = disp_h_curr/display_transform_double;
   ALLEGRO_TRANSFORM trans;
   al_identity_transform(&trans);
   al_orthographic_transform(&trans, 0, 0, -1.0, SCREEN_W, SCREEN_H, 1.0);
   al_use_projection_transform(&trans);
}

void auto_set_display_transform_double(void)
{
   display_transform_double = 1;

   if (disp_w_curr > 1023) display_transform_double = 2;
   if (disp_h_curr > 1023) display_transform_double = 2;

   if (disp_w_curr < 1024) display_transform_double = 1;
   if (disp_h_curr < 700) display_transform_double = 1;

   if (level_editor_running) display_transform_double = 1;

   if (help_screens_running)
   {
      if (disp_w_curr > 1279) display_transform_double = 2;
      if (disp_w_curr < 1280) display_transform_double = 1;
   }
   set_display_transform();
   set_map_var();
}
This extern variable controls the doubling:
extern int display_transform_double = 1;
// 1 = normal (no double)
// 2 = double
// 3 = triple
Then all of my drawing functions throughout the rest of the game that need to know screen size use the prescaled 'SCREEN_W' and 'SCREEN_H' instead of the actual sizes. The mouse_x and mouse_y positions are also scaled like this:
mouse_x = ev.mouse.x / display_transform_double;
mouse_y = ev.mouse.y / display_transform_double;

Detecting window move Because no events are triggered when the display window is moved, I had to detect it myself. Every frame, in the function 'proc_controllers()', I compare the display's window position to the stored values. If they differ, I call 'proc_screen_change()' with the new values.
if (!fullscreen) // detect if window was moved
{
   int x, y;
   al_get_window_position(display, &x, &y);
   if ((x != disp_x_curr) || (y != disp_y_curr))
   proc_screen_change(disp_w_curr, disp_h_curr, x, y, fullscreen);
}