| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269 |
- //*****************************************************************************
- //
- // widget.c - Generic widget tree handling code.
- //
- // Copyright (c) 2008-2010 Texas Instruments Incorporated. All rights reserved.
- // Software License Agreement
- //
- // Texas Instruments (TI) is supplying this software for use solely and
- // exclusively on TI's microcontroller products. The software is owned by
- // TI and/or its suppliers, and is protected under applicable copyright
- // laws. You may not combine this software with "viral" open-source
- // software in order to form a larger program.
- //
- // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
- // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
- // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
- // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
- // DAMAGES, FOR ANY REASON WHATSOEVER.
- //
- // This is part of revision 6288 of the Stellaris Graphics Library.
- //
- //*****************************************************************************
- #include "debug.h"
- #include "grlib.h"
- #include "widget.h"
- //*****************************************************************************
- //
- //! \addtogroup widget_api
- //! @{
- //
- //*****************************************************************************
- //*****************************************************************************
- //
- // Flags that indicate how messages from the message queue are processed. They
- // can be sent via either a pre-order or post-order search, and can optionally
- // be sent to no other widgets once one accepts the message.
- //
- //*****************************************************************************
- #define MQ_FLAG_POST_ORDER 1
- #define MQ_FLAG_STOP_ON_SUCCESS 2
- //*****************************************************************************
- //
- // The size of the message queue. In order to make the queue pointer
- // arithmetic more efficient, this should be a power of two.
- //
- //*****************************************************************************
- #define QUEUE_SIZE 16
- #ifdef DEBUG_MSGQ
- //*****************************************************************************
- //
- // In debug builds, keep track of the number of cases where a message was
- // lost due to the queue being full. We count the following occurrences:
- //
- // 1. All messages discarded due to queue overflow (g_ulMQOverflow)
- // 2. Messages other than WIDGET_MSG_PTR_MOVE discarded due to queue
- // overflow (g_ulMQNonMouseOverflow). In this case, we also remember the
- // last message that was discarded (g_ulMQLastLostMsg).
- // 3. The number of calls to WidgetMessageQueueAdd that fail due to the queue
- // mutex already being held.
- // 4. The number of cases where WidgetMessageQueueAdd reused an unread
- // WIDGET_MSG_PTR_MOVE message when a second one arrived before the previous
- // one had been processed.
- //
- //*****************************************************************************
- unsigned int g_ulMQOverflow = 0;
- unsigned int g_ulMQNonMouseOverflow = 0;
- unsigned int g_ulMQLastLostMsg = 0;
- unsigned int g_ulMQMutexClash = 0;
- unsigned int g_ulMQMoveOverwrite = 0;
- #endif
- //*****************************************************************************
- //
- // This structure describes the message queue used to hold widget messages.
- //
- //*****************************************************************************
- typedef struct
- {
- //
- // The flags that describe how this message should be processed; this is
- // defined by the MQ_FLAG_xxx flags.
- //
- unsigned int ulFlags;
- //
- // The widget (or widget tree) to which the message should be sent.
- //
- tWidget *pWidget;
- //
- // The message to be sent.
- //
- unsigned int ulMessage;
- //
- // The first parameter to the message.
- //
- unsigned int ulParam1;
- //
- // The second parameter to the message.
- //
- unsigned int ulParam2;
- }
- tWidgetMessageQueue;
- //*****************************************************************************
- //
- // The root of the widget tree. This is the widget used when no parent is
- // specified when adding a widget, or when no widget is specified when sending
- // a message. The parent and sibling of this widget are always zero. This
- // should not be directly referenced by applications; WIDGET_ROOT should be
- // used instead.
- //
- //*****************************************************************************
- tWidget g_sRoot =
- {
- sizeof(tWidget),
- 0,
- 0,
- 0,
- 0,
- {
- 0,
- 0,
- 0,
- 0,
- },
- WidgetDefaultMsgProc
- };
- //*****************************************************************************
- //
- // The widget that has captured pointer messages. When a pointer down message
- // is accepted by a widget, that widget is saved in this variable and all
- // subsequent pointer move and pointer up messages are sent directly to this
- // widget.
- //
- //*****************************************************************************
- static tWidget *g_pPointerWidget = 0;
- //*****************************************************************************
- //
- // The message queue that holds messages that are waiting to be processed.
- //
- //*****************************************************************************
- static volatile tWidgetMessageQueue g_pMQ[QUEUE_SIZE];
- //*****************************************************************************
- //
- // The offset to the next message to be read from the message queue. The
- // message queue is empty when this has the same value as g_ulMQWrite.
- //
- //*****************************************************************************
- static unsigned int g_ulMQRead = 0;
- //*****************************************************************************
- //
- // The offset to the next message to be written to the message queue. The
- // message queue is full when this value is one less than g_ulMQRead (modulo
- // the queue size).
- //
- //*****************************************************************************
- static volatile unsigned int g_ulMQWrite = 0;
- //*****************************************************************************
- //
- // The mutex used to protect access to the message queue.
- //
- //*****************************************************************************
- static unsigned char g_ucMQMutex = 0;
- //*****************************************************************************
- //
- //! Initializes a mutex to the unowned state.
- //!
- //! \param pcMutex is a pointer to mutex that is to be initialized.
- //!
- //! This function initializes a mutual exclusion semaphore (mutex) to its
- //! unowned state in preparation for use with WidgetMutexGet() and
- //! WidgetMutexPut(). A mutex is a two state object typically used to
- //! serialize access to a shared resource. An application will call
- //! WidgetMutexGet() to request ownership of the mutex. If ownership is
- //! granted, the caller may safely access the resource then release the mutex
- //! using WidgetMutexPut() once it is finished. If ownership is not granted,
- //! the caller knows that some other context is currently modifying the shared
- //! resource and it must not access the resource at that time.
- //!
- //! Note that this function must not be called if the mutex passed in \e pcMutex
- //! is already in use since this will have the effect of releasing the lock even
- //! if some caller currently owns it.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- WidgetMutexInit(unsigned char *pcMutex)
- {
- //
- // Catch NULL pointers in a debug build.
- //
- ASSERT(pcMutex);
- //
- // Clear the mutex location to set it to the unowned state.
- //
- *pcMutex = 0;
- }
- //*****************************************************************************
- //
- //! Attempts to acquire a mutex.
- //!
- //! \param pcMutex is a pointer to mutex that is to be acquired.
- //!
- //! This function attempts to acquire a mutual exclusion semaphore (mutex) on
- //! behalf of the caller. If the mutex is not already held, 0 is returned to
- //! indicate that the caller may safely access whichever resource the mutex is
- //! protecting. If the mutex is already held, 1 is returned and the caller
- //! must not access the shared resource.
- //!
- //! When access to the shared resource is complete, the mutex owner should call
- //! WidgetMutexPut() to release the mutex and relinquish ownership of the
- //! shared resource.
- //!
- //! \return Returns 0 if the mutex is acquired successfully or 1 if it is
- //! already held by another caller.
- //
- //*****************************************************************************
- #if defined(ewarm) || defined(DOXYGEN)
- unsigned int
- WidgetMutexGet(unsigned char *pcMutex)
- {
- //
- // Acquire the mutex if possible.
- //
- __asm(" mov r1, #1\n"
- " ldrexb r2, [r0]\n"
- " cmp r2, #0\n"
- " it eq\n"
- " strexb r2, r1, [r0]\n"
- " mov r0, r2\n");
- //
- // "Warning[Pe940]: missing return statement at end of non-void function"
- // is suppressed here to avoid putting a "bx lr" in the inline assembly
- // above and a superfluous return statement here.
- //
- #pragma diag_suppress=Pe940
- }
- #pragma diag_default=Pe940
- #elif defined(codered) || defined(gcc) || defined(sourcerygxx)
- unsigned int __attribute__((naked))
- WidgetMutexGet(unsigned char *pcMutex)
- {
- unsigned int ulRet;
- //
- // Acquire the mutex if possible.
- //
- __asm(" mov r1, #1\n"
- " ldrexb r2, [r0]\n"
- " cmp r2, #0\n"
- " it eq\n"
- " strexbeq r2, r1, [r0]\n"
- " mov r0, r2\n"
- " bx lr\n"
- : "=r" (ulRet));
- //
- // The return is handled in the inline assembly, but the compiler will
- // still complain if there is not an explicit return here (despite the fact
- // that this does not result in any code being produced because of the
- // naked attribute).
- //
- return(ulRet);
- }
- #elif defined(rvmdk) || defined(__ARMCC_VERSION)
- __asm unsigned int
- WidgetMutexGet(unsigned char *pcMutex)
- {
- mov r1, #1
- ldrexb r2, [r0]
- cmp r2, #0
- it eq
- strexbeq r2, r1, [r0]
- mov r0, r2
- bx lr
- }
- #elif defined(ccs)
- unsigned int
- WidgetMutexGet(unsigned char *pcMutex)
- {
- //
- // Acquire the mutex if possible.
- //
- __asm(" mov r1, #1\n"
- " ldrexb r2, [r0]\n"
- " cmp r2, #0\n"
- " it EQ\n" // TI assembler requires upper case cond
- " strexbeq r2, r1, [r0]\n"
- " mov r0, r2\n"
- " bx lr\n");
- //
- // The following keeps the TI compiler from optimizing away the code.
- //
- return((unsigned int)pcMutex + 1);
- }
- #elif defined (__TMS470__)
- __asm(" .sect \".text:WidgetMutexGet\"\n"
- " .clink\n"
- " .global WidgetMutexGet\n"
- "WidgetMutexGet:\n"
- " mov r1, #1\n"
- " swpb r1, r1, [r0]\n"
- " mov r0, r1\n"
- " bx lr\n");
- #elif defined (_TMS320C6X)
- unsigned int WidgetMutexGet(unsigned char *pcMutex)
- {
- char temp;
- unsigned int restore_value;
- // Acquire the mutex if possible (disable interrupts to make atomic)
- restore_value = _disable_interrupts();
- temp = *pcMutex;
- *pcMutex = 1;
- _restore_interrupts(restore_value);
- return ((unsigned int) temp);
- }
- #elif defined (__IAR_SYSTEMS_ICC__)
- unsigned int WidgetMutexGet(unsigned char *pcMutex)
- {
- __asm(" mov r1, #1\n"
- " swpb r1, r1, [r0]\n"
- " mov r0, r1\n"
- "bx lr\n");
- #pragma diag_suppress=Pe940
- }
- #pragma diag_suppress=Pe940
- #else
- unsigned int __attribute__((naked)) WidgetMutexGet(unsigned char *pcMutex)
- {
- // Acquire the mutex if possible.
- __asm(" mov r1, #1\n"
- " swpb r1, r1, [r0]\n"
- " mov r0, r1\n"
- " bx lr\n");
- // The following keeps the TI compiler from optimizing away the code.
- return((unsigned int)(*pcMutex));
- }
- #endif
- //*****************************************************************************
- //
- //! Release a mutex.
- //!
- //! \param pcMutex is a pointer to mutex that is to be released.
- //!
- //! This function releases a mutual exclusion semaphore (mutex), leaving it in
- //! the unowned state.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- WidgetMutexPut(unsigned char *pcMutex)
- {
- //
- // Release the mutex.
- //
- *pcMutex = 0;
- }
- //*****************************************************************************
- //
- // Determines if a widget exists in the tree below a given point.
- //
- // \param pWidget is a pointer to the widget tree.
- // \param pFind is a pointer to the widget that is being searched for.
- //
- // This function searches the widget tree below pWidget to determine whether
- // or not the widget pointed to by \e pFind exists in the subtree.
- //
- // \return Returns 1 if \e pFind exists in the subtree or 0 if it does not.
- //
- //*****************************************************************************
- static int
- WidgetIsInTree(tWidget *pWidget, tWidget *pFind)
- {
- tWidget *pTemp;
- //
- // Check the arguments.
- //
- ASSERT(pWidget);
- ASSERT(pFind);
- //
- // Loop through the tree under the widget until every widget is searched.
- //
- for(pTemp = pWidget; pTemp != pWidget->pParent; )
- {
- //
- // See if this widget has a child.
- //
- if(pTemp->pChild)
- {
- //
- // Go to this widget's child first.
- //
- pTemp = pTemp->pChild;
- }
- //
- // This widget does not have a child, so either a sibling or a parent
- // must be checked. When moving back to the parent, another move must
- // be performed as well to avoid getting stuck in a loop (since the
- // parent's children have already been searched.
- //
- else
- {
- //
- // Loop until returning to the parent of the starting widget. This
- // loop will be explicitly broken out of if an intervening widget
- // is encountered that has not been searched.
- //
- while(pTemp != pWidget->pParent)
- {
- if(pTemp == pFind)
- {
- return(1);
- }
- //
- // See if this widget has a sibling.
- //
- if(pTemp->pNext)
- {
- //
- // Visit the sibling of this widget.
- //
- pTemp = pTemp->pNext;
- //
- // Since this widget has not been searched yet, break out
- // of the controlling loop.
- //
- break;
- }
- else
- {
- //
- // This widget has no siblings, so go to its parent. Since
- // the parent has already been searched, the same sibling
- // vs. parent decision must be made on this widget as well.
- //
- pTemp = pTemp->pParent;
- }
- }
- }
- }
- //
- // The widget could not be found.
- //
- return(0);
- }
- //*****************************************************************************
- //
- //! Handles widget messages.
- //!
- //! \param pWidget is a pointer to the widget.
- //! \param ulMessage is the message to be processed.
- //! \param ulParam1 is the first parameter to the message.
- //! \param ulParam2 is the second parameter to the message.
- //!
- //! This function is a default handler for widget messages; it simply ignores
- //! all messages sent to it. This is used as the message handler for the root
- //! widget, and should be called by the message handler for other widgets when
- //! they do not explicitly handle the provided message (in case new messages
- //! are added that require some default but override-able processing).
- //!
- //! \return Always returns 0.
- //
- //*****************************************************************************
- int
- WidgetDefaultMsgProc(tWidget *pWidget, unsigned int ulMessage,
- unsigned int ulParam1, unsigned int ulParam2)
- {
- //
- // Check the arguments.
- //
- ASSERT(pWidget);
- //
- // Return zero for all messages.
- //
- return(0);
- }
- //*****************************************************************************
- //
- //! Adds a widget to the widget tree.
- //!
- //! \param pParent is the parent for the widget. To add to the root of the tree
- //! set this parameter to \b WIDGET_ROOT.
- //! \param pWidget is the widget to add.
- //!
- //! This function adds a widget to the widget tree at the given position within
- //! the tree. The widget will become the last child of its parent, and will
- //! therefore be searched after the existing children.
- //!
- //! The added widget can be a full widget tree, allowing addition of an entire
- //! heirarchy all at once (for example, adding an entire screen to the widget
- //! tree all at once). In this case, it is the responsibility of the caller to
- //! ensure that the pParent field of each widget in the added tree is correctly
- //! set (in other words, only the widget pointed to by \e pWidget is updated to
- //! properly reside in the tree).
- //!
- //! It is the responsibility of the caller to initialize the pNext and pChild
- //! field of the added widget; either of these fields being non-zero results in
- //! a pre-defined tree of widgets being added instead of a single one.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- WidgetAdd(tWidget *pParent, tWidget *pWidget)
- {
- //
- // Check the arguments.
- //
- ASSERT(pParent);
- ASSERT(pWidget);
- //
- // Make this widget be a child of its parent.
- //
- pWidget->pParent = pParent;
- //
- // See if this parent already has children.
- //
- if(pParent->pChild)
- {
- //
- // Find the last child of this parent and also check that widget is not
- // already present at this level of the tree.
- //
- for(pParent = pParent->pChild; pParent->pNext;
- pParent = pParent->pNext)
- {
- //
- // If we find this widget here already, just return. If we don't
- // do this, we allow errant programs to add the same child twice
- // resulting in looping on message processing.
- //
- if(pParent == pWidget)
- {
- return;
- }
- }
- //
- // We perform one final check to see if we are about to add the widget
- // twice. We need this to catch the case of a single child which
- // causes the previous loop to exit before performing the widget check.
- //
- if(pParent == pWidget)
- {
- return;
- }
- //
- // Add this widget to the end of the list of children of this parent.
- //
- pParent->pNext = pWidget;
- }
- else
- {
- //
- // Make this widget be the first (and only) child of this parent.
- //
- pParent->pChild = pWidget;
- }
- }
- //*****************************************************************************
- //
- //! Removes a widget from the widget tree.
- //!
- //! \param pWidget is the widget to be removed.
- //!
- //! This function removes a widget from the widget tree. The removed widget
- //! can be a full widget tree, allowing removal of an entire heirarchy all at
- //! once (for example, removing an entire screen from the widget tree).
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- WidgetRemove(tWidget *pWidget)
- {
- tWidget *pTemp;
- //
- // Check the argument.
- //
- ASSERT(pWidget);
- //
- // Make sure that the supplied widget is actually in the tree section
- // owned by its parent and, hence, removeable.
- //
- if(!pWidget->pParent || !WidgetIsInTree(pWidget->pParent, pWidget))
- {
- return;
- }
- //
- // See if this widget is the first child of its parent.
- //
- if(pWidget->pParent->pChild == pWidget)
- {
- //
- // Make the first child of this widgets parent be this widget's
- // sibling.
- //
- pWidget->pParent->pChild = pWidget->pNext;
- }
- else
- {
- //
- // Find the sibling directly before this widget.
- //
- for(pTemp = pWidget->pParent->pChild; pTemp->pNext != pWidget;
- pTemp = pTemp->pNext)
- {
- }
- //
- // Make the previous sibling point to the next sibling, removing this
- // widget from the sibling chain.
- //
- pTemp->pNext = pWidget->pNext;
- }
- //
- // Check to see if the widget which currently owns the pointer has just
- // been removed and, if so, clear the pointer focus.
- //
- if(g_pPointerWidget && !WidgetIsInTree(&g_sRoot, g_pPointerWidget))
- {
- g_pPointerWidget = 0;
- }
- //
- // Clear the next pointer of the widget.
- //
- pWidget->pNext = 0;
- }
- //*****************************************************************************
- //
- //! Sends a message to a widget tree via a pre-order, depth-first search.
- //!
- //! \param pWidget is a pointer to the widget tree.
- //! \param ulMessage is the message to send.
- //! \param ulParam1 is the first parameter to the message.
- //! \param ulParam2 is the second parameter to the message.
- //! \param bStopOnSuccess is true if the search should be stopped when the
- //! first widget is found that returns success in response to the message.
- //!
- //! This function performs a pre-order, depth-first search of the widget tree,
- //! sending a message to each widget encountered. In a depth-first search, the
- //! children of a widget are searched before its siblings (preferring to go
- //! deeper into the tree, hence the name depth-first). A pre-order search
- //! means that the message is sent to a widget before any of its children are
- //! searched.
- //!
- //! An example use of the pre-order search is for paint messages; the larger
- //! enclosing widgets should be drawn on the screen before the smaller widgets
- //! that reside within the parent widget (otherwise, the children would be
- //! overwritten by the parent).
- //!
- //! \return Returns 0 if \e bStopOnSuccess is false or no widget returned
- //! success in response to the message, or the value returned by the first
- //! widget to successfully process the message.
- //
- //*****************************************************************************
- unsigned int
- WidgetMessageSendPreOrder(tWidget *pWidget, unsigned int ulMessage,
- unsigned int ulParam1, unsigned int ulParam2,
- unsigned int bStopOnSuccess)
- {
- unsigned int ulRet;
- tWidget *pTemp;
- //
- // Check the arguments.
- //
- ASSERT(pWidget);
- //
- // Send the message to the initial widget and return if it succeeded and
- // the search should stop on success.
- //
- ulRet = pWidget->pfnMsgProc(pWidget, ulMessage, ulParam1, ulParam2);
- if((ulRet != 0) && bStopOnSuccess)
- {
- return(ulRet);
- }
- //
- // Return if the widget does not have any children.
- //
- if(!pWidget->pChild)
- {
- return(0);
- }
- //
- // Loop through the tree under the widget until every widget is searched.
- //
- for(pTemp = pWidget->pChild; pTemp != pWidget; )
- {
- //
- // Send the message to this widget and return if it succeeded and the
- // search should stop on success.
- //
- ulRet = pTemp->pfnMsgProc(pTemp, ulMessage, ulParam1, ulParam2);
- if((ulRet != 0) && bStopOnSuccess)
- {
- return(ulRet);
- }
- //
- // Find the next widget to examine. If this widget has a child, then
- // that is the next widget to examine.
- //
- if(pTemp->pChild)
- {
- pTemp = pTemp->pChild;
- }
- //
- // This widget does not have a child, so either a sibling or a parent
- // must be checked. When moving back to the parent, another move must
- // be performed as well to avoid getting stuck in a loop (since the
- // parent's children have already been searched).
- //
- else
- {
- //
- // Loop until returning to the starting widget. This loop will be
- // explicitly broken out of if an intervening widget is encountered
- // that has not be searched.
- //
- while(pTemp != pWidget)
- {
- //
- // See if this widget has a sibling.
- //
- if(pTemp->pNext)
- {
- //
- // Visit the sibling of this widget.
- //
- pTemp = pTemp->pNext;
- //
- // Since this widget has not been searched yet, break out
- // of the controlling loop.
- //
- break;
- }
- else
- {
- //
- // This widget has no siblings, so go to its parent. Since
- // the parent has already been searched, the same sibling
- // vs. parent decision must be made on this widget as well.
- //
- pTemp = pTemp->pParent;
- }
- }
- }
- }
- //
- // No widget returned success for the message, or bStopOnSuccess was zero,
- // so return zero.
- //
- return(0);
- }
- //*****************************************************************************
- //
- //! Sends a message to a widget tree via a post-order, depth-first search.
- //!
- //! \param pWidget is a pointer to the widget tree; if this is zero then the
- //! root of the widget tree willb e used.
- //! \param ulMessage is the message to send.
- //! \param ulParam1 is the first parameter to the message.
- //! \param ulParam2 is the second parameter to the message.
- //! \param bStopOnSuccess is true if the search should be stopped when the
- //! first widget is found that returns success in response to the message.
- //!
- //! This function performs a post-order, depth-first search of the widget tree,
- //! sending a message to each widget encountered. In a depth-first search, the
- //! children of a widget are searched before its sibling (preferring to go
- //! deeper into the tree, hence the name depth-first). A post-order search
- //! means that the message is sent to a widget after all of its children are
- //! searched.
- //!
- //! An example use of the post-order search is for pointer-related messages;
- //! those messages should be delivered to the lowest widget in the tree before
- //! its parents (in other words, the widget deepest in the tree that has a hit
- //! should get the message, not the higher up widgets that also include the hit
- //! location).
- //!
- //! Special handling is performed for pointer-related messages. The widget
- //! that accepts \b #WIDGET_MSG_PTR_DOWN is remembered and subsequent
- //! \b #WIDGET_MSG_PTR_MOVE and \b #WIDGET_MSG_PTR_UP messages are sent
- //! directly to that widget.
- //!
- //! \return Returns 0 if \e bStopOnSuccess is false or no widget returned
- //! success in response to the message, or the value returned by the first
- //! widget to successfully process the message.
- //
- //*****************************************************************************
- unsigned int
- WidgetMessageSendPostOrder(tWidget *pWidget, unsigned int ulMessage,
- unsigned int ulParam1, unsigned int ulParam2,
- unsigned int bStopOnSuccess)
- {
- unsigned int ulRet;
- tWidget *pTemp;
- //
- // Check the arguments.
- //
- ASSERT(pWidget);
- //
- // See if this is a pointer move or up message.
- //
- if((ulMessage == WIDGET_MSG_PTR_MOVE) || (ulMessage == WIDGET_MSG_PTR_UP))
- {
- //
- // If there is not a widget that has captured pointer messages, then
- // simply drop this message.
- //
- if(!g_pPointerWidget)
- {
- return(0);
- }
- //
- // Send the message directly to the widget that has captured pointer
- // messages.
- //
- ulRet = g_pPointerWidget->pfnMsgProc(g_pPointerWidget, ulMessage,
- ulParam1, ulParam2);
- //
- // See if this is a pointer up message.
- //
- if(ulMessage == WIDGET_MSG_PTR_UP)
- {
- //
- // Since this was a pointer up, the widget no longer has pointer
- // messages captured.
- //
- g_pPointerWidget = 0;
- }
- //
- // Return the value returned by the pointer capture widget.
- //
- return(ulRet);
- }
- //
- // Loop through the tree under the widget until every widget is searched.
- //
- for(pTemp = pWidget; pTemp != pWidget->pParent; )
- {
- //
- // See if this widget has a child.
- //
- if(pTemp->pChild)
- {
- //
- // Go to this widget's child first.
- //
- pTemp = pTemp->pChild;
- }
- //
- // This widget does not have a child, so either a sibling or a parent
- // must be checked. When moving back to the parent, another move must
- // be performed as well to avoid getting stuck in a loop (since the
- // parent's children have already been searched.
- //
- else
- {
- //
- // Loop until returning to the parent of the starting widget. This
- // loop will be explicitly broken out of if an intervening widget
- // is encountered that has not been searched.
- //
- while(pTemp != pWidget->pParent)
- {
- //
- // Send the message to this widget.
- //
- ulRet = pTemp->pfnMsgProc(pTemp, ulMessage, ulParam1,
- ulParam2);
- //
- // If this is a pointer down message, the widget accepted the
- // message and the handler didn't modify the tree such that
- // this widget is no longer present, then save a pointer to the
- // widget for subsequent pointer move or pointer up messages.
- //
- if((ulMessage == WIDGET_MSG_PTR_DOWN) && (ulRet != 0))
- {
- //
- // Is the current widget still in the tree?
- //
- if(WidgetIsInTree(&g_sRoot, pTemp))
- {
- //
- // The widget is still in the tree so save it for later
- // use.
- //
- g_pPointerWidget = pTemp;
- }
- else
- {
- //
- // Although this widget handled the PTR_DOWN message,
- // it's message handler rearranged the widget tree and
- // removed itself so we don't want to send any more
- // messages directly to it after all.
- //
- g_pPointerWidget = 0;
- }
- }
- //
- // If the widget returned success and the search should stop on
- // success then return immediately.
- //
- if((ulRet != 0) && bStopOnSuccess)
- {
- return(ulRet);
- }
- //
- // See if this widget has a sibling.
- //
- if(pTemp->pNext)
- {
- //
- // Visit the sibling of this widget.
- //
- pTemp = pTemp->pNext;
- //
- // Since this widget has not been searched yet, break out
- // of the controlling loop.
- //
- break;
- }
- else
- {
- //
- // This widget has no siblings, so go to its parent. Since
- // the parent has already been searched, the same sibling
- // vs. parent decision must be made on this widget as well.
- //
- pTemp = pTemp->pParent;
- }
- }
- }
- }
- //
- // No widget returned success for the message, or bStopOnSuccess was zero,
- // so return zero.
- //
- return(0);
- }
- //*****************************************************************************
- //
- //! Adds a message to the widget message queue.
- //!
- //! \param pWidget is the widget to which the message should be sent.
- //! \param ulMessage is the message to be sent.
- //! \param ulParam1 is the first parameter to the message.
- //! \param ulParam2 is the second parameter to the message.
- //! \param bPostOrder is \b true if the message should be sent via a post-order
- //! search, and \b false if it should be sent via a pre-order search.
- //! \param bStopOnSuccess is \b true if the message should be sent to widgets
- //! until one returns success, and \b false if it should be sent to all
- //! widgets.
- //!
- //! This function places a widget message into the message queue for later
- //! processing. The messages are removed from the queue by
- //! WidgetMessageQueueProcess() and sent to the appropriate place.
- //!
- //! It is safe for code which interrupts WidgetMessageQueueProcess() (or called
- //! by it) to call this function to send a message. It is not safe for code
- //! which interrupts this function to call this function as well; it is up to
- //! the caller to guarantee that the later sequence never occurs.
- //!
- //! \return Returns 1 if the message was added to the queue, and 0 if it could
- //! not be added since either the queue is full or another context is currently
- //! adding a message to the queue.
- //
- //*****************************************************************************
- int
- WidgetMessageQueueAdd(tWidget *pWidget, unsigned int ulMessage,
- unsigned int ulParam1, unsigned int ulParam2,
- unsigned int bPostOrder, unsigned int bStopOnSuccess)
- {
- unsigned int ulNext;
- unsigned int ulOwned;
- //
- // Check the arguments.
- //
- ASSERT(pWidget);
- //
- // Get the mutex we use to protect access to the message queue.
- //
- ulOwned = WidgetMutexGet(&g_ucMQMutex);
- if(ulOwned)
- {
- //
- // The mutex is already being held by some other caller so return a
- // failure.
- //
- #ifdef DEBUG_MSGQ
- g_ulMQMutexClash++;
- #endif
- return(0);
- }
- //
- // Compute the next value for the write pointer.
- //
- ulNext = (g_ulMQWrite + 1) % QUEUE_SIZE;
- //
- // If the queue is not empty, and this is a pointer move message, see if
- // the previous message was also a move and, if so, replace the
- // coordinates. Without this, the message queue can very quickly overflow
- // if the application is busy doing something while the user keeps pressing
- // the display.
- //
- if(ulMessage == WIDGET_MSG_PTR_MOVE)
- {
- //
- // Is the message queue empty?
- //
- if(g_ulMQRead != g_ulMQWrite)
- {
- //
- // No - what is the index of the previous message?
- //
- ulOwned = (g_ulMQWrite == 0) ? (QUEUE_SIZE - 1) : (g_ulMQWrite - 1);
- //
- // Was this a pointer move message?
- //
- if(g_pMQ[g_ulMQWrite].ulMessage == WIDGET_MSG_PTR_MOVE)
- {
- //
- // Yes - overwrite this message with the new
- // coordinate information.
- //
- g_pMQ[ulOwned].ulParam1 = ulParam1;
- g_pMQ[ulOwned].ulParam2 = ulParam2;
- #ifdef DEBUG_MSGQ
- g_ulMQMoveOverwrite++;
- #endif
- //
- // Release the message queue mutex.
- //
- WidgetMutexPut(&g_ucMQMutex);
- //
- // Success.
- //
- return(1);
- }
- }
- }
- //
- // Return a failure if the message queue is full.
- //
- if(ulNext == g_ulMQRead)
- {
- #ifdef DEBUG_MSGQ
- g_ulMQOverflow++;
- if(ulMessage != WIDGET_MSG_PTR_MOVE)
- {
- g_ulMQNonMouseOverflow++;
- g_ulMQLastLostMsg = ulMessage;
- }
- #endif
- //
- // Release the message queue mutex.
- //
- WidgetMutexPut(&g_ucMQMutex);
- return(0);
- }
- //
- // Write this message into the next location in the message queue.
- //
- g_pMQ[g_ulMQWrite].ulFlags = ((bPostOrder ? MQ_FLAG_POST_ORDER : 0) |
- (bStopOnSuccess ? MQ_FLAG_STOP_ON_SUCCESS :
- 0));
- g_pMQ[g_ulMQWrite].pWidget = pWidget;
- g_pMQ[g_ulMQWrite].ulMessage = ulMessage;
- g_pMQ[g_ulMQWrite].ulParam1 = ulParam1;
- g_pMQ[g_ulMQWrite].ulParam2 = ulParam2;
- //
- // Update the message queue write pointer.
- //
- g_ulMQWrite = ulNext;
- //
- // Release the message queue mutex.
- //
- WidgetMutexPut(&g_ucMQMutex);
- //
- // Success.
- //
- return(1);
- }
- //*****************************************************************************
- //
- //! Processes the messages in the widget message queue.
- //!
- //! This function extracts messages from the widget message queue one at a time
- //! and processes them. If the processing of a widget message requires that a
- //! new message be sent, it is acceptable to call WidgetMessageQueueAdd(). It
- //! is also acceptable for code which interrupts this function to call
- //! WidgetMessageQueueAdd() to send more messages. In both cases, the newly
- //! added message will also be processed before this function returns.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- WidgetMessageQueueProcess(void)
- {
- tWidget *pWidget;
- unsigned int ulFlags, ulMessage, ulParam1, ulParam2;
- //
- // Loop while there are more messages in the message queue.
- //
- while(g_ulMQRead != g_ulMQWrite)
- {
- //
- // Copy the contents of this message into local variables.
- //
- pWidget = g_pMQ[g_ulMQRead].pWidget;
- ulFlags = g_pMQ[g_ulMQRead].ulFlags;
- ulMessage = g_pMQ[g_ulMQRead].ulMessage;
- ulParam1 = g_pMQ[g_ulMQRead].ulParam1;
- ulParam2 = g_pMQ[g_ulMQRead].ulParam2;
- //
- // Remove this message from the queue.
- //
- g_ulMQRead = (g_ulMQRead + 1) % QUEUE_SIZE;
- //
- // See if this message should be sent via a post-order or pre-order
- // search.
- //
- if(ulFlags & MQ_FLAG_POST_ORDER)
- {
- //
- // Send this message with a post-order search of the widget tree.
- //
- WidgetMessageSendPostOrder(pWidget, ulMessage, ulParam1, ulParam2,
- ((ulFlags & MQ_FLAG_STOP_ON_SUCCESS) ?
- 1 : 0));
- }
- else
- {
- //
- // Send this message with a pre-order search of the widget tree.
- //
- WidgetMessageSendPreOrder(pWidget, ulMessage, ulParam1, ulParam2,
- ((ulFlags & MQ_FLAG_STOP_ON_SUCCESS) ?
- 1 : 0));
- }
- }
- }
- //*****************************************************************************
- //
- //! Sends a pointer message.
- //!
- //! \param ulMessage is the pointer message to be sent.
- //! \param lX is the X coordinate associated with the message.
- //! \param lY is the Y coordinate associated with the message.
- //!
- //! This function sends a pointer message to the root widget. A pointer driver
- //! (such as a touch screen driver) can use this function to deliver pointer
- //! activity to the widget tree without having to have direct knowledge of the
- //! structure of the widget framework.
- //!
- //! \return Returns 1 if the message was added to the queue, and 0 if it could
- //! not be added since the queue is full.
- //
- //*****************************************************************************
- int
- WidgetPointerMessage(unsigned int ulMessage, int lX, int lY)
- {
- //
- // Add the message to the widget message queue.
- //
- return(WidgetMessageQueueAdd(WIDGET_ROOT, ulMessage, lX, lY, 1, 1));
- }
- //*****************************************************************************
- //
- // Close the Doxygen group.
- //! @}
- //
- //*****************************************************************************
|