第12课 - 注释符号
第12课 - 注释符号
1. 下面的注释正确吗?
在现代软件开发中,代码量动辄几十万行,这么庞大的程序非常需要注释,否则代码可能看的一头雾水。
先检验一下大家对注释的掌握程度,下面这个程序中的注释都正确吗?
1 #include<stdio.h> 2 3 int main() 4 { 5 int/**/i; 6 7 char* s = "abcdefg //ijklmn"; 8 9 //Is it a \ 10 valid comment? 11 12 in/**/t j; 13 14 return 0; 15 }
怎么验证上面的注释是否正确呢?因为注释是由预处理器处理的,我们使用 gcc -E命令 预处理上面的代码,看处理结果是什么样的。
1 root@ubuntu:/home/swj/c_course/ch_12# gcc -E 12-1.c 2 # 1 "12-1.c" 3 # 1 "<built-in>" 4 # 1 "<command-line>" 5 # 1 "/usr/include/stdc-predef.h" 1 3 4 6 # 1 "<command-line>" 2 7 # 1 "12-1.c" 8 9 10 int main() 11 { 12 int i; 这里注释被替换成了空格 13 14 char* s = "abcdefg //ijklmn"; 字符串字面量中的注释没有起效 15 16 由接续符连接的两行代码被注释掉了 17 18 19 in t j; 这里注释被替换成了空格,引起了语法错误 20 21 return 0; 22 }
为什么结果是这样的呢?我们来看下C语言中注释的规则。
2. 注释的规则
(1)预处理器在处理注释时,使用空格替换整个注释
(2)字符串字面量中的 // 和 /*...*/ 不代表注释符号,即注释无效
(3)/*...*/ 型注释不能被嵌套
了解了这三条规则之后,再分析前面代码的预处理结果就很明了了。
3. 有趣的问题
你觉得 y= x/*p; 是什么意思?
作者本意是将x除以*p的结果赋值给y。那实际是什么样的呢?我们写代码测试一下。
1 int main() 2 { 3 int x = 2; 4 int y = 1; 5 int *p = &y; 6 7 y = x/*p; 8 9 return 0; 10 }
从代码提示中可以看到 /* 后面的代码全部被当做注释了,我们编译这个代码也报错了,可见这里语法有问题。
为什么会产生这个结果呢?编译器将 /* 作为一段注释的开始,把 /* 后的内容和都当成注释内容,直到 */ 出现为止。
在编译器看来,注释和其它程序元素是平等的。因此,作为工程师不能轻视注释。
解决方法:将 / 两边各加一个空格,防止 / 与 * 结合就可以了。
4. 糟糕的注释
(1)教科书型注释!注释用于阐述原因和意图而不是描述程序的运行过程,下面的注释对理解程序毫无帮助!
1 int main() 2 { 3 r = n / 2; //r是n的一半 4 while ((r - n / r) <= t) //循环,仅当r - n/r 不大于t 5 { 6 } 7 8 r = r + n * t; //对变量r进行赋值 9 n++; //变量n自增1 10 11 return 0; 12 }
(2)迷惑型的注释!写注释不是晒心情,必须无二义性,起到对代码进行提示的作用,避免使用缩写!
下面的注释中,0x723是10进制的1827,是贝多芬去世的那一年。R.I.P.L.V.B是Rest In Peace. Ludwig Van Beethoven.(路德维希·凡·贝多芬安息吧!)的缩写。 鬼能看懂!!!
1 int main() 2 { 3 init(); 4 5 //...... 6 //...... 7 8 sad = 0x723; //R.I.P.L.V.B. 9 10 //...... 11 //...... 12 13 finalize(); 14 15 return 0; 16 }
(3)忽悠型注释!注释是对代码的提示,避免臃肿和喧宾夺主。
1 int main() 2 { 3 //...... 4 //...... 5 6 //Bob 07/24/1995 7 /*我知道这个问题很难解决而且现在必须依赖于这个contains函数 8 *但我以后会用一种更加直观优雅有意义的方式重写这段代码。 9 *现在这么做只是由于时间紧近,但我一定会解决的。 10 */ 11 12 if (contains(s, "error")) 13 { 14 exit(1); 15 } 16 17 //...... 18 //...... 19 20 return 0; 21 }
(4)搞笑型注释!佛祖是佛学专业的大师,但是没学过编程,因此保佑不了你,你只能靠自己避开bug。
看了上面那么多糟糕的注释之后,大家肯定很想知道正确的注释是什么样的,下面展示一下高通公司(Qualcomm)代码中的注释是如何写的。
1 /* 2 ======================================================================== 3 4 FILE: Form.c 5 6 SERVICES: 7 8 GENERAL DESCRIPTION: Concrete implementation of RootForm and base IForm 9 methods 10 11 ======================================================================== 12 ======================================================================== 13 14 Copyright ?1999-2005 QUALCOMM Incorporated 15 All Rights Reserved. 16 QUALCOMM Proprietary/GTDR 17 18 ======================================================================== 19 ======================================================================== 20 */ 21 22 23 /*================================================================================== 24 XXXXXXX Confidential Proprietary 25 (c) Copyright XXXXXXX - All Rights Reserved 26 27 Revision History: 28 Modification 29 Author Date CR Number Major Changes 30 ---------------------- ------------ ------------ ---------------------------- 31 Daniel Rossler 01/18/2007 LIBkk94550 Add check for NULL pointers 32 in order to avoid a panic 33 ==================================================================================*/ 34 35 36 37 #include "FormBase.h" 38 39 #include "AEESoftkeyWidget.h" 40 #include "AEEImageWidget.h" 41 #include "AEEStaticWidget.h" 42 #include "AEEImageStaticWidget.h" 43 #include "AEERootContainer.h" 44 #include "AEEWProperties.h" 45 #include "AEEVectorModel.h" 46 47 #include "AEEWeb.h" 48 49 #include "AEERootForm.h" 50 #include "AEEResFile.h" 51 52 #include "FormUtil.h" 53 #include "AEEDisplayCanvas.h" 54 55 #define FORMSTACK_MIN 10 56 #define FORMSTACK_GROW 2 57 58 ///////////////////////////////////////////////////////////////// 59 // RootForm 60 61 typedef struct RootForm { 62 Form base; 63 64 IRootContainer * piContainer; 65 AEERect rcContainer; 66 AEERect rcClient; 67 68 IVectorModel * piForms; 69 ModelListener mlFormActive; 70 ModelListener mlFormTopmostNonPopup; 71 72 IWidget * piTitle; 73 ImageStaticInfo titleInfo; 74 IWidget * piSoftkeys; 75 IWidget * piBackground; 76 77 IWidget * piActiveWidget; 78 79 IResFile * piThemeFile; 80 const char * themeFile; 81 } RootForm; 82 83 #define DECL(c) c* me = (c *)po 84 85 static __inline IForm *ROOTFORM_TO_IFORM(RootForm *me) { 86 return (IForm *)me; 87 } 88 89 static __inline Form *ROOTFORM_TO_FORM(RootForm *me) { 90 return (Form *)me; 91 } 92 93 static __inline IRootForm *ROOTFORM_TO_IROOTFORM(RootForm *me) { 94 return (IRootForm *)me; 95 } 96 97 static void RootForm_FreeFormEntry(IForm *po) 98 { 99 IFORM_Release(po); 100 } 101 102 static void RootForm_UpdateClientArea(RootForm *me) 103 { 104 WidgetPos pos; 105 WExtent titleExtent, skExtent; 106 107 if (me->piSoftkeys) { 108 IWIDGET_GetExtent(me->piSoftkeys, &skExtent); 109 110 // Adjust softkey position based on current height 111 IROOTCONTAINER_GetPos(me->piContainer, me->piSoftkeys, &pos); 112 pos.y = me->rcContainer.dy - skExtent.height; 113 IROOTCONTAINER_SetPos(me->piContainer, me->piSoftkeys, WIDGET_ZNORMAL, &pos); 114 } else { 115 SETWEXTENT(&skExtent, 0, 0); 116 } 117 118 if (me->piTitle) { 119 IWIDGET_GetExtent(me->piTitle, &titleExtent); 120 } else { 121 SETWEXTENT(&titleExtent, 0, 0); 122 } 123 124 // Calculate client area 125 SETAEERECT(&me->rcClient, 0, titleExtent.height, 126 me->rcContainer.dx, 127 me->rcContainer.dy - skExtent.height - titleExtent.height); 128 } 129 130 131 static void RootForm_UpdateTheme(RootForm *me, const char *baseName) 132 { 133 WExtent wextent; 134 135 BUIT_LOG("FORMS EVT: Update Theme Started for %s", baseName); 136 137 if (!me->piThemeFile) 138 return; 139 140 if (me->piTitle) { 141 IWIDGET_SetProperties(me->piTitle, me->piThemeFile, baseName, "Title", "Properties", 0); 142 IWIDGET_GetPreferredExtent(me->piTitle, &wextent); 143 wextent.width = me->rcContainer.dx; 144 IWIDGET_SetExtent(me->piTitle, &wextent); 145 } 146 147 if (me->piSoftkeys) { 148 IWIDGET_SetProperties(me->piSoftkeys, me->piThemeFile, baseName, "Softkeys", "Properties", 0); 149 IWIDGET_GetPreferredExtent(me->piSoftkeys, &wextent); 150 wextent.width = me->rcContainer.dx; 151 IWIDGET_SetExtent(me->piSoftkeys, &wextent); 152 } 153 154 if (me->piBackground) { 155 IWIDGET_SetProperties(me->piBackground, me->piThemeFile, baseName, "Background", "Properties", 0); 156 } 157 158 // Update client area since sizes may have changed 159 RootForm_UpdateClientArea(me); 160 161 BUIT_LOG("FORMS EVT: Update Theme Finished for %s", baseName); 162 } 163 164 // updates the rootform with the background image, softkey and 165 // title text of the TOS form. 166 static void RootForm_Update(RootForm *me, uint32 dwItemMask, IForm* piForm) 167 { 168 boolean bPopup = 0; 169 170 // get form's popup flag 171 bPopup = IFORM_GetIsPopup(piForm); 172 173 // if the form's widget has changed, update the scroll model 174 // for the scroll indicator in the softkey widget 175 if (dwItemMask & FORMITEM_WIDGET) { 176 177 IWidget *piWidget = NULL; 178 // get form's widget 179 IFORM_GetWidget(piForm, WID_FORM, &piWidget); 180 181 // update the widget and the scroll model 182 if (piWidget) { 183 184 // if the active widget has been changed underneath us... 185 186 if (me->piActiveWidget && piWidget != me->piActiveWidget) { 187 // this block will only be executed when the form widget is changed 188 // by the application logic while the form is active 189 WidgetPos pos; 190 WExtent we; 191 192 IWIDGET_MoveFocus(FORM_WIDGET(me), (IWidget*)WIDGET_FOCUS_NONE); 193 194 IWIDGET_GetExtent(me->piActiveWidget, &we); 195 IWIDGET_SetExtent(piWidget, &we); 196 197 // remove the previously active widget from the root container 198 if (AEE_SUCCESS == IROOTCONTAINER_GetPos(me->piContainer, me->piActiveWidget, &pos)) { 199 IROOTCONTAINER_Remove(me->piContainer, me->piActiveWidget); 200 } 201 202 // add the new widget to the root container 203 IROOTCONTAINER_Insert(me->piContainer, piWidget, WIDGET_ZTOPMOST, &pos); 204 // and remember it fondly 205 RELEASEIF(me->piActiveWidget); 206 me->piActiveWidget = piWidget; 207 ADDREFIF(piWidget); 208 209 // set focus to the new widget 210 IWIDGET_MoveFocus(FORM_WIDGET(me), piWidget); 211 212 } else if (!me->piActiveWidget) { 213 me->piActiveWidget = piWidget; 214 ADDREFIF(piWidget); 215 } 216 217 } 218 219 RELEASEIF(piWidget); 220 } 221 222 223 // if the form's background image has changed... 224 // if form is a popup, then retain the background image 225 // from the previous form 226 if (dwItemMask & FORMITEM_BACKGROUND && me->piBackground && !bPopup) { 227 IImage *pii = NULL; 228 229 // Try to grab the image from the new form. 230 IFORM_GetBGImage(piForm, &pii); 231 232 // If non-existent, try defaulting to the root form 233 if (!pii) IFORM_GetBGImage(ROOTFORM_TO_IFORM(me), &pii); 234 235 // Apply the result (NULL or otherwise) to our background widget 236 IWIDGET_SetImage(me->piBackground, pii); 237 RELEASEIF(pii); 238 } 239 240 // if the form's title text has changed... retain previous title 241 // if we are a popup 242 243 if ((dwItemMask & FORMITEM_TITLE) && me->piTitle && !bPopup) { 244 // Release image. Text is owned by form 245 RELEASEIF(me->titleInfo.piImage); 246 IFORM_GetTextPtr(piForm, FID_TITLE, &me->titleInfo.pwText); 247 IFORM_GetTitleImage(piForm, &me->titleInfo.piImage); 248 249 // Set title info 250 IWIDGET_SetImageStaticInfo(me->piTitle, &me->titleInfo, 0); 251 } 252 253 // if the form's softkey text has changed... 254 if ((dwItemMask & FORMITEM_SOFTKEY) && me->piSoftkeys) { 255 256 IForm* piTopForm = IROOTFORM_GetTopForm(ROOTFORM_TO_IROOTFORM(me)); 257 258 AECHAR *pwsz = NULL; 259 IWidget *piKey = NULL; 260 261 if (piTopForm == piForm) { 262 // set softkey 1 text 263 IFORM_GetTextPtr(piForm, FID_SOFTKEY1, &pwsz); 264 if (AEE_SUCCESS == IWIDGET_GetSoftkey(me->piSoftkeys, PROP_SOFTKEY1, &piKey)) { 265 IWIDGET_SetText(piKey, pwsz, 0); 266 } 267 RELEASEIF(piKey); 268 269 // set softkey 2 text 270 IFORM_GetTextPtr(piForm, FID_SOFTKEY2, &pwsz); 271 if (AEE_SUCCESS == IWIDGET_GetSoftkey(me->piSoftkeys, PROP_SOFTKEY2, &piKey)) { 272 IWIDGET_SetText(piKey, pwsz, 0); 273 } 274 } 275 RELEASEIF(piKey); 276 } 277 278 if ((dwItemMask & FORMITEM_THEME_BASENAME)) { 279 char *baseName = 0; 280 281 IFORM_GetThemeBaseName(piForm, &baseName); 282 RootForm_UpdateTheme(me, baseName); 283 } 284 285 } 286 287 static boolean RootForm_ReplaceWidget(RootForm *me, IWidget **piw, IWidget *piwNew, IWidget *piwBefore) 288 { 289 int result = AEE_SUCCESS; 290 WidgetPos pos; 291 292 if (*piw) { 293 (void) IROOTCONTAINER_GetPos(me->piContainer, *piw, &pos); 294 (void) IROOTCONTAINER_Remove(me->piContainer, *piw); 295 IWIDGET_Release(*piw); 296 } 297 298 if (piwNew) { 299 result = IROOTCONTAINER_Insert(me->piContainer, piwNew, piwBefore, &pos); 300 301 if (result == AEE_SUCCESS) { 302 IWIDGET_AddRef(piwNew); 303 } else { 304 piwNew = NULL; 305 } 306 } 307 308 *piw = piwNew; 309 310 // Do an update since extents may have changed 311 RootForm_UpdateClientArea(me); 312 313 return (AEE_SUCCESS == result); 314 } 315 316 static int RootForm_SetThemeName(RootForm *me, const char *themeFile) 317 { 318 if (!me->piThemeFile) 319 return EBADSTATE; 320 321 FREEIF(me->themeFile); 322 me->themeFile = STRDUP(themeFile); 323 324 IRESFILE_Close(me->piThemeFile); 325 if (themeFile) 326 return IRESFILE_Open(me->piThemeFile, themeFile); 327 else 328 return AEE_SUCCESS; 329 } 330 331 static int RootForm_SetDisplay(RootForm *me, IDisplay *piDisplay) 332 { 333 int nErr = AEE_SUCCESS; 334 IDisplayCanvas *piCanvas = 0; 335 336 nErr = ISHELL_CreateInstance(FORM_SHELL(me), AEECLSID_DISPLAYCANVAS, (void **)&piCanvas); 337 338 if (!nErr) { 339 WExtent extent; 340 WidgetPos pos; 341 342 343 IDISPLAY_SetClipRect(piDisplay, NULL); // reset the clipping rectangle 344 IDISPLAY_GetClipRect(piDisplay, &me->rcContainer); 345 SETAEERECT(&me->rcClient, 0, 0, me->rcContainer.dx, me->rcContainer.dy); 346 347 IDISPLAYCANVAS_SetDisplay(piCanvas, piDisplay); 348 IROOTCONTAINER_SetCanvas(me->piContainer, (ICanvas *)piCanvas, &me->rcContainer); 349 350 if (me->piTitle) { 351 // Set extent, title is already positioned at 0, 0 352 IWIDGET_GetExtent(me->piTitle, &extent); 353 extent.width = me->rcContainer.dx; 354 IWIDGET_SetExtent(me->piTitle, &extent); 355 } 356 357 if (me->piBackground) { 358 // Set extent, background is already positioned at 0, 0 359 extent.width = me->rcContainer.dx; 360 extent.height = me->rcContainer.dy; 361 IWIDGET_SetExtent(me->piBackground, &extent); 362 } 363 364 if (me->piSoftkeys) { 365 // Set extent 366 IWIDGET_GetExtent(me->piSoftkeys, &extent); 367 extent.width = me->rcContainer.dx; 368 IWIDGET_SetExtent(me->piSoftkeys, &extent); 369 // And position at bottom of screen 370 IROOTCONTAINER_GetPos(me->piContainer, me->piSoftkeys, &pos); 371 pos.y = me->rcContainer.dy - extent.height; 372 IROOTCONTAINER_SetPos(me->piContainer, WIDGET_ZNORMAL, me->piSoftkeys, &pos); 373 } 374 } 375 376 RELEASEIF(piCanvas); 377 378 return nErr; 379 } 380 381 382 static void RootForm_ApplyTheme(RootForm *me) 383 { 384 int nrForms, i; 385 386 if (!me->piThemeFile) 387 return; 388 389 nrForms = IVECTORMODEL_Size(me->piForms); 390 for (i = 0; i < nrForms; i++) { 391 IForm *piForm; 392 char* pTheme = 0; 393 IVECTORMODEL_GetAt(me->piForms, i, (void **)&piForm); 394 395 IFORM_GetThemeBaseName(ROOTFORM_TO_IFORM(me), &pTheme); 396 pTheme = (pTheme) ? pTheme : "(None)"; 397 398 BUIT_LOG("FORMS EVT: Apply Theme Started for %s", pTheme); 399 400 IFORM_ApplyTheme(piForm); 401 402 BUIT_LOG("FORMS EVT: Apply Theme Finished for %s", pTheme); 403 } 404 405 if (nrForms == 0) { 406 char *baseName = 0; 407 408 IFORM_GetThemeBaseName(ROOTFORM_TO_IFORM(me), &baseName); 409 #ifdef FEATURE_MOT_BREW 410 if (baseName != NULL) { 411 RootForm_UpdateTheme(me, baseName); 412 } 413 #else 414 RootForm_UpdateTheme(me, baseName); 415 #endif /*FEATURE_MOT_BREW*/ 416 } 417 } 418 419 boolean RootForm_HandleEvent(IRootForm *po, AEEEvent evt, uint16 wParam, uint32 dwParam) 420 { 421 DECL(RootForm); 422 423 if (FORM_WIDGET(me) 424 && IWIDGET_HandleEvent(FORM_WIDGET(me), evt, wParam, dwParam)) 425 return TRUE; 426 427 if (evt == EVT_WDG_GETPROPERTY) { 428 switch(wParam) { 429 case FID_THEME_FNAME: 430 *(const char **)dwParam = me->themeFile; 431 return TRUE; 432 433 case FID_THEME_FILE: 434 *(IResFile **)dwParam = me->piThemeFile; 435 ADDREFIF(me->piThemeFile); 436 return TRUE; 437 438 case WID_TITLE: 439 *(IWidget **)dwParam = me->piTitle; 440 ADDREFIF(me->piTitle); 441 return TRUE; 442 443 case WID_SOFTKEYS: 444 *(IWidget **)dwParam = me->piSoftkeys; 445 ADDREFIF(me->piSoftkeys); 446 return TRUE; 447 448 case WID_BACKGROUND: 449 *(IWidget **)dwParam = me->piBackground; 450 ADDREFIF(me->piBackground); 451 return TRUE; 452 453 case WID_FORM: 454 IROOTCONTAINER_QueryInterface(me->piContainer, AEEIID_WIDGET, (void **)dwParam); 455 return TRUE; 456 457 case WID_CONTAINER: 458 *(IContainer **)dwParam = IROOTCONTAINER_TO_ICONTAINER(me->piContainer); 459 ADDREFIF(me->piContainer); 460 return TRUE; 461 462 default: 463 // Fall back on formbase 464 return Form_HandleEvent(ROOTFORM_TO_IFORM(me), evt, wParam, dwParam); 465 } 466 467 } else if (evt == EVT_WDG_SETPROPERTY) { 468 IForm *piForm = 0; 469 470 switch(wParam) { 471 case FID_ACTIVE: 472 piForm = IROOTFORM_GetTopForm(po); 473 if (piForm) { 474 // Activate or de-activate the top form 475 IFORM_SetProperty(piForm, FID_ACTIVE, dwParam); 476 } 477 // and invalidate root container on activation 478 if ((boolean)dwParam) { 479 IROOTCONTAINER_Invalidate(me->piContainer, 0, 0, 0); 480 } 481 return TRUE; 482 483 case FID_THEME: 484 RootForm_ApplyTheme(me); 485 return TRUE; 486 487 case FID_THEME_FNAME: 488 if (AEE_SUCCESS == RootForm_SetThemeName(me, (const char *)dwParam)) { 489 RootForm_ApplyTheme(me); 490 return TRUE; 491 } 492 return FALSE; 493 494 case FID_BACKGROUND: 495 // If we have a background widget, set the image into it 496 if (me->piBackground) { 497 IWIDGET_SetFormImage(me->piBackground, FORM_SHELL(me), (FormRes *)dwParam); 498 } 499 // Also load the image into our internal form, which will hold it as a default for other forms 500 return Form_HandleEvent(ROOTFORM_TO_IFORM(me), evt, wParam, dwParam); 501 502 case FID_DISPLAY: 503 return AEE_SUCCESS == RootForm_SetDisplay(me, (IDisplay *)dwParam); 504 505 case FID_WPROPS: { 506 WPropDesc *pdesc = (WPropDesc *)dwParam; 507 WResPropDesc wd; 508 509 wd.piResFile = me->piThemeFile; 510 if (pdesc) { 511 wd.args = pdesc->args; 512 wd.piWidget = pdesc->piWidget; 513 } 514 return IWIDGET_SetProperty(pdesc->piWidget, PROP_APPLYWPROPS, (uint32)&wd); 515 } 516 517 case WID_TITLE: 518 return RootForm_ReplaceWidget(me, &me->piTitle, (IWidget *)dwParam, WIDGET_ZNORMAL); 519 520 case WID_SOFTKEYS: 521 return RootForm_ReplaceWidget(me, &me->piSoftkeys, (IWidget *)dwParam, WIDGET_ZNORMAL); 522 523 case WID_BACKGROUND: 524 return RootForm_ReplaceWidget(me, &me->piBackground, (IWidget *)dwParam, WIDGET_ZBOTTOMMOST); 525 526 default: 527 // Fall back on formbase 528 return Form_HandleEvent(ROOTFORM_TO_IFORM(me), evt, wParam, dwParam); 529 } 530 } 531 532 // Non get/set property events are sent on to the topmost form 533 { 534 IForm *piForm = IROOTFORM_GetTopForm(po); 535 if (!piForm) 536 return FALSE; 537 else 538 return IFORM_HandleEvent(piForm, evt, wParam, dwParam); 539 } 540 } 541 542 543 static void RootForm_UpdateActiveListenerCB(RootForm *me, FormEvent *pEvent) 544 { 545 if (pEvent->base.evCode == EVT_MDL_FORM_CHANGE) { 546 RootForm_Update(me, pEvent->dwItemMask, pEvent->piForm); 547 } 548 } 549 550 static void RootForm_UpdateTopmostNonPopupListenerCB(RootForm *me, FormEvent *pEvent) 551 { 552 uint32 dwItemMask = pEvent->dwItemMask & (FORMITEM_BACKGROUND | FORMITEM_TITLE | FORMITEM_SOFTKEY); 553 554 if (pEvent->base.evCode == EVT_MDL_FORM_CHANGE && dwItemMask) { 555 RootForm_Update(me, dwItemMask, pEvent->piForm); 556 } 557 } 558 559 static void RootForm_ShowFormWidget(IRootForm *po, IForm *piForm, boolean bShow, boolean bFocus) 560 { 561 DECL(RootForm); 562 WidgetPos pos; 563 IWidget *piWidget; 564 565 if (!piForm) 566 return; 567 568 IFORM_GetWidget(piForm, WID_FORM, &piWidget); 569 570 if (!piWidget) 571 return; 572 573 // Set visibility 574 IROOTCONTAINER_GetPos(me->piContainer, piWidget, &pos); 575 pos.bVisible = bShow; 576 IROOTCONTAINER_SetPos(me->piContainer, piWidget, WIDGET_ZNORMAL, &pos); 577 578 // and set focus to the widget 579 if (bShow && bFocus) { 580 IWIDGET_MoveFocus(FORM_WIDGET(me), piWidget); 581 } else { 582 IWIDGET_MoveFocus(FORM_WIDGET(me), WIDGET_FOCUS_NONE); 583 } 584 585 IWIDGET_Release(piWidget); 586 } 587 588 589 /** Activates a given form. Previous form should have been 590 deactivated before this is called with bActivate set 591 */ 592 static void RootForm_ActivateForm(IRootForm *po, IForm *piForm, boolean bActivate) 593 { 594 DECL(RootForm); 595 596 if (!piForm) 597 return; 598 599 if (bActivate) { 600 // Undo the currently known active widget 601 RELEASEIF(me->piActiveWidget); 602 IFORM_GetWidget(piForm, WID_FORM, &me->piActiveWidget); 603 // Then go update all the items except the forms widget as this is not the 604 // form updating its own widget. Need to update first since theme information 605 // affect client area which affects form activation 606 RootForm_Update(me, FORMITEM_ALL & ~FORMITEM_WIDGET, piForm); 607 // then activate 608 IFORM_Activate(piForm); 609 } else { 610 IFORM_Deactivate(piForm); 611 } 612 } 613 614 static int RootForm_GetFormIndex(RootForm *me, IForm **ppiForm) 615 { 616 IForm *piForm; 617 int nrForms; 618 619 nrForms = IVECTORMODEL_Size(me->piForms); 620 621 if (nrForms > 0) { 622 623 if (*ppiForm == FORM_LAST || *ppiForm == FORM_DEFAULT) { 624 625 IVECTORMODEL_GetAt(me->piForms, nrForms - 1, (void **)ppiForm); 626 return nrForms - 1; 627 628 } else if (*ppiForm == FORM_FIRST) { 629 630 IVECTORMODEL_GetAt(me->piForms, 0, (void **)ppiForm); 631 return 0; 632 633 } else { 634 635 int i; 636 for (i = 0; i < nrForms; i++) { 637 IVECTORMODEL_GetAt(me->piForms, i, (void **)&piForm); 638 if (piForm == *ppiForm) 639 return i; 640 } 641 642 } 643 } 644 645 return -1; 646 } 647 648 static __inline int RootForm_GetFormInsertionIndex(RootForm *me, IForm **ppiForm) 649 { 650 int delta; 651 652 if (*ppiForm == FORM_FIRST) 653 return 0; 654 655 if (*ppiForm == FORM_LAST || *ppiForm == FORM_DEFAULT) { 656 delta = 1; 657 } else { 658 delta = 0; 659 } 660 661 return RootForm_GetFormIndex(me, ppiForm) + delta; 662 } 663 664 static void RootForm_StackChange(IRootForm *po) 665 { 666 DECL(RootForm); 667 IForm* piTopForm = IROOTFORM_GetTopForm(po); 668 669 LISTENER_Cancel(&me->mlFormActive); 670 LISTENER_Cancel(&me->mlFormTopmostNonPopup); 671 672 // If there are still forms on the stack, then we need to set up several things: 673 // 1. The topmost form is the active form 674 // 2. All other forms are not active 675 // 3. The topmost form is being listened to via mlFormActive 676 // 4. The topmost non-popup form is being listened to via mlFormTopmostNonPopup 677 // 5. The topmost non-popup form and all popup forms on top of it are shown 678 // 6. Forms below the topmost non-popup form are now shown 679 if (piTopForm) 680 { 681 boolean bFoundTopmostNonPopup = FALSE; 682 IModel* piModel = NULL; 683 IForm* pif; 684 685 // Logging stack change begin 686 BUIT_LOG("FORMS EVT: Stack Change Starting...", 1); 687 688 // Need to deal with the non-active forms first, then the active form 689 for (pif = piTopForm; pif; pif = IROOTFORM_GetForm(po, pif, FALSE, FALSE)) 690 { 691 boolean bPopup; 692 693 bPopup = IFORM_GetIsPopup(pif); 694 IFORM_GetFormModel(pif, &piModel); 695 if (piModel) 696 { 697 if (pif != piTopForm) 698 { 699 RootForm_ShowFormWidget(po, pif, (boolean)(bFoundTopmostNonPopup? FALSE : TRUE), FALSE); 700 if (IFORM_IsActive(pif)) 701 { 702 RootForm_ActivateForm(po, pif, FALSE); 703 } 704 } 705 706 if (!bPopup && !bFoundTopmostNonPopup) 707 { 708 IMODEL_AddListenerEx(piModel, &me->mlFormTopmostNonPopup, (PFNLISTENER)RootForm_UpdateTopmostNonPopupListenerCB, me); 709 if (pif != piTopForm) 710 // Only update if not the topmost form since the 711 // Activate below applies theme again The topmost 712 // non-popup (but not the top!) influences the 713 // background, title ans associated themes 714 RootForm_Update(me, FORMITEM_BACKGROUND | FORMITEM_TITLE | FORMITEM_THEME_BASENAME, pif); 715 bFoundTopmostNonPopup = TRUE; 716 } 717 } 718 RELEASEIF(piModel); 719 } 720 721 RootForm_ActivateForm(po, piTopForm, TRUE); 722 RootForm_ShowFormWidget(po, piTopForm, TRUE, TRUE); 723 IFORM_GetFormModel(piTopForm, &piModel); 724 if (piModel) 725 IMODEL_AddListenerEx(piModel, &me->mlFormActive, (PFNLISTENER)RootForm_UpdateActiveListenerCB, me); 726 RELEASEIF(piModel); 727 728 // Log that the form is about to be activated - all theme stuff has happened by now) 729 BUIT_LOG("FORMS EVT: Stack Change Finished", 1); 730 731 } 732 733 // Notify change in stack 734 Form_Notify(ROOTFORM_TO_FORM(me), FORMITEM_STACK); 735 } 736 737 738 int RootForm_InsertForm(IRootForm *po, IForm *piForm, IForm *pifBefore) 739 { 740 DECL(RootForm); 741 IWidget *piWidget = 0; 742 IWidget *piwBefore = 0; 743 IForm *pifCurrent; 744 int nrForms, formIndex, nErr; 745 746 if (!piForm) 747 return EBADPARM; 748 749 // Make sure we can insert, get the index we want to insert at 750 formIndex = RootForm_GetFormInsertionIndex(me, &pifBefore); 751 752 if (formIndex < 0) 753 return EBADPARM; 754 755 nrForms = IVECTORMODEL_Size(me->piForms); 756 pifCurrent = IROOTFORM_GetTopForm(po); 757 758 // Get widget to insert 759 IFORM_GetWidget(piForm, WID_FORM, &piWidget); 760 761 // Get widget insertion point. 762 if (formIndex == nrForms || !nrForms) { 763 piwBefore = WIDGET_ZTOPMOST; 764 } else if (pifBefore == FORM_FIRST) { 765 if (me->piBackground != NULL) { 766 767 // If we have a background widget, try to insert the form's widget 768 // above the background widget 769 piwBefore = IROOTCONTAINER_GetWidget(me->piContainer, me->piBackground, TRUE, FALSE); 770 if (piwBefore) { 771 // Add a reference, so it can be released below. 772 IWIDGET_AddRef(piwBefore); 773 } 774 } 775 776 if (!piwBefore) { 777 // No background widget, insert the form's widget at the bottom. 778 piwBefore = WIDGET_ZBOTTOMMOST; 779 } 780 781 } else { 782 IFORM_GetWidget(pifBefore, WID_FORM, &piwBefore); 783 } 784 785 // Make sure we have space for the new form 786 nErr = IVECTORMODEL_EnsureCapacity(me->piForms, MAX(FORMSTACK_MIN, nrForms + 1), FORMSTACK_GROW); 787 788 // Now insert 789 if (!nErr && piWidget && piwBefore) { 790 WidgetPos pos; 791 792 // Not really needed here since Activate does this to, but since 793 // we need to give a position on insert we may as well do it 794 // right 795 pos.x = me->rcClient.x; 796 pos.y = me->rcClient.y; 797 pos.bVisible = (piwBefore == WIDGET_ZTOPMOST); 798 799 // Insert widget into widget stack 800 nErr = IROOTCONTAINER_Insert(me->piContainer, piWidget, piwBefore, &pos); 801 } 802 803 if (!nErr) { 804 char* pTheme = 0; 805 806 // Add form to formstack 807 IVECTORMODEL_InsertAt(me->piForms, formIndex, piForm); 808 IFORM_AddRef(piForm); 809 810 // Set rootform 811 IFORM_SetProperty(piForm, FID_ROOT, (uint32)po); 812 813 // Log info 814 IFORM_GetThemeBaseName(ROOTFORM_TO_IFORM(me), &pTheme); 815 pTheme = (pTheme) ? pTheme : "(None)"; 816 817 BUIT_LOG("FORMS EVT: Insert Set Theme Started for %s", pTheme); 818 819 // Set theme on new form 820 IFORM_ApplyTheme(piForm); 821 822 BUIT_LOG("FORMS EVT: Insert Set Theme Finished for %s", pTheme); 823 //RootForm_Update(me, FORMITEM_THEME, piForm); 824 825 RootForm_StackChange(po); 826 827 } 828 829 RELEASEIF(piWidget); 830 if (piwBefore != WIDGET_ZTOPMOST && piwBefore != WIDGET_ZBOTTOMMOST) 831 RELEASEIF(piwBefore); 832 return nErr; 833 } 834 835 int RootForm_RemoveForm(IRootForm *po, IForm *piForm) 836 { 837 DECL(RootForm); 838 IWidget *piWidget = 0; 839 IForm *piF = 0; 840 int nrForms = 0; 841 int formIndex; 842 boolean bOnlyPopups = 1; 843 844 if (me->piForms) 845 nrForms = IVECTORMODEL_Size(me->piForms); 846 847 if (piForm == FORM_ALL) { 848 while (nrForms > 0) { 849 IROOTFORM_RemoveForm(po, FORM_LAST); 850 nrForms = IVECTORMODEL_Size(me->piForms); 851 } 852 853 } else { 854 formIndex = RootForm_GetFormIndex(me, &piForm); 855 856 if (formIndex < 0) 857 return EBADPARM; 858 859 IFORM_GetWidget(piForm, WID_FORM, &piWidget); 860 861 if (piWidget) { 862 IROOTCONTAINER_Remove(me->piContainer, piWidget); 863 } 864 865 // Hide form widget 866 RootForm_ShowFormWidget(po, piForm, FALSE, FALSE); 867 // Deactivate form 868 RootForm_ActivateForm(po, piForm, FALSE); 869 // Tell it of rootform departure 870 IFORM_SetProperty(piForm, FID_ROOT, 0); 871 // Delete it from the stack 872 IVECTORMODEL_DeleteAt(me->piForms, formIndex); 873 874 RootForm_StackChange(po); 875 876 RELEASEIF(piWidget); 877 878 // Now many forms do we now have? 879 nrForms = IVECTORMODEL_Size(me->piForms); 880 } 881 882 // Cycle through remaining forms to determine type 883 for (piF = IROOTFORM_GetTopForm(po); piF && bOnlyPopups; piF = IROOTFORM_GetForm(po, piF, FALSE, FALSE)) 884 { 885 bOnlyPopups &= IFORM_GetIsPopup(piF); 886 } 887 888 889 if ((0 == nrForms) || bOnlyPopups) 890 { 891 // If we don't have any more forms, or the only forms we do have are popups, 892 // ensure the title has been cleaned (the title memory is owned by the last full screen form, 893 // which may no longer exist). 894 if (me->piTitle) { 895 // Release image. Text is owned by form 896 RELEASEIF(me->titleInfo.piImage); 897 me->titleInfo.pwText = NULL; 898 899 // Set title info 900 IWIDGET_SetImageStaticInfo(me->piTitle, &me->titleInfo, 0); 901 } 902 } 903 904 if (0 == nrForms) { 905 906 // There are no more forms, ensure the softkey labels 907 // have been cleaned (the softkey memory is owned by the form, which may no 908 // longer exist). 909 if (me->piSoftkeys) { 910 IWidget *piKey = NULL; 911 912 (void) IWIDGET_GetSoftkey(me->piSoftkeys, PROP_SOFTKEY1, &piKey); 913 if (piKey) { 914 IWIDGET_SetText(piKey, NULL, 0); 915 IWIDGET_Release(piKey); 916 piKey = NULL; 917 } 918 919 (void) IWIDGET_GetSoftkey(me->piSoftkeys, PROP_SOFTKEY2, &piKey); 920 if (piKey) { 921 IWIDGET_SetText(piKey, NULL, 0); 922 IWIDGET_Release(piKey); 923 piKey = NULL; 924 } 925 926 } 927 } else { 928 RootForm_Update(me, FORMITEM_THEME_BASENAME, IROOTFORM_GetTopForm(po)); 929 } 930 931 return AEE_SUCCESS; 932 } 933 934 935 void RootForm_GetClientRect(IRootForm *po, IXYContainer **ppo, AEERect *rc) 936 { 937 DECL(RootForm); 938 939 if (rc) { 940 *rc = me->rcClient; 941 } 942 943 if (ppo && me->piContainer) { 944 *ppo = IROOTCONTAINER_TO_IXYCONTAINER(me->piContainer); 945 IROOTCONTAINER_AddRef(me->piContainer); 946 } 947 } 948 949 IForm *RootForm_GetForm(IRootForm *po, IForm *pifRef, boolean bNext, boolean bWrap) 950 { 951 DECL(RootForm); 952 IForm *piForm = 0; 953 int nrForms, formIndex; 954 955 if (me->piForms == NULL) 956 return NULL; 957 958 nrForms = IVECTORMODEL_Size(me->piForms); 959 960 if (pifRef == NULL) { 961 formIndex = bNext ? 0 : nrForms - 1; 962 IVECTORMODEL_GetAt(me->piForms, formIndex, (void **)&piForm); 963 return piForm; 964 } 965 966 formIndex = RootForm_GetFormIndex(me, &pifRef); 967 968 if (formIndex < 0) 969 return NULL; 970 971 formIndex += bNext ? 1 : -1; 972 if (formIndex < 0) { 973 formIndex = bWrap ? nrForms - 1 : -1; 974 } else if (formIndex >= nrForms) { 975 formIndex = bWrap ? 0 : - 1; 976 } 977 978 if (formIndex < 0) 979 return NULL; 980 981 IVECTORMODEL_GetAt(me->piForms, formIndex, (void **)&piForm); 982 return piForm; 983 } 984 985 int RootForm_ResolveForm(IRootForm *po, char const *szFormUrl, IForm **ppiForm) 986 { 987 DECL(RootForm); 988 IWebUtil *piWebUtil = 0; 989 AEECLSID formClsId; 990 int result; 991 UrlParts parts; 992 char *path = 0; 993 994 if (!ppiForm || !szFormUrl) 995 return EBADPARM; 996 997 // Assume failure 998 *ppiForm = 0; 999 1000 // Parse the URL 1001 result = ISHELL_CreateInstance(FORM_SHELL(me), AEECLSID_WEBUTIL, (void **) &piWebUtil); 1002 1003 if (result == 0) 1004 result = IWEBUTIL_ParseUrl(piWebUtil, szFormUrl, &parts); 1005 1006 // Check the scheme 1007 if (result == 0 1008 && (!UP_HASSCHM(&parts) || STRNCMP(parts.cpcSchm,FORM_URL_SCHEME,sizeof(FORM_URL_SCHEME)-1))) 1009 result = ESCHEMENOTSUPPORTED; 1010 1011 // Do we have a path? 1012 if (result == 0 1013 && (!UP_HASPATH(&parts) || UP_PATHLEN(&parts) <= 0)) 1014 result = ESCHEMENOTSUPPORTED; 1015 1016 // Extract the path (we need it to be NULL terminated) 1017 if (result == 0 1018 && 0 == (path = MALLOC(UP_PATHLEN(&parts)+1))) 1019 result = ENOMEMORY; 1020 1021 if (result == 0) { 1022 STRNCPY(path, parts.cpcHost, UP_PATHLEN(&parts)+1); 1023 1024 // Does a handler exist for this path, of type AEEIID_FORM? 1025 if (0 == (formClsId = ISHELL_GetHandler(FORM_SHELL(me), AEEIID_FORM, path))) 1026 // Nope... 1027 result = ESCHEMENOTSUPPORTED; 1028 } 1029 1030 if (result == 0) 1031 // Got the actual class id, lets create the form 1032 result = ISHELL_CreateInstance(FORM_SHELL(me), formClsId, (void **) ppiForm); 1033 1034 // 1035 // TODO: We could use IWEBUTIL_ParseFormFields() to parse parts.cpcSrch 1036 // for known Form properties and apply them here... 1037 1038 RELEASEIF(piWebUtil); 1039 FREEIF(path); 1040 1041 return result; 1042 } 1043 1044 void RootForm_Dtor(RootForm *me) 1045 { 1046 IROOTFORM_RemoveForm(ROOTFORM_TO_IROOTFORM(me), FORM_ALL); 1047 1048 RELEASEIF(me->piTitle); 1049 RELEASEIF(me->piSoftkeys); 1050 RELEASEIF(me->piContainer); 1051 RELEASEIF(me->piBackground); 1052 RELEASEIF(me->titleInfo.piImage); 1053 RELEASEIF(me->piForms); 1054 RELEASEIF(me->piActiveWidget); 1055 RELEASEIF(me->piThemeFile); 1056 FREEIF(me->themeFile); 1057 1058 Form_Dtor(&me->base); 1059 } 1060 1061 uint32 RootForm_Release(IRootForm *po) 1062 { 1063 DECL(RootForm); 1064 1065 if (FORM_NREFS(me) == 1) 1066 RootForm_Dtor(me); 1067 1068 return Form_Release(IROOTFORM_TO_IFORM(po)); 1069 } 1070 1071 int RootForm_QueryInterface(IRootForm *po, AEECLSID clsid, void **ppo) 1072 { 1073 if (clsid == AEEIID_ROOTFORM) { 1074 *ppo = po; 1075 Form_AddRef(IROOTFORM_TO_IFORM(po)); 1076 return AEE_SUCCESS; 1077 } 1078 1079 return Form_QueryInterface(IROOTFORM_TO_IFORM(po), clsid, ppo); 1080 } 1081 1082 int RootForm_Construct(RootForm *me, AEEVTBL(IRootForm) *pvt, IModule *piModule, IShell *piShell) 1083 { 1084 int result; 1085 WExtent extent; 1086 WidgetPos pos; 1087 IDisplay *piDisplay = 0; 1088 ICanvas *piCanvas = 0; 1089 1090 Form_Ctor(&me->base, (AEEVTBL(IForm) *)pvt, piModule, piShell, 1091 (PFNHANDLER)RootForm_HandleEvent); 1092 1093 pos.x = 0; 1094 pos.y = 0; 1095 pos.bVisible = TRUE; 1096 SETWEXTENT(&extent, 0, 0); 1097 1098 // Form overrides 1099 pvt->Release = RootForm_Release; 1100 pvt->QueryInterface = RootForm_QueryInterface; 1101 // RootForm definitions 1102 pvt->InsertForm = RootForm_InsertForm; 1103 pvt->RemoveForm = RootForm_RemoveForm; 1104 pvt->GetClientRect = RootForm_GetClientRect; 1105 pvt->GetForm = RootForm_GetForm; 1106 pvt->ResolveForm = RootForm_ResolveForm; 1107 1108 result = ISHELL_CreateInstance(piShell, AEECLSID_VECTORMODEL, (void **)&me->piForms); 1109 1110 if (result == 0) { 1111 IVECTORMODEL_SetPfnFree(me->piForms, (PFNNOTIFY)RootForm_FreeFormEntry); 1112 1113 result = ISHELL_CreateInstance(piShell, AEECLSID_DISPLAY, (void **)&piDisplay); 1114 } 1115 1116 if (result == 0) 1117 result = ISHELL_CreateInstance(piShell, AEECLSID_ROOTCONTAINER, (void **)&me->piContainer); 1118 1119 if (result == 0) 1120 result = IROOTCONTAINER_QueryInterface(me->piContainer, AEEIID_WIDGET, (void **)&me->base.piWidget); 1121 1122 if (result == 0) 1123 result = ISHELL_CreateInstance(piShell, AEECLSID_RESFILE, (void **)&me->piThemeFile); 1124 1125 if (result == 0) 1126 result = ISHELL_CreateInstance(piShell, AEECLSID_IMAGEWIDGET, (void **)&me->piBackground); 1127 1128 if (result == 0) { 1129 IWIDGET_SetFlags(me->piBackground, IDF_ALIGN_RIGHT | IDF_ALIGN_BOTTOM); 1130 1131 // Insert, extent will be fixed up in SetDisplay below 1132 result = IROOTCONTAINER_Insert(me->piContainer, me->piBackground, WIDGET_ZBOTTOMMOST, &pos); 1133 } 1134 1135 if (result == 0) 1136 // Construct title 1137 result = ISHELL_CreateInstance(piShell, AEECLSID_IMAGESTATICWIDGET, (void **)&me->piTitle); 1138 1139 if (result == 0) { 1140 extent.height = 15; 1141 // Set title font to bold by default. Apps and themes can override it. 1142 IWIDGET_SetFontClass(me->piTitle, AEECLSID_FONTSYSBOLD); 1143 1144 IWIDGET_SetShadowOffsetY(me->piTitle, 0); 1145 IWIDGET_SetBorderWidth(me->piTitle, 0); 1146 IWIDGET_SetExtent(me->piTitle, &extent); 1147 // Add to container 1148 result = IROOTCONTAINER_Insert(me->piContainer, me->piTitle, WIDGET_ZTOPMOST, &pos); 1149 } 1150 1151 if (result == 0) 1152 // Construct Softkeys 1153 result = ISHELL_CreateInstance(piShell, AEECLSID_SOFTKEYWIDGET, (void **)&me->piSoftkeys); 1154 1155 if (result == 0) { 1156 IWIDGET_SetShadowOffsetY(me->piSoftkeys, -1); 1157 IWIDGET_SetBorderWidth(me->piSoftkeys, 0); 1158 IWIDGET_SetExtent(me->piSoftkeys, &extent); 1159 IWIDGET_SetLeftPadding(me->piSoftkeys, 2); 1160 IWIDGET_SetRightPadding(me->piSoftkeys, 2); 1161 1162 // Insert at 0, 0. Correct positioning will happen in SetDisplay 1163 result = IROOTCONTAINER_Insert(me->piContainer, me->piSoftkeys, WIDGET_ZTOPMOST, &pos); 1164 } 1165 1166 if (result == 0) 1167 result = RootForm_SetDisplay(me, piDisplay); 1168 1169 if (result == 0) { 1170 char* pTheme = 0; 1171 IFORM_SetThemeBaseName(ROOTFORM_TO_IFORM(me), "Root"); 1172 1173 IFORM_GetThemeBaseName(ROOTFORM_TO_IFORM(me), &pTheme); 1174 pTheme = (pTheme) ? pTheme : "(None)"; 1175 1176 BUIT_LOG("FORMS EVT: Construct Set Theme Started for %s", pTheme); 1177 1178 IROOTFORM_SetThemeFileName(ROOTFORM_TO_IROOTFORM(me), "theme.bar"); 1179 1180 BUIT_LOG("FORMS EVT: Construct Set Theme Finished for %s", pTheme); 1181 1182 } else { 1183 RootForm_Dtor(me); 1184 } 1185 1186 RELEASEIF(piDisplay); 1187 RELEASEIF(piCanvas); 1188 1189 return result; 1190 } 1191 1192 1193 int RootForm_New(IRootForm **ppo, IModule *piModule, IShell *piShell) 1194 { 1195 RootForm *me = MALLOCREC_VTBL(RootForm, IRootForm); 1196 int result; 1197 1198 *ppo = (IRootForm *)me; 1199 1200 if (!me) 1201 return ENOMEMORY; 1202 1203 result = RootForm_Construct(me, GETVTBL(me, IRootForm), piModule, piShell); 1204 1205 if (result != 0) { 1206 *ppo = NULL; 1207 FREE(me); 1208 } 1209 1210 return result; 1211 }