Changeset 170


Ignore:
Timestamp:
Aug 23, 2010, 3:56:09 AM (10 years ago)
Author:
sam
Message:

Properly implement program termination, including in the GTK program.

Location:
trunk/src
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/debugsprite.cpp

    r154 r170  
    3636    data = new DebugSpriteData();
    3737    data->game = game;
     38    Ticker::Ref(game);
    3839    data->tiler = Tiler::Register("art/test/character-dress.png");
    3940    data->x = 320;
     
    7273DebugSprite::~DebugSprite()
    7374{
     75    Ticker::Unref(data->game);
    7476    Tiler::Deregister(data->tiler);
    7577    delete data;
  • trunk/src/dict.cpp

    r153 r170  
    8686    else
    8787    {
    88         data->entities[id]->Ref();
     88        Ticker::Ref(data->entities[id]);
    8989    }
    9090
     
    9494void Dict::RemoveSlot(int id)
    9595{
    96     if (data->entities[id]->Unref() == 0)
     96    if (Ticker::Unref(data->entities[id]) == 0)
    9797        data->entities[id] = NULL;
    9898}
     
    101101void Dict::SetEntity(int id, Entity *entity)
    102102{
    103     entity->Ref();
     103    Ticker::Ref(entity);
    104104    data->entities[id] = entity;
    105105}
  • trunk/src/entity.cpp

    r154 r170  
    6464}
    6565
    66 void Entity::Ref()
    67 {
    68     ref++;
    69 }
    70 
    71 int Entity::Unref()
    72 {
    73     return --ref;
    74 }
    75 
  • trunk/src/entity.h

    r154 r170  
    2323    friend class Dict;
    2424
    25 public:
    26     virtual void Ref();
    27     virtual int Unref();
    28 
    2925protected:
    3026    typedef enum
     
    4844    virtual void TickDraw(float deltams);
    4945
    50     Entity *next;
    51     int ref, destroy;
     46    Entity *next, *autonext;
     47    int ref, autorelease, destroy;
    5248
    5349#if !FINAL_RELEASE
  • trunk/src/font.cpp

    r156 r170  
    7575    Entity::TickDraw(deltams);
    7676
    77     if (data->img)
     77    if (destroy)
     78    {
     79        if (data->img)
     80            SDL_FreeSurface(data->img);
     81        else
     82            glDeleteTextures(1, &data->texture);
     83    }
     84    else if (data->img)
    7885    {
    7986        data->width = data->img->w / 16;
     
    9198        SDL_FreeSurface(data->img);
    9299        data->img = NULL;
    93     }
    94     else if (ref == 0)
    95     {
    96         glDeleteTextures(1, &data->texture);
    97         destroy = 1;
    98100    }
    99101}
  • trunk/src/gtk/editor.cpp

    r166 r170  
    1616#include "glmapview.h"
    1717#include "debugfps.h"
     18
     19static gboolean delayed_quit(GtkWidget *w, GdkEvent *e, void *data)
     20{
     21    (void)w;
     22    (void)e;
     23    (void)data;
     24    gtk_main_quit();
     25    return TRUE;
     26}
    1827
    1928int main(int argc, char **argv)
     
    4251
    4352    /* Show window. We're good to go! */
    44     gtk_widget_show_all(GTK_WIDGET(gtk_builder_get_object(builder, "window")));
     53    GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
     54    gtk_widget_show_all(window);
     55    gtk_signal_connect(GTK_OBJECT(window), "delete_event",
     56                       GTK_SIGNAL_FUNC(delayed_quit), NULL);
    4557    g_object_unref(G_OBJECT(builder));
    4658
     59    glmapview->LoadMap("maps/testmap.tmx");
    4760    new DebugFps();
    48     glmapview->LoadMap("maps/testmap.tmx");
    49     glmapview->SetFocus();
    5061
    5162    gtk_main();
  • trunk/src/gtk/editor.xml

    r166 r170  
    55  <object class="GtkWindow" id="window">
    66    <property name="title" translatable="yes">Deus Hax Editor</property>
    7     <signal name="delete_event" handler="gtk_main_quit"/>
    87    <child>
    98      <object class="GtkVBox" id="vbox1">
     
    2423                      <object class="GtkImageMenuItem" id="imagemenuitem1">
    2524                        <property name="visible">True</property>
     25                        <property name="use_action_appearance">True</property>
    2626                        <property name="related_action">action_new</property>
     27                        <property name="use_underline">True</property>
     28                        <property name="use_stock">True</property>
     29                      </object>
     30                    </child>
     31                    <child>
     32                      <object class="GtkImageMenuItem" id="imagemenuitem2">
     33                        <property name="visible">True</property>
    2734                        <property name="use_action_appearance">True</property>
    28                         <property name="use_underline">True</property>
    29                         <property name="use_stock">True</property>
    30                       </object>
    31                     </child>
    32                     <child>
    33                       <object class="GtkImageMenuItem" id="imagemenuitem2">
    34                         <property name="visible">True</property>
    3535                        <property name="related_action">action_open</property>
    36                         <property name="use_action_appearance">True</property>
    3736                        <property name="use_underline">True</property>
    3837                        <property name="use_stock">True</property>
     
    6867                        <property name="always_show_image">True</property>
    6968                        <signal name="activate" handler="gtk_main_quit"/>
     69                        <signal name="activate" handler="gtk_true"/>
    7070                      </object>
    7171                    </child>
     
    159159              <object class="GtkToolButton" id="toolbutton2">
    160160                <property name="visible">True</property>
     161                <property name="use_action_appearance">True</property>
    161162                <property name="related_action">action_new</property>
    162                 <property name="use_action_appearance">True</property>
    163163                <property name="label" translatable="yes">toolbutton</property>
    164164                <property name="use_underline">True</property>
     
    172172              <object class="GtkToolButton" id="toolbutton1">
    173173                <property name="visible">True</property>
     174                <property name="use_action_appearance">True</property>
    174175                <property name="related_action">action_open</property>
    175                 <property name="use_action_appearance">True</property>
    176176                <property name="label" translatable="yes">Open...</property>
    177177                <property name="use_underline">True</property>
     
    185185              <object class="GtkToolButton" id="toolbutton4">
    186186                <property name="visible">True</property>
     187                <property name="use_action_appearance">True</property>
    187188                <property name="related_action">action_save</property>
    188                 <property name="use_action_appearance">True</property>
    189189                <property name="label" translatable="yes">Save</property>
    190190                <property name="use_underline">True</property>
  • trunk/src/gtk/glmapview.cpp

    r169 r170  
    5151     * the timeout value. */
    5252    g_idle_add((GSourceFunc)IdleTickSignal, this);
     53    gtk_quit_add(0, (GtkFunction)ShutdownSignal, this);
    5354
    5455    gtk_signal_connect(GTK_OBJECT(glarea), "realize",
    5556                       GTK_SIGNAL_FUNC(SetupSignal), this);
    56     gtk_signal_connect(GTK_OBJECT(glarea), "destroy",
    57                        GTK_SIGNAL_FUNC(DestroySignal), this);
    5857    gtk_signal_connect(GTK_OBJECT(glarea), "expose_event",
    5958                       GTK_SIGNAL_FUNC(DrawSignal), this);
     
    7675    // FIXME: detect when the map viewer is killed
    7776    mapviewer = new MapViewer(path);
    78 
    79     UpdateAdjustments();
    80 }
    81 
    82 void GlMapView::SetFocus()
    83 {
    84     gtk_widget_grab_focus(glarea);
     77    Ticker::Ref(mapviewer);
     78
     79    UpdateAdjustments();
     80}
     81
     82void GlMapView::CloseMap()
     83{
     84    if (mapviewer)
     85        Ticker::Unref(mapviewer);
     86    mapviewer = NULL;
     87
     88    UpdateAdjustments();
    8589}
    8690
    8791gboolean GlMapView::IdleTick()
    8892{
     93    if (Ticker::Finished())
     94    {
     95        gtk_main_quit();
     96        return FALSE;
     97    }
     98
    8999    // FIXME: do not do anything if the previous tick was too recent?
    90100    ticking = TRUE;
     
    105115{
    106116    /* Set up display */
     117    gtk_widget_grab_focus(glarea);
    107118    if (gtk_gl_area_make_current(GTK_GL_AREA(glarea)))
    108119        Video::Setup(glarea->allocation.width, glarea->allocation.height);
     
    113124}
    114125
    115 gboolean GlMapView::Destroy()
    116 {
    117     g_idle_remove_by_data(this);
     126gboolean GlMapView::Shutdown()
     127{
     128    CloseMap();
     129    Ticker::Shutdown();
     130    /* Hijack the exit process by adding another level of gtk_main */
     131    gtk_widget_set_sensitive(gtk_widget_get_toplevel(glarea), FALSE);
     132    gtk_main();
    118133    return TRUE;
    119134}
     
    240255}
    241256
    242 gboolean GlMapView::DestroySignal(GtkWidget *w, GlMapView *that)
    243 {
    244     (void)w;
    245     return that->Destroy();
     257gboolean GlMapView::ShutdownSignal(GlMapView *that)
     258{
     259    return that->Shutdown();
    246260}
    247261
  • trunk/src/gtk/glmapview.h

    r169 r170  
    1414    GlMapView(GtkBuilder *builder);
    1515    void LoadMap(char const *path);
    16     void SetFocus();
     16    void CloseMap();
    1717
    1818private:
     
    2020    gboolean IdleTick();
    2121    gboolean Setup();
    22     gboolean Destroy();
     22    gboolean Shutdown();
    2323    gboolean Draw(GdkEventExpose *e);
    2424    void Scroll(double dx, double dy);
     
    3131    static gboolean IdleTickSignal(GlMapView *that);
    3232    static gboolean SetupSignal(GtkWidget *w, GlMapView *that);
    33     static gboolean DestroySignal(GtkWidget *w, GlMapView *that);
     33    static gboolean ShutdownSignal(GlMapView *that);
    3434    static gboolean DrawSignal(GtkWidget *w, GdkEventExpose *e,
    3535                               GlMapView *that);
  • trunk/src/sdlinput.cpp

    r150 r170  
    2222
    2323private:
    24     Game *game;
    2524    int mx, my;
    2625};
     
    3029 */
    3130
    32 SdlInput::SdlInput(Game *game)
     31SdlInput::SdlInput()
    3332{
    3433    SDL_Init(SDL_INIT_TIMER);
    3534
    3635    data = new SdlInputData();
    37     data->game = game;
    3836    SDL_GetMouseState(&data->mx, &data->my);
    3937}
     
    4846    Entity::TickGame(deltams);
    4947
    50     if (data->game->Finished())
    51         destroy = 1;
    52 
    5348    /* Handle mouse input */
    5449    SDL_GetMouseState(&data->mx, &data->my);
     
    5954    {
    6055        if (event.type == SDL_QUIT)
    61             data->game->Quit();
     56            Ticker::Shutdown();
    6257#if 0
    6358        else if (event.type == SDL_KEYDOWN)
  • trunk/src/sdlinput.h

    r149 r170  
    2020{
    2121public:
    22     SdlInput(Game *game);
     22    SdlInput();
    2323    virtual ~SdlInput();
    2424
  • trunk/src/test-map.cpp

    r154 r170  
    4949
    5050    /* Register an input driver and some debug stuff */
    51     new SdlInput(game);
     51    new SdlInput();
    5252    new DebugFps();
    5353    new DebugSprite(game);
    5454    //new DebugRecord("lolengine.ogg");
    5555
    56     while (!game->Finished())
     56    while (!Ticker::Finished())
    5757    {
    5858        /* Tick the game */
  • trunk/src/ticker.cpp

    r167 r170  
    2424public:
    2525    TickerData() :
    26         todo(0), nentities(0),
     26        todolist(0), autolist(0),
     27        nentities(0),
    2728        frame(0), deltams(0), bias(0)
    2829    {
     
    3637        if (nentities)
    3738            fprintf(stderr, "ERROR: still %i entities in ticker\n", nentities);
     39        if (autolist)
     40        {
     41            int count = 0;
     42            for (Entity *e = autolist; e; e = e->autonext, count++)
     43                ;
     44            fprintf(stderr, "ERROR: still %i autoreleased entities\n", count);
     45        }
     46        fprintf(stderr, "INFO: %i frames required to quit\n",
     47                frame - quitframe);
    3848#endif
    3949    }
     
    4151private:
    4252    /* Entity management */
    43     Entity *todo;
     53    Entity *todolist, *autolist;
    4454    Entity *list[Entity::GROUP_COUNT];
    4555    int nentities;
    4656
    4757    /* Fixed framerate management */
    48     int frame;
     58    int frame, quitframe;
    4959    Timer timer;
    5060    float deltams, bias;
     
    6373     * ready yet, so we do not know which group this entity belongs to. Wait
    6474     * until the first tick. */
    65     entity->next = data->todo;
    66     data->todo = entity;
     75    entity->next = data->todolist;
     76    data->todolist = entity;
     77    /* Objects are autoreleased by default. Put them in a circular list. */
     78    entity->autorelease = 1;
     79    entity->autonext = data->autolist;
     80    data->autolist = entity;
     81    entity->ref = 1;
     82
     83    data->nentities++;
     84}
     85
     86void Ticker::Ref(Entity *entity)
     87{
     88#if !FINAL_RELEASE
     89    if (entity->destroy)
     90        fprintf(stderr, "ERROR: refing entity scheduled for destruction\n");
     91#endif
     92    if (entity->autorelease)
     93    {
     94        /* Get the entity out of the autorelease list. This is usually
     95         * very fast since the first entry in autolist is the last
     96         * registered entity. */
     97        for (Entity *e = data->autolist, *prev = NULL; e;
     98             prev = e, e = e->autonext)
     99        {
     100            if (e == entity)
     101            {
     102                if (prev)
     103                    prev->autonext = e->autonext;
     104                else
     105                    data->autolist = e->autonext;
     106                break;
     107            }
     108        }
     109        entity->autorelease = 0;
     110    }
     111    else
     112        entity->ref++;
     113}
     114
     115int Ticker::Unref(Entity *entity)
     116{
     117#if !FINAL_RELEASE
     118    if (entity->ref <= 0)
     119        fprintf(stderr, "ERROR: dereferencing unreferenced entity\n");
     120    if (entity->autorelease)
     121        fprintf(stderr, "ERROR: dereferencing autoreleased entity\n");
     122#endif
     123    return --entity->ref;
    67124}
    68125
     
    73130
    74131    Profiler::Start(Profiler::STAT_TICK_GAME);
     132
     133#if 0
     134    fprintf(stderr, "-------------------------------------\n");
     135    for (int i = 0; i < Entity::GROUP_COUNT; i++)
     136    {
     137        fprintf(stderr, "Group %i\n", i);
     138
     139        for (Entity *e = data->list[i]; e; e = e->next)
     140            fprintf(stderr, "  \\-- %s (ref %i, destroy %i)\n", e->GetName(), e->ref, e->destroy);
     141    }
     142#endif
    75143
    76144    data->frame++;
     
    83151     * are already marked for destruction. */
    84152    for (int i = 0; i < Entity::GROUP_COUNT; i++)
    85         for (Entity *e = data->list[i], *prev = NULL; e; prev = e, e = e->next)
     153        for (Entity *e = data->list[i], *prev = NULL; e; )
     154        {
    86155            if (e->destroy)
    87156            {
     
    91160                    data->list[i] = e->next;
    92161
     162                Entity *tmp = e;
     163                e = e->next;
     164                delete tmp;
     165
    93166                data->nentities--;
    94                 delete e;
    95             }
     167            }
     168            else
     169            {
     170                if (e->ref <= 0)
     171                    e->destroy = 1;
     172                prev = e;
     173                e = e->next;
     174            }
     175        }
    96176
    97177    /* Insert waiting objects into the appropriate lists */
    98     while (data->todo)
    99     {
    100         Entity *e = data->todo;
    101         data->todo = e->next;
     178    while (data->todolist)
     179    {
     180        Entity *e = data->todolist;
     181        data->todolist = e->next;
    102182
    103183        int i = e->GetGroup();
    104184        e->next = data->list[i];
    105185        data->list[i] = e;
    106         data->nentities++;
    107186    }
    108187
     
    170249}
    171250
     251void Ticker::Shutdown()
     252{
     253    /* We're bailing out. Release all autorelease objects. */
     254    while (data->autolist)
     255    {
     256        data->autolist->ref--;
     257        data->autolist = data->autolist->autonext;
     258    }
     259
     260    data->quitframe = data->frame;
     261}
     262
     263int Ticker::Finished()
     264{
     265    return !data->nentities;
     266}
     267
  • trunk/src/ticker.h

    r167 r170  
    2121public:
    2222    static void Register(Entity *entity);
     23    static void Ref(Entity *entity);
     24    static int Unref(Entity *entity);
    2325
    2426    static void TickGame();
     
    2628    static void ClampFps(float deltams);
    2729    static int GetFrameNum();
     30
     31    static void Shutdown();
     32    static int Finished();
    2833};
    2934
  • trunk/src/tileset.cpp

    r154 r170  
    8484    Entity::TickDraw(deltams);
    8585
    86     if (data->img)
     86    if (destroy)
     87    {
     88        if (data->img)
     89            SDL_FreeSurface(data->img);
     90        else
     91            glDeleteTextures(1, &data->texture);
     92    }
     93    else if (data->img)
    8794    {
    8895        glGenTextures(1, &data->texture);
     
    97104        SDL_FreeSurface(data->img);
    98105        data->img = NULL;
    99     }
    100     else if (ref == 0)
    101     {
    102         glDeleteTextures(1, &data->texture);
    103         destroy = 1;
    104106    }
    105107}
Note: See TracChangeset for help on using the changeset viewer.