PageRenderTime 128ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ttk.c

https://github.com/MostAwesomeDude/ttk
C | 1988 lines | 1530 code | 356 blank | 102 comment | 429 complexity | 95ada1bfbba16d24dfeb93dd5dac3f0d MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) 2005 Joshua Oreman
  3. *
  4. * This file is a part of TTK.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. #include <ttk.h>
  21. #include <stdio.h>
  22. #include <fcntl.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <dirent.h>
  26. #include <sys/stat.h>
  27. #include <SDL.h>
  28. TWindowStack *ttk_windows = 0;
  29. ttk_font ttk_menufont, ttk_textfont;
  30. ttk_screeninfo *ttk_screen = 0;
  31. ttk_fontinfo *ttk_fonts = 0;
  32. TWidgetList *ttk_header_widgets = 0;
  33. int ttk_button_presstime[128];
  34. int ttk_button_holdsent[128];
  35. int ttk_button_erets[128];
  36. TWidget *ttk_button_pressedfor[128];
  37. int ttk_first_stap, ttk_last_stap, ttk_last_stap_time, ttk_ignore_stap;
  38. int ttk_dirty = 0;
  39. int (*ttk_global_evhandler)(int, int, int);
  40. int (*ttk_global_unusedhandler)(int, int, int);
  41. int ttk_epoch = 0;
  42. static ttk_timer ttk_timers = 0;
  43. static int ttk_transit_frames = 16;
  44. static void (*ttk_clicker)() = ttk_click;
  45. static int ttk_started = 0;
  46. static int ttk_podversion = -1;
  47. static int ttk_scroll_num = 1, ttk_scroll_denom = 1;
  48. static enum ttk_justification header_text_justification = TTK_TEXT_CENTER;
  49. static int header_text_pos = -1;
  50. #ifdef IPOD
  51. #define outl(datum,addr) (*(volatile unsigned long *)(addr) = (datum))
  52. #define inl(addr) (*(volatile unsigned long *)(addr))
  53. #endif
  54. void ttk_widget_nodrawing (TWidget *w, ttk_surface s) {}
  55. int ttk_widget_noaction_2 (TWidget *w, int i1, int i2) { return TTK_EV_UNUSED; }
  56. int ttk_widget_noaction_1 (TWidget *w, int i) { return TTK_EV_UNUSED; }
  57. int ttk_widget_noaction_i0 (TWidget *w) { return 0; }
  58. void ttk_widget_noaction_0 (TWidget *w) {}
  59. #ifdef IPOD
  60. #define FONTSDIR "/usr/share/fonts"
  61. #define SCHEMESDIR "/usr/share/schemes"
  62. #else
  63. #define FONTSDIR "fonts"
  64. #define SCHEMESDIR "schemes"
  65. #endif
  66. static int C_timer_get_current();
  67. static int C_timer_check();
  68. int ttk_version_check (int otherver)
  69. {
  70. int myver = TTK_API_VERSION;
  71. /* version completely equal - OK */
  72. if (myver == otherver)
  73. return 1;
  74. /* version less - some stuff may be missing, won't work */
  75. if (myver < otherver) {
  76. fprintf (stderr, "Error: I was compiled with TTK headers version %x but "
  77. "linked with library version %x.\n", otherver, myver);
  78. return 0;
  79. }
  80. /* minor version more - only stuff added, OK */
  81. if (((myver & ~0xff) == (otherver & ~0xff)) && ((myver & 0xff) >= (otherver & 0xff))) {
  82. fprintf (stderr, "Warning: I was compiled with TTK headers version %x but "
  83. "linked with library version %x.\n "
  84. "This will probably be OK, but you should soon recompile this "
  85. "program completely to fix the problem.\n", otherver, myver);
  86. return 1;
  87. }
  88. /* major version more - won't work */
  89. fprintf (stderr, "Error: I was compiled with TTK headers version %x but "
  90. "linked with library version %x.\n "
  91. "There have been major changes between those versions, so you must "
  92. "recompile this program.\n", otherver, myver);
  93. return 0;
  94. }
  95. void ttk_header_set_text_position( int x )
  96. {
  97. header_text_pos = x;
  98. }
  99. void ttk_header_set_text_justification( enum ttk_justification j )
  100. {
  101. header_text_justification = j;
  102. }
  103. // Returns the number of fonts loaded.
  104. static int ttk_parse_fonts_list (const char *flf)
  105. {
  106. char buf[128];
  107. ttk_fontinfo *current = 0;
  108. int fonts = 0;
  109. FILE *fp = fopen (flf, "r");
  110. if (!fp) return 0;
  111. while (fgets (buf, 128, fp)) {
  112. if (buf[0] == '#') {
  113. continue;
  114. }
  115. if (buf[strlen (buf) - 1] == '\n')
  116. buf[strlen (buf) - 1] = 0;
  117. if (!strlen (buf)) {
  118. continue;
  119. }
  120. if (!strchr (buf, '[') || !strchr (buf, ']') || !strchr (buf, '(') || !strchr (buf, ')') ||
  121. !strchr (buf, '<') || !strchr (buf, '>')) {
  122. fprintf (stderr, "Invalid fonts.lst (bad line: |%s|)\n", buf);
  123. break;
  124. }
  125. if (!ttk_fonts) {
  126. ttk_fonts = current = malloc (sizeof(ttk_fontinfo));
  127. } else {
  128. if (!current) {
  129. current = ttk_fonts;
  130. while (current->next) current = current->next;
  131. }
  132. current->next = malloc (sizeof(ttk_fontinfo));
  133. current = current->next;
  134. }
  135. strncpy (current->file, strchr (buf, '[') + 1, 63);
  136. strncpy (current->name, strchr (buf, '(') + 1, 63);
  137. current->file[63] = current->name[63] = 0;
  138. *strchr (current->file, ']') = 0;
  139. *strchr (current->name, ')') = 0;
  140. current->size = atoi (strchr (buf, '<') + 1);
  141. if (strchr (buf, '{')) {
  142. char *p = strchr (buf, '{') + 1;
  143. int sign = 1;
  144. if (*p == '-') {
  145. sign = -1;
  146. p++;
  147. } else if (*p == '+') {
  148. p++;
  149. }
  150. current->offset = atoi (p) * sign;
  151. } else {
  152. current->offset = 0;
  153. }
  154. current->refs = 0;
  155. current->loaded = 0;
  156. current->next = 0;
  157. fonts++;
  158. }
  159. fclose (fp);
  160. return fonts;
  161. }
  162. static int ttk_parse_fonts_list_dir (const char *dirname)
  163. {
  164. int nfonts = 0;
  165. int cwdfd = open (".", O_RDONLY);
  166. if (chdir (dirname) < 0) {
  167. close (cwdfd);
  168. return 0;
  169. }
  170. DIR *dir = opendir (".");
  171. struct dirent *d;
  172. while ((d = readdir (dir)) != 0) {
  173. if (d->d_name[0] != '.') {
  174. struct stat st;
  175. if (stat (d->d_name, &st) >= 0 && S_ISREG (st.st_mode))
  176. nfonts += ttk_parse_fonts_list (d->d_name);
  177. }
  178. }
  179. closedir (dir);
  180. fchdir (cwdfd);
  181. close (cwdfd);
  182. return nfonts;
  183. }
  184. // Get the font [name] sized closest to [size].
  185. ttk_fontinfo *ttk_get_fontinfo (const char *name, int size)
  186. {
  187. ttk_fontinfo *current = ttk_fonts;
  188. ttk_fontinfo *bestmatch = 0;
  189. int havematch = 0;
  190. int bestmatchsize = -1;
  191. while (current) {
  192. if (strcmp (current->name, name) == 0 && (!current->loaded || current->good)) {
  193. if (current->size == 0) { // scalable font, name match --> go
  194. bestmatch = current;
  195. bestmatchsize = size;
  196. }
  197. if ((bestmatchsize < size && current->size > bestmatchsize) ||
  198. (bestmatchsize > size && current->size < bestmatchsize)) {
  199. bestmatch = current;
  200. bestmatchsize = current->size;
  201. }
  202. }
  203. current = current->next;
  204. }
  205. if (!bestmatch) { // no name matches, try ALL fonts close to that size.
  206. current = ttk_fonts;
  207. while (current) {
  208. if (!current->loaded || current->good) {
  209. if (current->size == 0) { // scalable font --> go
  210. bestmatch = current;
  211. bestmatchsize = size;
  212. }
  213. if ((bestmatchsize < size && current->size > bestmatchsize) ||
  214. (bestmatchsize > size && current->size < bestmatchsize)) {
  215. bestmatch = current;
  216. bestmatchsize = current->size;
  217. }
  218. }
  219. current = current->next;
  220. }
  221. }
  222. if (!bestmatch->loaded) {
  223. char tmp[256];
  224. strcpy (tmp, FONTSDIR);
  225. strcat (tmp, "/");
  226. strcat (tmp, bestmatch->file);
  227. bestmatch->good = 1; // will be unset if bad
  228. ttk_load_font (bestmatch, tmp, bestmatch->size);
  229. bestmatch->f->ofs = bestmatch->offset;
  230. bestmatch->f->fi = bestmatch;
  231. bestmatch->loaded = 1;
  232. if (!bestmatch->good) return ttk_get_fontinfo ("Any Font", 0);
  233. }
  234. bestmatch->refs++;
  235. return bestmatch;
  236. }
  237. ttk_font ttk_get_font (const char *name, int size)
  238. {
  239. return ttk_get_fontinfo (name, size) -> f;
  240. }
  241. void ttk_done_fontinfo (ttk_fontinfo *fi)
  242. {
  243. fi->refs--;
  244. if (fi->refs <= 0) {
  245. ttk_unload_font (fi);
  246. fi->loaded = 0;
  247. }
  248. }
  249. void ttk_done_font (ttk_font f)
  250. {
  251. ttk_done_fontinfo (f->fi);
  252. }
  253. TWindow *ttk_init()
  254. {
  255. TWindow *ret;
  256. ttk_color dots_b;
  257. ttk_color dots_1;
  258. ttk_color dots_2;
  259. ttk_color dots_3;
  260. if (!ttk_screen) {
  261. int ver;
  262. ttk_screen = malloc (sizeof(ttk_screeninfo));
  263. #ifdef IPOD
  264. ver = ttk_get_podversion();
  265. if (ver & (TTK_POD_1G|TTK_POD_2G|TTK_POD_3G|TTK_POD_4G)) {
  266. ttk_screen->w = 160;
  267. ttk_screen->h = 128;
  268. ttk_screen->bpp = 2;
  269. } else if (ver & (TTK_POD_MINI_1G|TTK_POD_MINI_2G)) {
  270. ttk_screen->w = 138;
  271. ttk_screen->h = 110;
  272. ttk_screen->bpp = 2;
  273. } else if (ver & TTK_POD_PHOTO) {
  274. ttk_screen->w = 220;
  275. ttk_screen->h = 176;
  276. ttk_screen->bpp = 16;
  277. } else if (ver & TTK_POD_SANSA) {
  278. ttk_screen->w = 220;
  279. ttk_screen->h = 176;
  280. ttk_screen->bpp = 16;
  281. } else if (ver & TTK_POD_NANO) {
  282. ttk_screen->w = 176;
  283. ttk_screen->h = 132;
  284. ttk_screen->bpp = 16;
  285. } else if (ver & TTK_POD_VIDEO) {
  286. ttk_screen->w = 320;
  287. ttk_screen->h = 240;
  288. ttk_screen->bpp = 16;
  289. } else {
  290. fprintf (stderr, "Couldn't determine your iPod version (v=0%o)\n", ver);
  291. free (ttk_screen);
  292. exit (1);
  293. }
  294. #else
  295. ttk_screen->w = 160;
  296. ttk_screen->h = 128;
  297. ttk_screen->bpp = 2;
  298. #endif
  299. ttk_screen->wx = 0;
  300. if (ttk_screen->bpp == 16) {
  301. if (ttk_screen->h == 176 || ttk_screen->h == 132)
  302. ttk_screen->wy = 21; /* Photo & Nano: 22px header, 22px menu items */
  303. else if (ttk_screen->h == 240)
  304. ttk_screen->wy = 23; /* Video: 24px header, 24px menu items */
  305. else
  306. ttk_screen->wy = 22; /* sensible default for the unknown */
  307. } else {
  308. ttk_screen->wy = 19; /* Reg/Mini: 20px header, 18px menu items */
  309. }
  310. }
  311. ttk_gfx_init();
  312. /* the startup screen dots */
  313. if( ttk_screen->bpp == 2 )
  314. {
  315. dots_b = ttk_makecol( 255, 255, 255 );
  316. dots_1 = dots_2 = dots_3 = ttk_makecol( 0, 0, 0 );
  317. } else {
  318. dots_b = ttk_makecol( 0, 0, 0 );
  319. dots_1 = ttk_makecol( 255, 64, 64 );
  320. dots_2 = ttk_makecol( 64, 255, 64 );
  321. dots_3 = ttk_makecol( 64, 64, 255 );
  322. }
  323. ttk_fillrect (ttk_screen->srf, 0, 0, ttk_screen->w, ttk_screen->h, dots_b );
  324. if( ttk_screen->bpp == 2 )
  325. {
  326. ttk_draw_icon_color( ttk_icon_tux, ttk_screen->srf,
  327. ttk_screen->w/4-16+2, ttk_screen->h/2 - 16,
  328. dots_1, dots_b );
  329. ttk_draw_icon_color( ttk_icon_tux, ttk_screen->srf,
  330. ttk_screen->w/2-16, ttk_screen->h/2 - 16,
  331. dots_1, dots_b );
  332. ttk_draw_icon_color( ttk_icon_tux, ttk_screen->srf,
  333. (ttk_screen->w*3/4)-16+2, ttk_screen->h/2 - 16,
  334. dots_1, dots_b );
  335. } else {
  336. ttk_fillellipse (ttk_screen->srf,
  337. ttk_screen->w/4, ttk_screen->h/2,
  338. 18, 18, dots_1 );
  339. ttk_fillellipse (ttk_screen->srf,
  340. ttk_screen->w/2, ttk_screen->h/2,
  341. 18, 18, dots_2 );
  342. ttk_fillellipse (ttk_screen->srf,
  343. ttk_screen->w*3/4, ttk_screen->h/2,
  344. 18, 18, dots_3 );
  345. ttk_draw_icon_color( ttk_icon_tux, ttk_screen->srf,
  346. ttk_screen->w/4-16+2, ttk_screen->h/2 - 16,
  347. dots_b, dots_1 );
  348. ttk_draw_icon_color( ttk_icon_tux, ttk_screen->srf,
  349. ttk_screen->w/2-16+2, ttk_screen->h/2 - 16,
  350. dots_b, dots_2 );
  351. ttk_draw_icon_color( ttk_icon_tux, ttk_screen->srf,
  352. (ttk_screen->w*3/4)-16+2, ttk_screen->h/2 - 16,
  353. dots_b, dots_3 );
  354. }
  355. ttk_gfx_update (ttk_screen->srf);
  356. int nfonts = 0;
  357. nfonts += ttk_parse_fonts_list (FONTSDIR "/fonts.lst");
  358. nfonts += ttk_parse_fonts_list_dir (FONTSDIR "/fonts.lst.d");
  359. if (!nfonts) {
  360. fprintf (stderr, "No fonts list, or no fonts in it. Make one, or put some in.\n");
  361. ttk_quit();
  362. exit (1);
  363. }
  364. ret = ttk_new_window();
  365. ttk_windows = (TWindowStack *)malloc (sizeof(TWindowStack));
  366. ttk_windows->w = ret;
  367. ttk_windows->minimized = 0;
  368. ttk_windows->next = 0;
  369. ret->onscreen++;
  370. return ret;
  371. }
  372. void ttk_draw_window (TWindow *win)
  373. {
  374. TApItem b, *bg;
  375. ttk_screeninfo *s = ttk_screen;
  376. if (win->background) {
  377. memcpy (&b, win->background, sizeof(TApItem));
  378. } else {
  379. memcpy (&b, ttk_ap_getx ("window.bg"), sizeof(TApItem));
  380. }
  381. b.spacing = 0;
  382. b.type |= TTK_AP_SPACING;
  383. if (win->x > s->wx+2 || win->y > s->wy+2)
  384. b.spacing = ttk_ap_getx ("window.border") -> spacing;
  385. bg = &b;
  386. ttk_ap_fillrect (s->srf, bg, win->x, win->y, win->x + win->w, win->y + win->h);
  387. ttk_blit_image_ex (win->srf, 0, 0, win->w, win->h, s->srf, win->x, win->y);
  388. if (win->x > s->wx || win->y > s->wy) { // popup window
  389. ttk_ap_rect (s->srf, ttk_ap_get ("window.border"), win->x, win->y,
  390. win->x + win->w, win->y + win->h);
  391. }
  392. ttk_dirty |= TTK_DIRTY_WINDOWAREA | TTK_DIRTY_SCREEN;
  393. }
  394. int ttk_button_pressed (int button)
  395. {
  396. return ttk_button_presstime[button];
  397. }
  398. static int iterate_widgets (TWidgetList *wids, int (*func)(TWidget *, int), int arg)
  399. {
  400. TWidgetList *current = wids;
  401. int eret = 0;
  402. while (current) {
  403. eret |= func (current->v, arg);
  404. current = current->next;
  405. }
  406. return eret;
  407. }
  408. static int do_timers (TWidget *wid, int tick)
  409. {
  410. int eret = 0;
  411. if (wid->frame && wid->framedelay && (wid->framelast + wid->framedelay <= tick)) {
  412. wid->framelast = tick;
  413. eret |= wid->frame (wid) & ~TTK_EV_UNUSED;
  414. }
  415. if (wid->timer && wid->timerdelay && (wid->timerlast + wid->timerdelay <= tick)) {
  416. wid->timerlast = tick + 1;
  417. eret |= wid->timer (wid) & ~TTK_EV_UNUSED;
  418. }
  419. return eret;
  420. }
  421. static int do_draw (TWidget *wid, int force)
  422. {
  423. if (wid->dirty || force) {
  424. if (!force)
  425. ttk_fillrect (wid->win->srf, wid->x, wid->y, wid->x + wid->w, wid->y + wid->h,
  426. ttk_makecol (CKEY));
  427. if (wid->win)
  428. wid->draw (wid, wid->win->srf);
  429. else
  430. wid->draw (wid, ttk_screen->srf);
  431. wid->dirty = 0;
  432. return 1;
  433. }
  434. return 0;
  435. }
  436. static int check_dirty (TWidget *wid, int unused)
  437. {
  438. return !!wid->dirty;
  439. }
  440. int ttk_run()
  441. {
  442. ttk_screeninfo *s = ttk_screen;
  443. TWindow *win;
  444. TWidgetList *cur;
  445. TWidget *evtarget; // usually win->focus
  446. int tick, i;
  447. int ev, earg, eret;
  448. int in, st, touch;
  449. int iter = 0;
  450. const char *keys = "mfwd\n", *p;
  451. static int initd = 0;
  452. int local, global;
  453. static int sofar = 0;
  454. int time = 0, hs;
  455. ttk_timer ctim;
  456. int textpos = 0;
  457. TWidget *pf;
  458. ttk_started = 1;
  459. if (!initd) {
  460. for (i = 0; i < 128; i++) {
  461. ttk_button_presstime[i] = 0;
  462. ttk_button_holdsent[i] = 0;
  463. ttk_button_erets[i] = 0;
  464. }
  465. if (!ttk_windows) {
  466. fprintf (stderr, "Run with no windows\n");
  467. ttk_quit();
  468. exit (1);
  469. }
  470. initd = 1;
  471. }
  472. ttk_dirty |= TTK_FILTHY;
  473. while(1) {
  474. if (!ttk_windows)
  475. return 0;
  476. // If all windows are minimized, this'll loop however-many times
  477. // and eventually one of the minimized flags will get reset to 0
  478. // by ttk_move_window().
  479. if (ttk_windows->minimized)
  480. ttk_move_window (ttk_windows->w, 0, TTK_MOVE_END);
  481. win = ttk_windows->w;
  482. if (win->input) evtarget = win->input;
  483. else evtarget = win->focus;
  484. tick = ttk_getticks();
  485. if (win->epoch < ttk_epoch) {
  486. ttk_dirty |= TTK_FILTHY;
  487. win->dirty++;
  488. win->epoch = ttk_epoch;
  489. }
  490. /********** EVENT STUFF **********/
  491. eret = 0;
  492. /*** Do header widget timers, and check for need to redraw the header ***/
  493. if (ttk_header_widgets) {
  494. eret |= iterate_widgets (ttk_header_widgets, do_timers, tick) & ~TTK_EV_UNUSED;
  495. if (win->show_header && iterate_widgets (ttk_header_widgets, check_dirty, 0)) {
  496. ttk_dirty |= TTK_DIRTY_HEADER;
  497. }
  498. }
  499. /*** Do timers for TI, and check if it wants a draw. ***/
  500. if (win->input) {
  501. eret |= do_timers (win->input, tick) & ~TTK_EV_UNUSED;
  502. if (win->input->dirty) {
  503. ttk_dirty |= TTK_DIRTY_INPUT;
  504. }
  505. }
  506. /*** Do timers for widgets. ***/
  507. eret |= iterate_widgets (win->widgets, do_timers, tick) & ~TTK_EV_UNUSED;
  508. /*** Do global timers. ***/
  509. ctim = ttk_timers;
  510. while (ctim) {
  511. if (tick > (ctim->started + ctim->delay)) {
  512. ttk_timer next = ctim->next;
  513. void (*fn)() = ctim->fn;
  514. ttk_destroy_timer (ctim);
  515. ctim = next;
  516. // We delay the call of fn in case it itself
  517. // calls ttk_run() (e.g. for a dialog).
  518. fn();
  519. continue;
  520. }
  521. ctim = ctim->next;
  522. }
  523. /*** Check for events. ***/
  524. if (evtarget && evtarget->rawkeys)
  525. ev = ttk_get_rawevent (&earg);
  526. else
  527. ev = ttk_get_event (&earg);
  528. local = global = 1;
  529. if (!ev)
  530. local = global = 0;
  531. if (!ttk_global_evhandler)
  532. global = 0;
  533. if (ev == TTK_BUTTON_DOWN) {
  534. if (!((ttk_button_pressedfor[earg] == 0 || ttk_button_pressedfor[earg] == evtarget) &&
  535. (ttk_button_presstime[earg] == 0 || ttk_button_presstime[earg] == tick))) // key rept
  536. global = 0;
  537. }
  538. if (!evtarget) local = 0;
  539. if (global) {
  540. local &= !ttk_global_evhandler (ev, earg, tick - ttk_button_presstime[earg]);
  541. }
  542. if (ev == TTK_SCROLL) {
  543. if (ttk_scroll_denom > 1) {
  544. sofar += earg;
  545. if (sofar > -ttk_scroll_denom && sofar < ttk_scroll_denom) local = 0;
  546. else if (sofar < 0) {
  547. while (sofar <= -ttk_scroll_denom) sofar += ttk_scroll_denom;
  548. } else {
  549. while (sofar >= ttk_scroll_denom) sofar -= ttk_scroll_denom;
  550. }
  551. }
  552. earg *= ttk_scroll_num;
  553. }
  554. /*** Send events. ***/
  555. switch (ev) {
  556. case TTK_BUTTON_DOWN:
  557. if (!ttk_button_presstime[earg] || !ttk_button_pressedfor[earg]) { // don't reset with key-repted buttons
  558. ttk_button_presstime[earg] = tick;
  559. ttk_button_pressedfor[earg] = evtarget;
  560. ttk_button_holdsent[earg] = 0;
  561. }
  562. // Don't send different parts of same keyt-rept to different widgets:
  563. if (local && (ttk_button_pressedfor[earg] == evtarget) &&
  564. ((ttk_button_presstime[earg] == tick) || evtarget->keyrepeat))
  565. {
  566. int er = evtarget->down (evtarget, earg);
  567. ttk_button_erets[earg] |= er; eret |= er & ~TTK_EV_UNUSED;
  568. }
  569. break;
  570. case TTK_BUTTON_UP:
  571. time = tick - ttk_button_presstime[earg];
  572. pf = ttk_button_pressedfor[earg];
  573. hs = ttk_button_holdsent[earg];
  574. // Need to be before, in case button() launches its own ttk_run().
  575. ttk_button_presstime[earg] = 0;
  576. ttk_button_holdsent[earg] = 0;
  577. ttk_button_pressedfor[earg] = 0;
  578. if (evtarget == pf && local && !hs) {
  579. int er = evtarget->button (evtarget, earg, time);
  580. // If *both* down and button returned unused, do unused. Otherwise,
  581. // don't.
  582. eret |= er;
  583. if (!((er & TTK_EV_UNUSED) && (ttk_button_erets[earg] & TTK_EV_UNUSED))) {
  584. eret &= ~TTK_EV_UNUSED;
  585. } else {
  586. eret |= TTK_EV_UNUSED;
  587. }
  588. }
  589. ttk_button_erets[earg] = 0;
  590. break;
  591. case TTK_SCROLL:
  592. if (local)
  593. eret |= evtarget->scroll (evtarget, earg) & ~TTK_EV_UNUSED;
  594. break;
  595. }
  596. /*** Check more events. ***/
  597. if (evtarget) {
  598. // held
  599. for (p = keys; *p; p++) {
  600. if (ttk_button_presstime[*p] && (tick - ttk_button_presstime[*p] >= evtarget->holdtime) && !ttk_button_holdsent[*p] && (evtarget->held != ttk_widget_noaction_1)) {
  601. int er = evtarget->held (evtarget, *p);
  602. if (!(er & TTK_EV_UNUSED)) {
  603. eret |= er;
  604. ttk_button_holdsent[*p] = 1;
  605. }
  606. }
  607. // If user pushes a button on clickwheel, it'll also register as a tap.
  608. // Counter that.
  609. if (ttk_button_presstime[*p] && (ttk_get_podversion() & TTK_POD_PP502X) &&
  610. ttk_last_stap_time) ttk_ignore_stap = 1;
  611. }
  612. // stap
  613. #ifdef IPOD
  614. if (ttk_get_podversion() & TTK_POD_PP502X) {
  615. in = inl (0x7000C140);
  616. st = (in & 0x40000000);
  617. touch = (in & 0x007F0000) >> 16;
  618. if (st) {
  619. if (!ttk_last_stap_time) {
  620. ttk_first_stap = touch;
  621. ttk_last_stap_time = tick;
  622. }
  623. ttk_last_stap = touch;
  624. } else if (ttk_last_stap_time) {
  625. // Heuristic: finger moved <1/20 of wheel, held for <2/5 sec.
  626. if ((abs(ttk_last_stap - ttk_first_stap) <= 5) &&
  627. ((tick - ttk_last_stap_time) <= 400) &&
  628. !ttk_ignore_stap)
  629. {
  630. eret |= evtarget->stap (evtarget, ttk_first_stap);
  631. }
  632. // Even if it didn't match, reset it. Otherwise, no taps will be
  633. // recorded once you scroll.
  634. ttk_last_stap_time = 0;
  635. ttk_ignore_stap = 0;
  636. }
  637. }
  638. #else
  639. if (ev == TTK_BUTTON_UP) {
  640. switch (earg) {
  641. case '7': eret |= evtarget->stap (evtarget, 84); break;
  642. case '8': eret |= evtarget->stap (evtarget, 0); break;
  643. case '9': eret |= evtarget->stap (evtarget, 12); break;
  644. case '6': eret |= evtarget->stap (evtarget, 24); break;
  645. case '3': eret |= evtarget->stap (evtarget, 36); break;
  646. case '2': eret |= evtarget->stap (evtarget, 48); break;
  647. case '1': eret |= evtarget->stap (evtarget, 60); break;
  648. case '4': eret |= evtarget->stap (evtarget, 72); break;
  649. default: break;
  650. }
  651. }
  652. #endif
  653. }
  654. /*** Process text input events. ***/
  655. while (win->inbuf_start != win->inbuf_end) {
  656. if (win->focus) // NOT evtarget, that's probably the TI method
  657. eret |= win->focus->input (win->focus, win->inbuf[win->inbuf_start]) & ~TTK_EV_UNUSED;
  658. win->inbuf_start++;
  659. win->inbuf_start &= 0x1f;
  660. }
  661. /********** DRAWING STUFF **********/
  662. if (!ttk_windows) return 0;
  663. win = ttk_windows->w; // Yes, again; ttk_show_window() might've been called by an event.
  664. /*** Draw header, if necessary ***/
  665. if ((ttk_dirty & TTK_DIRTY_HEADER) && win->show_header) {
  666. const char * displayTitle = ttk_filter_sorting_characters( win->title );
  667. /* Clear it */
  668. ttk_ap_fillrect (s->srf, ttk_ap_get ("header.bg"), 0, 0, s->w, s->wy + ttk_ap_getx ("header.line") -> spacing);
  669. /* Draw the widgets */
  670. if (ttk_header_widgets) iterate_widgets (ttk_header_widgets, do_draw, 1);
  671. /* Draw title */
  672. /* autocenter if unset */
  673. textpos = ((header_text_pos>=0)?header_text_pos:((s->w)>>1));
  674. switch( header_text_justification ) {
  675. case( TTK_TEXT_LEFT ):
  676. break;
  677. case( TTK_TEXT_RIGHT ):
  678. textpos -= ttk_text_width( ttk_menufont, displayTitle);
  679. break;
  680. case( TTK_TEXT_CENTER ):
  681. default:
  682. textpos -= (ttk_text_width( ttk_menufont, displayTitle)>>1);
  683. break;
  684. }
  685. ttk_text (s->srf, ttk_menufont, textpos,
  686. (s->wy - ttk_text_height (ttk_menufont)) / 2,
  687. ttk_ap_getx ("header.fg") -> color, displayTitle );
  688. /* Draw line */
  689. ttk_ap_hline (s->srf, ttk_ap_get ("header.line"), 0, s->w, s->wy);
  690. ttk_dirty &= ~TTK_DIRTY_HEADER;
  691. ttk_dirty |= TTK_DIRTY_SCREEN;
  692. }
  693. /*** Redraw the widgets in the window, if it's dirty. ***/
  694. if (win->dirty) {
  695. ttk_fillrect (win->srf, 0, 0, win->w, win->h, ttk_makecol (CKEY));
  696. iterate_widgets (win->widgets, do_draw, 1);
  697. ttk_dirty |= TTK_DIRTY_WINDOWAREA;
  698. win->dirty = 0;
  699. }
  700. /*** Draw widgets that need it. ***/
  701. if (iterate_widgets (win->widgets, do_draw, 0)) {
  702. ttk_dirty |= TTK_DIRTY_WINDOWAREA;
  703. }
  704. /*** Draw the window surface to the screen surface. ***/
  705. if (ttk_dirty & TTK_DIRTY_WINDOWAREA) {
  706. TApItem b, *bg;
  707. if (win->background) {
  708. memcpy (&b, win->background, sizeof(TApItem));
  709. } else {
  710. memcpy (&b, ttk_ap_getx ("window.bg"), sizeof(TApItem));
  711. }
  712. b.spacing = 0;
  713. b.type |= TTK_AP_SPACING;
  714. if (win->x > s->wx+2 || win->y > s->wy+2)
  715. b.spacing = ttk_ap_getx ("window.border") -> spacing;
  716. bg = &b;
  717. ttk_ap_fillrect (s->srf, bg, win->x, win->y, win->x + win->w, win->y + win->h);
  718. ttk_blit_image_ex (win->srf, 0, 0, win->w, win->h, s->srf, win->x, win->y);
  719. if (win->x > s->wx+2 || win->y > s->wy+2) { // popup window
  720. ttk_ap_rect (s->srf, ttk_ap_get ("window.border"), win->x, win->y,
  721. win->x + win->w, win->y + win->h);
  722. }
  723. if( win->show_header )
  724. ttk_ap_hline (s->srf, ttk_ap_get ("header.line"), 0, s->w, s->wy);
  725. ttk_dirty &= ~TTK_DIRTY_WINDOWAREA;
  726. ttk_dirty |= TTK_DIRTY_SCREEN;
  727. }
  728. /*** Redraw input if necessary. ***/
  729. if ((ttk_dirty & TTK_DIRTY_INPUT) && win->input) {
  730. ttk_ap_fillrect (s->srf, ttk_ap_get ("window.bg"), win->input->x, win->input->y,
  731. win->input->x + win->input->w, win->input->y + win->input->h);
  732. if (ttk_ap_get ("window.border")) {
  733. TApItem border;
  734. memcpy (&border, ttk_ap_getx ("window.border"), sizeof(TApItem));
  735. border.spacing = -1;
  736. ttk_ap_rect (s->srf, &border, win->input->x, win->input->y,
  737. win->input->x + win->input->w, win->input->y + win->input->h);
  738. }
  739. win->input->draw (win->input, s->srf);
  740. ttk_dirty &= ~TTK_DIRTY_INPUT;
  741. ttk_dirty |= TTK_DIRTY_SCREEN;
  742. }
  743. /********** FINISHING UP **********/
  744. /*** Handle appropriate event actions. ***/
  745. if (eret & TTK_EV_CLICK)
  746. (*ttk_clicker)();
  747. if (eret & TTK_EV_DONE)
  748. return (eret >> 8);
  749. if ((eret & TTK_EV_UNUSED) && ttk_global_unusedhandler)
  750. eret |= ttk_global_unusedhandler (ev, earg, time);
  751. /*** Update the screen if we need it. ***/
  752. if (ttk_dirty & TTK_DIRTY_SCREEN) {
  753. ttk_gfx_update (ttk_screen->srf);
  754. ttk_dirty &= ~TTK_DIRTY_SCREEN;
  755. }
  756. #if !defined(IPOD) && !defined(SDL)
  757. ttk_delay(30);
  758. #endif
  759. }
  760. }
  761. void ttk_click_ex(int period, int duration)
  762. {
  763. period = period ? MIN(MAX(period, 5), 250) : 20; // period: 40=2286Hz, 30=3024Hz, 20=4465Hz, 10=8547Hz
  764. duration = MIN(MAX(duration, 1), 1000); //duration in millieconds.
  765. #ifdef IPOD
  766. if (ttk_get_podversion() & TTK_POD_PP502X) {
  767. outl(inl(0x70000010) & ~0xc, 0x70000010);
  768. outl(inl(0x6000600c) | 0x20000, 0x6000600c); /* enable device */
  769. outl(0x80000000 | 0x800000 | (period & 0xffff), 0x7000a000); /* set pitch */
  770. int starttime = C_timer_get_current();
  771. while (!C_timer_check (starttime, duration * 1000)); // milliseconds to microseconds (ms*1000)
  772. outl(0x0, 0x7000a000); /* piezo off */
  773. } else {
  774. static int fd = -1;
  775. static char buf;
  776. if (fd == -1 && (fd = open("/dev/ttyS1", O_WRONLY)) == -1
  777. && (fd = open("/dev/tts/1", O_WRONLY)) == -1) {
  778. return;
  779. }
  780. write(fd, &buf, 1);
  781. }
  782. #endif
  783. }
  784. void ttk_click()
  785. { ttk_click_ex(20, 2); }
  786. void ttk_quit()
  787. {
  788. ttk_gfx_quit();
  789. ttk_stop_cop();
  790. }
  791. static long iPod_GetGeneration()
  792. {
  793. int i;
  794. char cpuinfo[256];
  795. char *ptr;
  796. FILE *file;
  797. if ((file = fopen("/proc/cpuinfo", "r")) != NULL) {
  798. while (fgets(cpuinfo, sizeof(cpuinfo), file) != NULL)
  799. if (strncmp(cpuinfo, "Revision", 8) == 0)
  800. break;
  801. fclose(file);
  802. }
  803. for (i = 0; !isspace(cpuinfo[i]); i++);
  804. for (; isspace(cpuinfo[i]); i++);
  805. ptr = cpuinfo + i + 2;
  806. return strtol(ptr, NULL, 16);
  807. }
  808. static int ttk_get_podversion_raw()
  809. {
  810. #ifdef IPOD
  811. static int ver;
  812. if (!ver) ver = iPod_GetGeneration();
  813. switch (ver >> 16) {
  814. case 0x0: return TTK_POD_SANSA;
  815. case 0x1: return TTK_POD_1G;
  816. case 0x2: return TTK_POD_2G;
  817. case 0x3: return TTK_POD_3G;
  818. case 0x4: return TTK_POD_MINI_1G;
  819. case 0x5: return TTK_POD_4G;
  820. case 0x6: return TTK_POD_PHOTO;
  821. case 0x7: return TTK_POD_MINI_2G;
  822. case 0xB: return TTK_POD_VIDEO;
  823. case 0xC: return TTK_POD_NANO;
  824. default: return 0;
  825. }
  826. #else
  827. return TTK_POD_X11;
  828. #endif
  829. }
  830. int ttk_get_podversion()
  831. {
  832. if (ttk_podversion == -1)
  833. ttk_podversion = ttk_get_podversion_raw();
  834. return ttk_podversion;
  835. }
  836. void ttk_get_screensize (int *w, int *h, int *bpp)
  837. {
  838. if (!ttk_screen) return;
  839. if (w) *w = ttk_screen->w;
  840. if (h) *h = ttk_screen->h;
  841. if (bpp) *bpp = ttk_screen->bpp;
  842. }
  843. #ifndef IPOD
  844. typedef struct sdl_additional {
  845. Uint32 video_flags;
  846. Uint32 video_flags_mask;
  847. } sdl_additional;
  848. extern sdl_additional sdl_add;
  849. #endif
  850. #ifndef ABS
  851. #define ABS( A ) ( ((A)<0)?-(A):(A) )
  852. #endif
  853. void ttk_set_emulation (int w, int h, int bpp)
  854. {
  855. #ifndef IPOD
  856. if (!ttk_screen)
  857. ttk_screen = malloc (sizeof(struct ttk_screeninfo));
  858. ttk_screen->w = ABS( w );
  859. ttk_screen->h = ABS( h );
  860. ttk_screen->bpp = ABS( bpp );
  861. if( bpp<0 || w<0 || h<0 ) {
  862. sdl_add.video_flags = SDL_FULLSCREEN;
  863. sdl_add.video_flags_mask = SDL_FULLSCREEN;
  864. }
  865. ttk_screen->wx = 0;
  866. if (ttk_screen->bpp == 16) {
  867. ttk_screen->wy = 22; /* Photo: 22px header, 22px menu items */
  868. } else {
  869. ttk_screen->wy = 20; /* Reg/Mini: 20px header, 18px menu items */
  870. }
  871. #endif
  872. }
  873. ttk_fontinfo *ttk_get_fontlist()
  874. {
  875. return ttk_fonts;
  876. }
  877. TWindow *ttk_new_window()
  878. {
  879. TWindow *ret = calloc (1, sizeof(TWindow));
  880. ret->show_header = 1;
  881. ret->titlefree = 0;
  882. ret->widgets = 0;
  883. ret->x = ttk_screen->wx;
  884. ret->y = ttk_screen->wy;
  885. ret->w = ttk_screen->w - ttk_screen->wx;
  886. ret->h = ttk_screen->h - ttk_screen->wy;
  887. ret->color = (ttk_screen->bpp == 16);
  888. ret->srf = ttk_new_surface (ttk_screen->w, ttk_screen->h, ret->color? 16 : 2);
  889. ret->background = 0;
  890. ret->focus = ret->input = 0;
  891. ret->dirty = 0;
  892. ret->epoch = ttk_epoch;
  893. ret->inbuf_start = ret->inbuf_end = 0;
  894. ret->onscreen = 0;
  895. if (ttk_windows) {
  896. ret->title = strdup (ttk_windows->w->title);
  897. ret->titlefree = 1;
  898. } else {
  899. ret->title = "TTK";
  900. }
  901. ttk_fillrect (ret->srf, 0, 0, ret->w, ret->h, ttk_makecol (CKEY));
  902. return ret;
  903. }
  904. void ttk_window_show_header (TWindow *win)
  905. {
  906. if (!win->show_header) {
  907. win->show_header = 1;
  908. ttk_dirty |= TTK_FILTHY;
  909. if (win->focus) {
  910. win->focus->h -= 20;
  911. win->focus->dirty++;
  912. }
  913. win->x = ttk_screen->wx;
  914. win->y = ttk_screen->wy;
  915. win->w = ttk_screen->w - win->x;
  916. win->h = ttk_screen->h - win->y;
  917. }
  918. }
  919. void ttk_window_hide_header (TWindow *win)
  920. {
  921. if (win->show_header) {
  922. win->show_header = 0;
  923. ttk_dirty |= TTK_FILTHY;
  924. if (win->focus) {
  925. win->focus->h += ttk_screen->wy;
  926. win->focus->dirty++;
  927. }
  928. win->x = 0;
  929. win->y = 0;
  930. win->w = ttk_screen->w;
  931. win->h = ttk_screen->h;
  932. }
  933. }
  934. void ttk_free_window (TWindow *win)
  935. {
  936. ttk_hide_window (win);
  937. if (win->widgets) {
  938. TWidgetList *cur = win->widgets, *next;
  939. while (cur) {
  940. next = cur->next;
  941. cur->v->win = 0;
  942. ttk_free_widget (cur->v);
  943. free (cur);
  944. cur = next;
  945. }
  946. }
  947. ttk_free_surface (win->srf);
  948. if (win->titlefree) free ((void *)win->title);
  949. free (win);
  950. }
  951. void ttk_show_window (TWindow *win)
  952. {
  953. if (!win->onscreen) {
  954. TWindow *oldwindow = ttk_windows? ttk_windows->w : 0;
  955. TWindowStack *next = ttk_windows;
  956. TWidgetList *cur;
  957. ttk_windows = malloc (sizeof(struct TWindowStack));
  958. ttk_windows->w = win;
  959. ttk_windows->minimized = 0;
  960. ttk_windows->next = next;
  961. win->onscreen++;
  962. if (ttk_started && oldwindow &&
  963. oldwindow->w == win->w && oldwindow->h == win->h &&
  964. oldwindow->x == ttk_screen->wx && oldwindow->y == ttk_screen->wy) {
  965. int i;
  966. int jump = win->w / ttk_transit_frames;
  967. // Render the stuff in the new window
  968. ttk_fillrect (win->srf, 0, 0, win->w, win->h, ttk_makecol (CKEY));
  969. iterate_widgets (win->widgets, do_draw, 1);
  970. for (i = 0; i < ttk_transit_frames; i++) {
  971. ttk_ap_fillrect (ttk_screen->srf, ttk_ap_get ("window.bg"), ttk_screen->wx,
  972. ttk_screen->wy, ttk_screen->w, ttk_screen->h);
  973. ttk_blit_image_ex (oldwindow->srf, i * jump, 0, oldwindow->w - i*jump, oldwindow->h,
  974. ttk_screen->srf, ttk_screen->wx, ttk_screen->wy);
  975. ttk_blit_image_ex (win->srf, 0, 0, i * jump, oldwindow->h,
  976. ttk_screen->srf, oldwindow->w - i*jump + ttk_screen->wx,
  977. ttk_screen->wy);
  978. ttk_ap_hline (ttk_screen->srf, ttk_ap_get ("header.line"), 0, ttk_screen->w, ttk_screen->wy);
  979. ttk_gfx_update (ttk_screen->srf);
  980. #ifndef IPOD
  981. ttk_delay (10);
  982. #endif
  983. }
  984. ttk_ap_fillrect (ttk_screen->srf, ttk_ap_get ("window.bg"), ttk_screen->wx,
  985. ttk_screen->wy, ttk_screen->w, ttk_screen->h);
  986. ttk_blit_image (win->srf, ttk_screen->srf, ttk_screen->wx, ttk_screen->wy);
  987. ttk_ap_hline (ttk_screen->srf, ttk_ap_get ("header.line"), 0, ttk_screen->w, ttk_screen->wy);
  988. ttk_gfx_update (ttk_screen->srf);
  989. }
  990. } else {
  991. ttk_move_window (win, 0, TTK_MOVE_ABS);
  992. ttk_windows->minimized = 0;
  993. }
  994. ttk_dirty |= TTK_DIRTY_WINDOWAREA | TTK_DIRTY_HEADER;
  995. if (ttk_windows->w->input)
  996. ttk_dirty |= TTK_DIRTY_INPUT;
  997. }
  998. void ttk_set_popup (TWindow *win)
  999. {
  1000. int minx, miny, maxx, maxy;
  1001. TWidgetList *cur = win->widgets;
  1002. minx = miny = maxx = maxy = 0;
  1003. while (cur) {
  1004. if (cur->v->x < minx) minx = cur->v->x;
  1005. if (cur->v->y < miny) miny = cur->v->y;
  1006. if (cur->v->x + cur->v->w > maxx) maxx = cur->v->x + cur->v->w;
  1007. if (cur->v->y + cur->v->h > maxy) maxy = cur->v->y + cur->v->h;
  1008. cur = cur->next;
  1009. }
  1010. // Move widgets to upper-left corner of new window
  1011. cur = win->widgets;
  1012. while (cur) {
  1013. cur->v->x -= minx;
  1014. cur->v->y -= miny;
  1015. cur = cur->next;
  1016. }
  1017. // Center the window
  1018. win->x = ((ttk_screen->w - ttk_screen->wx) - (maxx - minx)) / 2 + ttk_screen->wx;
  1019. win->y = ((ttk_screen->h - ttk_screen->wy) - (maxy - miny)) / 2 + ttk_screen->wy;
  1020. win->w = maxx - minx;
  1021. win->h = maxy - miny;
  1022. }
  1023. void ttk_popup_window (TWindow *win)
  1024. {
  1025. ttk_set_popup (win);
  1026. ttk_show_window (win);
  1027. }
  1028. int ttk_hide_window (TWindow *win)
  1029. {
  1030. TWindowStack *current = ttk_windows, *last = 0;
  1031. int ret = 0;
  1032. if (!current) return 0;
  1033. while (current) {
  1034. if (current->w == win) {
  1035. if (last)
  1036. last->next = current->next;
  1037. else
  1038. ttk_windows = current->next;
  1039. ttk_dirty |= TTK_DIRTY_WINDOWAREA | TTK_DIRTY_HEADER;
  1040. free (current);
  1041. current = last;
  1042. win->onscreen = 0;
  1043. ret++;
  1044. }
  1045. last = current;
  1046. if (current) current = current->next;
  1047. }
  1048. if (ret && ttk_windows) {
  1049. TWindow *newwindow = ttk_windows->w;
  1050. if (newwindow->w == win->w && newwindow->h == win->h &&
  1051. newwindow->x == ttk_screen->wx && newwindow->y == ttk_screen->wy) {
  1052. int i;
  1053. int jump = win->w / ttk_transit_frames;
  1054. // Render stuff in the new window
  1055. ttk_fillrect (win->srf, 0, 0, win->w, win->h, ttk_makecol (CKEY));
  1056. iterate_widgets (win->widgets, do_draw, 1);
  1057. for (i = ttk_transit_frames - 1; i >= 0; i--) {
  1058. ttk_ap_fillrect (ttk_screen->srf, ttk_ap_get ("window.bg"), ttk_screen->wx,
  1059. ttk_screen->wy, ttk_screen->w, ttk_screen->h);
  1060. ttk_blit_image_ex (newwindow->srf, i * jump, 0, win->w - i*jump, win->h,
  1061. ttk_screen->srf, ttk_screen->wx, ttk_screen->wy);
  1062. ttk_blit_image_ex (win->srf, 0, 0, i * jump, win->h,
  1063. ttk_screen->srf, win->w - i*jump + ttk_screen->wx,
  1064. ttk_screen->wy);
  1065. ttk_ap_hline (ttk_screen->srf, ttk_ap_get ("header.line"), 0, ttk_screen->w, ttk_screen->wy);
  1066. ttk_gfx_update (ttk_screen->srf);
  1067. #ifndef IPOD
  1068. ttk_delay (10);
  1069. #endif
  1070. }
  1071. ttk_ap_fillrect (ttk_screen->srf, ttk_ap_get ("window.bg"), ttk_screen->wx,
  1072. ttk_screen->wy, ttk_screen->w, ttk_screen->h);
  1073. ttk_blit_image (newwindow->srf, ttk_screen->srf, ttk_screen->wx, ttk_screen->wy);
  1074. ttk_ap_hline (ttk_screen->srf, ttk_ap_get ("header.line"), 0, ttk_screen->w, ttk_screen->wy);
  1075. ttk_gfx_update (ttk_screen->srf);
  1076. }
  1077. }
  1078. return ret;
  1079. }
  1080. void ttk_move_window (TWindow *win, int offset, int whence)
  1081. {
  1082. TWindowStack *cur = ttk_windows, *last = 0;
  1083. int oidx, idx = -1, nitems = 0, i = 0;
  1084. int minimized = 0;
  1085. if (!cur) return;
  1086. while (cur) {
  1087. if ((cur->w == win) && (idx == -1)) {
  1088. idx = nitems;
  1089. if (last)
  1090. last->next = cur->next;
  1091. else
  1092. ttk_windows = cur->next;
  1093. minimized = cur->minimized;
  1094. last = cur;
  1095. cur = cur->next;
  1096. free (last);
  1097. }
  1098. nitems++;
  1099. last = cur;
  1100. if (cur) cur = cur->next;
  1101. }
  1102. if (idx == -1) return;
  1103. oidx = idx;
  1104. switch (whence) {
  1105. case TTK_MOVE_ABS:
  1106. idx = offset;
  1107. break;
  1108. case TTK_MOVE_REL:
  1109. idx -= offset;
  1110. break;
  1111. case TTK_MOVE_END:
  1112. idx = 32767; // obscenely high number
  1113. break;
  1114. }
  1115. if (idx < 0) idx = 0;
  1116. cur = ttk_windows;
  1117. last = 0;
  1118. while (cur) {
  1119. if (idx == i) {
  1120. TWindowStack *s = malloc (sizeof(TWindowStack));
  1121. if (last)
  1122. last->next = s;
  1123. else
  1124. ttk_windows = s;
  1125. s->next = cur;
  1126. s->w = win;
  1127. s->minimized = minimized;
  1128. break;
  1129. }
  1130. if (oidx == i)
  1131. i++; // double-increment, since something used to
  1132. // be here and [idx] is still based on that. :TRICKY:
  1133. last = cur;
  1134. cur = cur->next;
  1135. i++;
  1136. }
  1137. if (!cur && ttk_windows) { // index was past end, put it on end
  1138. cur = ttk_windows;
  1139. while (cur->next) cur = cur->next;
  1140. cur->next = malloc (sizeof(TWindowStack));
  1141. cur->next->w = win;
  1142. cur->next->minimized = minimized;
  1143. cur->next->next = 0;
  1144. }
  1145. if (ttk_windows)
  1146. ttk_windows->minimized = 0;
  1147. ttk_dirty |= TTK_FILTHY;
  1148. }
  1149. void ttk_window_title (TWindow *win, const char *str)
  1150. {
  1151. if (win->titlefree)
  1152. free ((void *)win->title);
  1153. win->title = malloc (strlen (str) + 1);
  1154. strcpy ((char *)win->title, str);
  1155. win->titlefree = 1;
  1156. if (ttk_windows && ttk_windows->w == win) {
  1157. ttk_dirty |= TTK_DIRTY_HEADER;
  1158. }
  1159. }
  1160. void ttk_add_header_widget (TWidget *wid)
  1161. {
  1162. TWidgetList *current;
  1163. wid->win = 0;
  1164. if (!ttk_header_widgets) {
  1165. ttk_header_widgets = current = malloc (sizeof(TWidgetList));
  1166. } else {
  1167. current = ttk_header_widgets;
  1168. while (current->next) current = current->next;
  1169. current->next = malloc (sizeof(TWidgetList));
  1170. current = current->next;
  1171. }
  1172. current->v = wid;
  1173. current->next = 0;
  1174. }
  1175. void ttk_remove_header_widget (TWidget *wid)
  1176. {
  1177. TWidgetList *current = ttk_header_widgets, *last = 0;
  1178. if (!current) return;
  1179. while (current) {
  1180. if (current->v == wid) {
  1181. if (last) last->next = current->next;
  1182. else ttk_header_widgets = current->next;
  1183. free (current);
  1184. if (last) current = last->next;
  1185. else current = ttk_header_widgets;
  1186. } else {
  1187. if (current) last = current, current = current->next;
  1188. }
  1189. }
  1190. }
  1191. TWidget *ttk_new_widget (int x, int y)
  1192. {
  1193. TWidget *ret = malloc (sizeof(TWidget));
  1194. int i;
  1195. if (!ret) return 0;
  1196. ret->x = x; ret->y = y; ret->w = 0; ret->h = 0;
  1197. ret->focusable = 0; ret->keyrepeat = 0; ret->rawkeys = 0;
  1198. ret->framelast = 0; ret->framedelay = 0;
  1199. ret->timerlast = 0; ret->timerdelay = 0;
  1200. ret->holdtime = 1000; ret->dirty = 1;
  1201. ret->draw = ttk_widget_nodrawing;
  1202. ret->button = ttk_widget_noaction_2;
  1203. ret->down = ret->held = ret->scroll = ret->stap = ttk_widget_noaction_1;
  1204. ret->input = ttk_widget_noaction_1;
  1205. ret->frame = ret->timer = ttk_widget_noaction_i0;
  1206. ret->destroy = ttk_widget_noaction_0;
  1207. ret->data = ret->data2 = 0;
  1208. return ret;
  1209. }
  1210. void ttk_free_widget (TWidget *wid)
  1211. {
  1212. if (!wid) return;
  1213. wid->destroy (wid);
  1214. if (wid->win)
  1215. ttk_remove_widget (wid->win, wid);
  1216. free (wid);
  1217. }
  1218. TWindow *ttk_add_widget (TWindow *win, TWidget *wid)
  1219. {
  1220. TWidgetList *current;
  1221. if (!wid || !win) return win;
  1222. if (!win->widgets) {
  1223. win->widgets = current = malloc (sizeof(TWidgetList));
  1224. } else {
  1225. current = win->widgets;
  1226. while (current->next) current = current->next;
  1227. current->next = malloc (sizeof(TWidgetList));
  1228. current = current->next;
  1229. }
  1230. if (wid->focusable)
  1231. win->focus = wid;
  1232. wid->dirty++;
  1233. wid->win = win;
  1234. current->v = wid;
  1235. current->next = 0;
  1236. return win;
  1237. }
  1238. int ttk_remove_widget (TWindow *win, TWidget *wid)
  1239. {
  1240. TWidgetList *current, *last = 0;
  1241. int count = 0;
  1242. if (!win || !wid || !win->widgets) return 0;
  1243. if (wid == win->focus) win->focus = 0;
  1244. current = win->widgets;
  1245. while (current) {
  1246. if (current->v == wid) {
  1247. if (last) last->next = current->next;
  1248. else win->widgets = current->next;
  1249. free (current);
  1250. if (last) current = last->next;
  1251. else current = win->widgets;
  1252. count++;
  1253. } else {
  1254. if (current && current->v->focusable) win->focus = current->v;
  1255. if (current) last = current, current = current->next;
  1256. }
  1257. }
  1258. win->dirty++;
  1259. wid->win = 0;
  1260. return count;
  1261. }
  1262. void ttk_widget_set_fps (TWidget *wid, int fps)
  1263. {
  1264. if (fps) {
  1265. wid->framelast = ttk_getticks();
  1266. wid->framedelay = 1000/fps;
  1267. } else {
  1268. wid->framelast = wid->framedelay = 0;
  1269. }
  1270. }
  1271. void ttk_widget_set_inv_fps (TWidget *wid, int fps_m1)
  1272. {
  1273. wid->framelast = ttk_getticks();
  1274. wid->framedelay = 1000*fps_m1; // works for 0 to unset
  1275. }
  1276. void ttk_widget_set_timer (TWidget *wid, int ms)
  1277. {
  1278. wid->timerlast = ttk_getticks();
  1279. wid->timerdelay = ms; // works for 0 to unset
  1280. }
  1281. void ttk_set_global_event_handler (int (*fn)(int ev, int earg, int time))
  1282. {
  1283. ttk_global_evhandler = fn;
  1284. }
  1285. void ttk_set_global_unused_handler (int (*fn)(int ev, int earg, int time))
  1286. {
  1287. ttk_global_unusedhandler = fn;
  1288. }
  1289. ttk_color ttk_mapcol (ttk_color col, ttk_surface src, ttk_surface dst)
  1290. {
  1291. int r, g, b;
  1292. if (!src) src = ttk_screen->srf;
  1293. if (!dst) dst = ttk_screen->srf;
  1294. if (src == dst) return col;
  1295. ttk_unmakecol_ex (col, &r, &g, &b, src);
  1296. return ttk_makecol_ex (r, g, b, dst);
  1297. }
  1298. #ifdef IPOD
  1299. /*** The following LCD code is taken from Linux kernel uclinux-2.4.24-uc0-ipod2,
  1300. file arch/armnommu/mach-ipod/fb.c. A few modifications have been made. ***/
  1301. #define LCD_DATA 0x10
  1302. #define LCD_CMD 0x08
  1303. #define IPOD_OLD_LCD_BASE 0xc0001000
  1304. #define IPOD_OLD_LCD_RTC 0xcf001110
  1305. #define IPOD_NEW_LCD_BASE 0x70003000
  1306. #define IPOD_NEW_LCD_RTC 0x60005010
  1307. static unsigned long lcd_base = 0, lcd_rtc = 0, lcd_width = 0, lcd_height = 0;
  1308. /* get current usec counter */
  1309. static int M_timer_get_current(void)
  1310. {
  1311. return inl(lcd_rtc);
  1312. }
  1313. /* check if number of useconds has past */
  1314. static int M_timer_check(int clock_start, int usecs)
  1315. {
  1316. unsigned long clock;
  1317. clock = inl(lcd_rtc);
  1318. if ( (clock - clock_start) >= usecs ) {
  1319. return 1;
  1320. } else {
  1321. return 0;
  1322. }
  1323. }
  1324. /* wait for LCD with timeout */
  1325. static void M_lcd_wait_write(void)
  1326. {
  1327. if ( (inl(lcd_base) & 0x8000) != 0 ) {
  1328. int start = M_timer_get_current();
  1329. do {
  1330. if ( (inl(lcd_base) & (unsigned int)0x8000) == 0 )
  1331. break;
  1332. } while ( M_timer_check(start, 1000) == 0 );
  1333. }
  1334. }
  1335. /* send LCD data */
  1336. static void M_lcd_send_data(int data_lo, int data_hi)
  1337. {
  1338. M_lcd_wait_write();
  1339. outl(data_lo, lcd_base + LCD_DATA);
  1340. M_lcd_wait_write();
  1341. outl(data_hi, lcd_base + LCD_DATA);
  1342. }
  1343. /* send LCD command */
  1344. static void
  1345. M_lcd_prepare_cmd(int cmd)
  1346. {
  1347. M_lcd_wait_write();
  1348. outl(0x0, lcd_base + LCD_CMD);
  1349. M_lcd_wait_write();
  1350. outl(cmd, lcd_base + LCD_CMD);
  1351. }
  1352. /* send LCD command and data */
  1353. static void M_lcd_cmd_and_data(int cmd, int data_lo, int data_hi)
  1354. {
  1355. M_lcd_prepare_cmd(cmd);
  1356. M_lcd_send_data(data_lo, data_hi);
  1357. }
  1358. // Copied from uW
  1359. static void M_update_display(int sx, int sy, int mx, int my, unsigned char *data, int pitch)
  1360. {
  1361. int y;
  1362. unsigned short cursor_pos;
  1363. sx >>= 3;
  1364. mx >>= 3;
  1365. cursor_pos = sx + (sy << 5);
  1366. for ( y = sy; y <= my; y++ ) {
  1367. unsigned char *img_data;
  1368. int x;
  1369. /* move the cursor */
  1370. M_lcd_cmd_and_data(0x11, cursor_pos >> 8, cursor_pos & 0xff);
  1371. /* setup for printing */
  1372. M_lcd_prepare_cmd(0x12);
  1373. img_data = data + (sx << 1) + (y * (lcd_width/4));
  1374. /* loops up to 160 times */
  1375. for ( x = sx; x <= mx; x++ ) {
  1376. /* display eight pixels */
  1377. M_lcd_send_data(*(img_data + 1), *img_data);
  1378. img_data += 2;
  1379. }
  1380. /* update cursor pos counter */
  1381. cursor_pos += 0x20;
  1382. }
  1383. }
  1384. /* get current usec counter */
  1385. static int C_timer_get_current(void)
  1386. {
  1387. return inl(0x60005010);
  1388. }
  1389. /* check if number of useconds has past */
  1390. static int C_timer_check(int clock_start, int usecs)
  1391. {
  1392. unsigned long clock;
  1393. clock = inl(0x60005010);
  1394. if ( (clock - clock_start) >= usecs ) {
  1395. return 1;
  1396. } else {
  1397. return 0;
  1398. }
  1399. }
  1400. /* wait for LCD with timeout */
  1401. static void C_lcd_wait_write(void)
  1402. {
  1403. if ((inl(0x70008A0C) & 0x80000000) != 0) {
  1404. int start = C_timer_get_current();
  1405. do {
  1406. if ((inl(0x70008A0C) & 0x80000000) == 0)
  1407. break;
  1408. } while (C_timer_check(start, 1000) == 0);
  1409. }
  1410. }
  1411. static void C_lcd_cmd_data(int cmd, int data)
  1412. {
  1413. C_lcd_wait_write();
  1414. outl(cmd | 0x80000000, 0x70008A0C);
  1415. C_lcd_wait_write();
  1416. outl(data | 0x80000000, 0x70008A0C);
  1417. }
  1418. static void C_update_display(int sx, int sy, int mx, int my, unsigned char *data, int pitch)
  1419. {
  1420. int height = (my - sy) + 1;
  1421. int width = (mx - sx) + 1;
  1422. char *addr = (char *)data;
  1423. if (width & 1) width++;
  1424. /* start X and Y */
  1425. C_lcd_cmd_data(0x12, (sy & 0xff));
  1426. C_lcd_cmd_data(0x13, (((ttk_screen->w - 1) - sx) & 0xff));
  1427. /* max X and Y */
  1428. C_lcd_cmd_data(0x15, (((sy + height) - 1) & 0xff));
  1429. C_lcd_cmd_data(0x16, (((((ttk_screen->w - 1) - sx) - width) + 1) & 0xff));
  1430. addr += sx + sy * pitch;
  1431. while (height > 0) {
  1432. int h, x, y, pixels_to_write;
  1433. pixels_to_write = (width * height) * 2;
  1434. /* calculate how much we can do in one go */
  1435. h = height;
  1436. if (pixels_to_write > 64000) {
  1437. h = (64000/2) / width;
  1438. pixels_to_write = (width * h) * 2;
  1439. }
  1440. outl(0x10000080, 0x70008A20);
  1441. outl((pixels_to_write - 1) | 0xC0010000, 0x70008A24);
  1442. outl(0x34000000, 0x70008A20);
  1443. /* for each row */
  1444. for (x = 0; x < h; x++)
  1445. {
  1446. /* for each column */
  1447. for (y = 0; y < width; y += 2) {
  1448. unsigned two_pixels;
  1449. two_pixels = addr[0] | (addr[1] << 16);
  1450. addr += 2;
  1451. while ((inl(0x70008A20) & 0x1000000) == 0);
  1452. /* output 2 pixels */
  1453. outl(two_pixels, 0x70008B00);
  1454. }
  1455. addr += pitch - width;
  1456. }
  1457. while ((inl(0x70008A20) & 0x4000000) == 0);
  1458. outl(0x0, 0x70008A24);
  1459. height = height - h;
  1460. }
  1461. }
  1462. /** End copied code. **/
  1463. void ttk_update_lcd (int xstart, int ystart, int xend, int yend, unsigned char *data)
  1464. {
  1465. static int do_color = 0;
  1466. static int pitch = 0;
  1467. if (lcd_base < 0) {
  1468. int ver = ttk_get_podversion();
  1469. if (!ver) { // X11
  1470. fprintf (stderr, "No iPod. Can't ttk_update_lcd.");
  1471. ttk_quit();
  1472. exit (1);
  1473. }
  1474. if (ver & TTK_POD_SANSA)
  1475. return; // SDL handles LCD code
  1476. if (ver & (TTK_POD_1G|TTK_POD_2G|TTK_POD_3G)) {
  1477. lcd_base = IPOD_OLD_LCD_BASE;
  1478. lcd_rtc = IPOD_OLD_LCD_RTC;
  1479. } else {
  1480. lcd_base = IPOD_NEW_LCD_BASE;
  1481. lcd_rtc = IPOD_NEW_LCD_RTC;
  1482. }
  1483. lcd_width = ttk_screen->w;
  1484. lcd_height = ttk_screen->h;
  1485. if (ver & TTK_POD_PHOTO) do_color = 1;
  1486. pitch = ttk_screen->w;
  1487. }
  1488. if (do_color) C_update_display (xstart, ystart, xend, yend, data, pitch);
  1489. else M_update_display (xstart, ystart, xend, yend, data, pitch);
  1490. }
  1491. #else
  1492. void ttk_update_lcd (int xstart, int ystart, int xend, int yend, unsigned char *data)
  1493. {
  1494. fprintf (stderr, "update_lcd() skipped: not on iPod\n");
  1495. }
  1496. #endif
  1497. void ttk_start_cop (void (*fn)()) { exit (255); }
  1498. void ttk_stop_cop() {}
  1499. void ttk_sleep_cop() {}
  1500. void ttk_wake_cop() {}
  1501. /* don't hurt yourself; I know I did. */
  1502. ttk_timer ttk_create_timer (int ms, void (*fn)())
  1503. {
  1504. #define TIMER_ALLOCD (head->delay)
  1505. /* yes, static variables are not entirely clean, but timers will probably
  1506. * be running until program exit, if not call ttk_create_timer with 0,0 */
  1507. static ttk_timer head;
  1508. ttk_timer cur;
  1509. int num;
  1510. /* special case so that -head- can be free'd */
  1511. if (!ms && !fn) {
  1512. free(head);
  1513. head = 0;
  1514. return 0;
  1515. }
  1516. /* count the number of timers used */
  1517. for (cur = head; cur && cur->next; cur = cur->next);
  1518. num = (cur) ? cur - head : 0;
  1519. /* if ttk_timers moved, make sure we don't leave a empty timer spot */
  1520. if (head && ttk_timers && ttk_timers != head->next) {
  1521. head->next = ttk_timers;
  1522. }
  1523. if (!head || ++num > TIMER_ALLOCD) {
  1524. int a = head ? TIMER_ALLOCD + 64 : 63;
  1525. /* if this realloc relocates the memory, all timers are screwed. */
  1526. cur = realloc(head, (a + 1) * sizeof(struct _ttk_timer));
  1527. if (head && cur != head) {
  1528. fprintf(stderr, "realloc relocated timers. All timers are now "
  1529. "broken. Why did you have over %d timers anyway? "
  1530. "Please report.", a - 64);
  1531. }
  1532. if (!head) cur->next = 0;
  1533. head = cur;
  1534. TIMER_ALLOCD = a;
  1535. }
  1536. cur = head;
  1537. while (cur->next == cur + 1)
  1538. cur = cur->next;
  1539. (cur + 1)->next = cur->next;
  1540. cur->next = cur + 1;
  1541. cur = cur->next;
  1542. /* reset ttk_timers so we aren't missing a timer in spot 1 */
  1543. ttk_timers = head->next;
  1544. cur->started = ttk_getticks();
  1545. cur->delay = ms;
  1546. cur->fn = fn;
  1547. return cur;
  1548. #undef TIMER_ALLOCD
  1549. }
  1550. void ttk_destroy_timer (ttk_timer tim)
  1551. {
  1552. ttk_timer cur = ttk_timers, last = 0;
  1553. while (cur && (cur != tim)) {
  1554. last = cur;
  1555. cur = cur->next;
  1556. }
  1557. if (cur != tim) {
  1558. fprintf (stderr, "Warning: didn't delete nonexistent timer %p\n", tim);
  1559. return;
  1560. }
  1561. if (last) {
  1562. last->next = cur->next;
  1563. } else {
  1564. ttk_timers = cur->next;
  1565. }
  1566. }
  1567. void ttk_set_transition_frames (int frames)
  1568. {
  1569. if (frames <= 0) frames = 1;
  1570. ttk_transit_frames = frames;
  1571. }
  1572. static void do_nothing() {}
  1573. void ttk_set_clicker (void (*fn)())
  1574. {
  1575. if (!fn) fn = do_nothing;
  1576. ttk_clicker = fn;
  1577. }
  1578. void ttk_set_scroll_multiplier (int num, int denom)
  1579. {
  1580. ttk_scroll_num = num;
  1581. ttk_scroll_denom = denom;
  1582. }
  1583. int ttk_input_start_for (TWindow *win, TWidget *inmethod)
  1584. {
  1585. inmethod->x = ttk_screen->w - inmethod->w - 1;
  1586. inmethod->y = ttk_screen->h - inmethod->h - 1;
  1587. inmethod->win = win;
  1588. win->input = inmethod;
  1589. return inmethod->h;
  1590. }
  1591. int ttk_input_start (TWidget *inmethod)
  1592. {
  1593. if (!ttk_windows || !ttk_windows->w) return -1;
  1594. ttk_input_start_for (ttk_windows->w, inmethod);
  1595. ttk_dirty |= TTK_DIRTY_WINDOWAREA | TTK_DIRTY_INPUT;
  1596. return inmethod->h;
  1597. }
  1598. void ttk_input_move (int x, int y)
  1599. {
  1600. if (!ttk_windows || !ttk_windows->w || !ttk_

Large files files are truncated, but you can click here to view the full file