Clock.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /**---------------------------------------------------------------------
  24. ***
  25. *** file: Clock.c
  26. ***
  27. *** project: MotifPlus Widgets
  28. ***
  29. *** description: Source code for DtClock class.
  30. *** Portions adapted from the Xaw Clock widget.
  31. ***
  32. ***
  33. *** (c) Copyright 1990 by Hewlett-Packard Company.
  34. ***
  35. ***
  36. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
  37. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  38. All Rights Reserved
  39. Permission to use, copy, modify, and distribute this software and its
  40. documentation for any purpose and without fee is hereby granted,
  41. provided that the above copyright notice appear in all copies and that
  42. both that copyright notice and this permission notice appear in
  43. supporting documentation, and that the names of Digital or MIT not be
  44. used in advertising or publicity pertaining to distribution of the
  45. software without specific, written prior permission.
  46. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  47. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  48. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  49. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  50. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  51. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  52. SOFTWARE.
  53. ***
  54. ***
  55. ***-------------------------------------------------------------------*/
  56. /*-------------------------------------------------------------
  57. ** Include Files
  58. */
  59. #include <stdio.h>
  60. #include <sys/stat.h>
  61. #include <time.h>
  62. #include <Xm/GadgetP.h>
  63. #include <Xm/ManagerP.h>
  64. #include "ClockP.h"
  65. #include <Dt/Control.h>
  66. /*-------------------------------------------------------------
  67. ** Public Interface
  68. **-------------------------------------------------------------
  69. */
  70. WidgetClass dtClockGadgetClass;
  71. /*-------------------------------------------------------------
  72. */
  73. #define SIZE_DEFAULT 32
  74. #define DELAY_DEFAULT 250
  75. #define VERTICES_IN_HANDS 6 /* to draw triangle */
  76. #define PI 3.14159265358979
  77. #define TWOPI (2. * PI)
  78. #define SMALL_TICK_FRACT 100
  79. #define SMALL_MINUTE_HAND_FRACT 95
  80. #define SMALL_HOUR_HAND_FRACT 68
  81. #define SMALL_HAND_WIDTH_FRACT 12
  82. #define TICK_FRACT 90
  83. #define MINUTE_HAND_FRACT 70
  84. #define HOUR_HAND_FRACT 40
  85. #define HAND_WIDTH_FRACT 7
  86. #define max(a,b) ((a) > (b) ? (a) : (b))
  87. #define min(a,b) ((a) < (b) ? (a) : (b))
  88. #define abs(a) ((a) < 0 ? - (a) : (a))
  89. #define G_Width(r) (r -> rectangle.width)
  90. #define G_Height(r) (r -> rectangle.height)
  91. #define M_BackgroundGC(m) (m -> manager.background_GC)
  92. #define G_X(r) (r -> rectangle.x)
  93. #define G_Y(r) (r -> rectangle.y)
  94. /* Is this still needed, or does <time.h> always declare time()? */
  95. extern time_t time ( time_t * );
  96. /******** Public Function Declarations ********/
  97. extern Widget DtCreateClock(
  98. Widget parent,
  99. String name,
  100. ArgList arglist,
  101. Cardinal argcount) ;
  102. /******** End Public Function Declarations ********/
  103. /******** Static Function Declarations ********/
  104. static void ClockTick(
  105. XtPointer client_data,
  106. XtIntervalId *id) ;
  107. static void DrawLine(
  108. DtClockGadget w,
  109. Dimension blank_length,
  110. Dimension length,
  111. double fraction_of_a_circle) ;
  112. static void DrawHand(
  113. DtClockGadget w,
  114. Dimension length,
  115. Dimension width,
  116. double fraction_of_a_circle) ;
  117. static void SetSegment(
  118. DtClockGadget w,
  119. int x1,
  120. int y1,
  121. int x2,
  122. int y2) ;
  123. static int round(
  124. double x) ;
  125. static void DrawClockFace(
  126. DtClockGadget g) ;
  127. static void Initialize(
  128. Widget request_w,
  129. Widget new_w) ;
  130. static void Destroy(
  131. Widget w) ;
  132. static void Resize(
  133. Widget widget) ;
  134. static void Draw(
  135. DtClockGadget g,
  136. Drawable drawable,
  137. Position x,
  138. Position y,
  139. Dimension w,
  140. Dimension h,
  141. Dimension h_t,
  142. Dimension s_t,
  143. unsigned char s_type,
  144. unsigned char fill_mode) ;
  145. static void UpdateGCs(
  146. DtClockGadget g) ;
  147. static void EraseHands ( DtClockGadget w, struct tm * tm );
  148. /******** End Static Function Declarations ********/
  149. /*-------------------------------------------------------------
  150. ** Resource List
  151. */
  152. #define R_Offset(field) \
  153. XtOffset (DtClockGadget, clock.field)
  154. static XtResource resources[] =
  155. {
  156. {
  157. XmNclockInterval,
  158. XmCInterval, XmRInt, sizeof (int),
  159. R_Offset (clock_interval), XmRImmediate, (XtPointer) 60
  160. },
  161. {
  162. XmNchime,
  163. XmCBoolean, XmRBoolean, sizeof (Boolean),
  164. R_Offset (chime), XmRImmediate, (XtPointer) FALSE
  165. },
  166. {
  167. XmNleftInset,
  168. XmCSpacing, XmRHorizontalDimension, sizeof (Dimension),
  169. R_Offset (left_inset), XmRImmediate, (caddr_t) 2
  170. },
  171. {
  172. XmNrightInset,
  173. XmCSpacing, XmRHorizontalDimension, sizeof (Dimension),
  174. R_Offset (right_inset), XmRImmediate, (caddr_t) 2
  175. },
  176. {
  177. XmNtopInset,
  178. XmCSpacing, XmRVerticalDimension, sizeof (Dimension),
  179. R_Offset (top_inset), XmRImmediate, (caddr_t) 2
  180. },
  181. {
  182. XmNbottomInset,
  183. XmCSpacing, XmRVerticalDimension, sizeof (Dimension),
  184. R_Offset (bottom_inset), XmRImmediate, (caddr_t) 2
  185. }
  186. };
  187. #undef R_Offset
  188. /*-------------------------------------------------------------
  189. ** Class Record
  190. */
  191. DtClockClassRec dtClockClassRec =
  192. {
  193. /* Core Part
  194. */
  195. {
  196. (WidgetClass) &dtControlClassRec, /* superclass */
  197. "Clock", /* class_name */
  198. sizeof (DtClockRec), /* widget_size */
  199. NULL, /* class_initialize */
  200. NULL, /* class_part_initialize*/
  201. False, /* class_inited */
  202. (XtInitProc) Initialize, /* initialize */
  203. NULL, /* initialize_hook */
  204. NULL, /* realize */
  205. NULL, /* actions */
  206. 0, /* num_actions */
  207. resources, /* resources */
  208. XtNumber (resources), /* num_resources */
  209. NULLQUARK, /* xrm_class */
  210. True, /* compress_motion */
  211. True, /* compress_exposure */
  212. True, /* compress_enterleave */
  213. False, /* visible_interest */
  214. Destroy, /* destroy */
  215. Resize, /* resize */
  216. XtInheritExpose, /* expose */
  217. NULL, /* set_values */
  218. NULL, /* set_values_hook */
  219. XtInheritSetValuesAlmost, /* set_values_almost */
  220. NULL, /* get_values_hook */
  221. NULL, /* accept_focus */
  222. XtVersion, /* version */
  223. NULL, /* callback private */
  224. NULL, /* tm_table */
  225. NULL, /* query_geometry */
  226. NULL, /* display_accelerator */
  227. NULL, /* extension */
  228. },
  229. /* XmGadget Part
  230. */
  231. {
  232. XmInheritBorderHighlight, /* border_highlight */
  233. XmInheritBorderUnhighlight, /* border_unhighlight */
  234. (XtActionProc) XmInheritArmAndActivate, /* arm_and_activate */
  235. (XmWidgetDispatchProc) XmInheritInputDispatch, /* input_dispatch */
  236. XmInheritVisualChange, /* visual_change */
  237. NULL, /* get_resources */
  238. 0, /* num_get_resources */
  239. XmInheritCachePart, /* class_cache_part */
  240. NULL, /* extension */
  241. },
  242. /* DtIcon Part
  243. */
  244. {
  245. DtInheritGetSize, /* get_size */
  246. DtInheritGetPositions, /* get_positions */
  247. (DrawProc) Draw, /* draw */
  248. DtInheritCallCallback, /* call_callback */
  249. (UpdateGCsProc) UpdateGCs, /* update_gcs */
  250. False, /* optimize_redraw */
  251. NULL, /* class_cache_part */
  252. NULL, /* extension */
  253. },
  254. /* DtClock Part
  255. */
  256. {
  257. NULL, /* class_cache_part */
  258. NULL, /* extension */
  259. },
  260. /* DtControl Part
  261. */
  262. {
  263. NULL, /* class_cache_part */
  264. NULL, /* extension */
  265. }
  266. };
  267. WidgetClass dtClockGadgetClass = (WidgetClass) &dtClockClassRec;
  268. /*-------------------------------------------------------------
  269. ** Private Functions
  270. **-------------------------------------------------------------
  271. */
  272. /*-------------------------------------------------------------
  273. ** ClockTick
  274. ** Clock timeout.
  275. */
  276. static void
  277. ClockTick(
  278. XtPointer client_data,
  279. XtIntervalId *id )
  280. {
  281. DtClockGadget w = (DtClockGadget)client_data;
  282. struct tm * localtime ();
  283. struct tm tm;
  284. time_t time_value;
  285. char * time_ptr;
  286. Display * dpy = XtDisplay (w);
  287. Window win = XtWindow (w);
  288. if (id || !w->clock.interval_id)
  289. w->clock.interval_id =
  290. XtAppAddTimeOut (
  291. XtWidgetToApplicationContext ((Widget) w),
  292. G_ClockInterval (w)*1000, ClockTick,
  293. (XtPointer)w );
  294. (void) time (&time_value);
  295. tm = *localtime (&time_value);
  296. if (! XtIsManaged ((Widget)w))
  297. {
  298. w->clock.otm = tm;
  299. return;
  300. }
  301. /* Beep on the half hour; double-beep on the hour.
  302. */
  303. if (w->clock.chime == TRUE)
  304. {
  305. if (w->clock.beeped && (tm.tm_min != 30) &&
  306. (tm.tm_min != 0))
  307. w->clock.beeped = FALSE;
  308. if (((tm.tm_min == 30) || (tm.tm_min == 0))
  309. && (!w->clock.beeped))
  310. {
  311. w->clock.beeped = TRUE;
  312. XBell (dpy, 50);
  313. if (tm.tm_min == 0)
  314. XBell (dpy, 50);
  315. }
  316. }
  317. /* remove this when clipping added to gcs */
  318. if ((G_Width (w) <
  319. (Dimension)((G_ClockWidth (w) / 2) + w->clock.centerX)) ||
  320. (G_Height (w) <
  321. (Dimension)((G_ClockHeight (w) / 2) + w->clock.centerY)))
  322. return;
  323. /* The second (or minute) hand is sec (or min) sixtieths around the
  324. * clock face. The hour hand is (hour + min/60) twelfths of the way
  325. * around the clock-face.
  326. */
  327. if (tm.tm_hour > 12)
  328. tm.tm_hour -= 12;
  329. EraseHands (w, &tm);
  330. w->clock.segbuffptr = w->clock.segbuff;
  331. w->clock.numseg = 0;
  332. /* Calculate the hour hand, fill it in with its color.
  333. */
  334. DrawHand (w, w->clock.minute_hand_length, w->clock.hand_width,
  335. ((double) tm.tm_min)/60.0);
  336. XDrawLines (dpy, win, G_ClockHandGC (w), w->clock.segbuff,
  337. VERTICES_IN_HANDS, CoordModeOrigin);
  338. XFillPolygon (dpy, win, G_ClockHandGC (w), w->clock.segbuff,
  339. VERTICES_IN_HANDS, Convex, CoordModeOrigin);
  340. w->clock.hour = w->clock.segbuffptr;
  341. DrawHand (w, w->clock.hour_hand_length, w->clock.hand_width,
  342. ((((double)tm.tm_hour) +
  343. (((double)tm.tm_min)/60.0)) / 12.0));
  344. XFillPolygon (dpy, win, G_ClockHandGC (w), w->clock.hour,
  345. VERTICES_IN_HANDS, Convex, CoordModeOrigin);
  346. XDrawLines (dpy, win, G_ClockHandGC (w), w->clock.hour,
  347. VERTICES_IN_HANDS, CoordModeOrigin);
  348. w->clock.sec = w->clock.segbuffptr;
  349. w->clock.otm = tm;
  350. }
  351. /*-------------------------------------------------------------
  352. ** EraseHands
  353. ** Erase clock hands.
  354. */
  355. static void
  356. EraseHands (
  357. DtClockGadget w,
  358. struct tm * tm )
  359. {
  360. XmManagerWidget mgr = (XmManagerWidget) XtParent (w);
  361. Display * dpy = XtDisplay (w);
  362. Window win = XtWindow (w);
  363. unsigned char behavior = G_Behavior (w);
  364. GC gc;
  365. if (! XtIsManaged ((Widget)w) || w->clock.numseg <= 0)
  366. return;
  367. gc = G_ClockBackgroundGC (w);
  368. /* Erase old hands.
  369. */
  370. if (!tm || tm->tm_min != w->clock.otm.tm_min ||
  371. tm->tm_hour != w->clock.otm.tm_hour)
  372. {
  373. XDrawLines (dpy, win, gc, w->clock.segbuff,
  374. VERTICES_IN_HANDS, CoordModeOrigin);
  375. XDrawLines (dpy, win, gc, w->clock.hour,
  376. VERTICES_IN_HANDS, CoordModeOrigin);
  377. XFillPolygon (dpy, win, gc, w->clock.segbuff,
  378. VERTICES_IN_HANDS, Convex, CoordModeOrigin);
  379. XFillPolygon (dpy, win, gc, w->clock.hour,
  380. VERTICES_IN_HANDS, Convex, CoordModeOrigin);
  381. }
  382. }
  383. /*-------------------------------------------------------------
  384. ** DrawLine
  385. ** Draw a line.
  386. * blank_length is the distance from the center which the line begins.
  387. * length is the maximum length of the hand.
  388. * Fraction_of_a_circle is a fraction between 0 and 1 (inclusive) indicating
  389. * how far around the circle (clockwise) from high noon.
  390. *
  391. * The blank_length feature is because I wanted to draw tick-marks around the
  392. * circle (for seconds). The obvious means of drawing lines from the center
  393. * to the perimeter, then erasing all but the outside most pixels doesn't
  394. * work because of round-off error (sigh).
  395. */
  396. static void
  397. DrawLine (
  398. DtClockGadget w,
  399. Dimension blank_length,
  400. Dimension length,
  401. double fraction_of_a_circle )
  402. {
  403. double dblank_length = (double)blank_length, dlength = (double)length;
  404. double angle, cosangle, sinangle;
  405. double cos ();
  406. double sin ();
  407. int cx = w->clock.centerX, cy = w->clock.centerY, x1, y1, x2, y2;
  408. /*
  409. * A full circle is 2 PI radians.
  410. * Angles are measured from 12 o'clock, clockwise increasing.
  411. * Since in X, +x is to the right and +y is downward:
  412. *
  413. * x = x0 + r * sin (theta)
  414. * y = y0 - r * cos (theta)
  415. *
  416. */
  417. angle = TWOPI * fraction_of_a_circle;
  418. cosangle = cos (angle);
  419. sinangle = sin (angle);
  420. /* break this out so that stupid compilers can cope */
  421. x1 = cx + (int) (dblank_length * sinangle);
  422. y1 = cy - (int) (dblank_length * cosangle);
  423. x2 = cx + (int) (dlength * sinangle);
  424. y2 = cy - (int) (dlength * cosangle);
  425. SetSegment (w, x1, y1, x2, y2);
  426. }
  427. /*-------------------------------------------------------------
  428. ** DrawHand
  429. ** Draw a hand.
  430. *
  431. * length is the maximum length of the hand.
  432. * width is the half-width of the hand.
  433. * Fraction_of_a_circle is a fraction between 0 and 1 (inclusive) indicating
  434. * how far around the circle (clockwise) from high noon.
  435. *
  436. */
  437. static void
  438. DrawHand(
  439. DtClockGadget w,
  440. Dimension length,
  441. Dimension width,
  442. double fraction_of_a_circle )
  443. {
  444. double angle, cosangle, sinangle;
  445. double ws, wc;
  446. Position x, y, x1, y1, x2, y2;
  447. double cos ();
  448. double sin ();
  449. /* A full circle is 2 PI radians.
  450. * Angles are measured from 12 o'clock, clockwise increasing.
  451. * Since in X, +x is to the right and +y is downward:
  452. *
  453. * x = x0 + r * sin (theta)
  454. * y = y0 - r * cos (theta)
  455. */
  456. angle = TWOPI * fraction_of_a_circle;
  457. cosangle = cos (angle);
  458. sinangle = sin (angle);
  459. /* Order of points when drawing the hand.
  460. * 1,4
  461. * / \
  462. * / \
  463. * / \
  464. * 2 ------- 3
  465. */
  466. wc = width * cosangle;
  467. ws = width * sinangle;
  468. SetSegment (w,
  469. x = w->clock.centerX + round (length * sinangle),
  470. y = w->clock.centerY - round (length * cosangle),
  471. x1 = w->clock.centerX - round (ws + wc),
  472. y1 = w->clock.centerY + round (wc - ws)); /* 1 ---- 2 */
  473. SetSegment (w, x1, y1,
  474. x2 = w->clock.centerX - round (ws - wc),
  475. y2 = w->clock.centerY + round (wc + ws)); /* 2 ----- 3 */
  476. SetSegment (w, x2, y2, x, y); /* 3 ----- 1 (4) */
  477. }
  478. /*-------------------------------------------------------------
  479. ** SetSegment
  480. ** Set segment values.
  481. */
  482. static void
  483. SetSegment(
  484. DtClockGadget w,
  485. int x1,
  486. int y1,
  487. int x2,
  488. int y2 )
  489. {
  490. w->clock.segbuffptr->x = x1 + G_X (w);
  491. w->clock.segbuffptr++->y = y1 + G_Y (w);
  492. w->clock.segbuffptr->x = x2 + G_X (w);
  493. w->clock.segbuffptr++->y = y2 + G_Y (w);
  494. w->clock.numseg += 2;
  495. }
  496. /*-------------------------------------------------------------
  497. ** round
  498. ** round integer.
  499. */
  500. static int
  501. round(
  502. double x )
  503. {
  504. return (x >= 0.0 ? (int) (x + .5) : (int) (x - .5));
  505. }
  506. /*-------------------------------------------------------------
  507. ** DrawClockFace
  508. *
  509. * Draw the clock face (every fifth tick-mark is longer
  510. * than the others).
  511. */
  512. static void
  513. DrawClockFace(
  514. DtClockGadget g )
  515. {
  516. Boolean draw_minute_ticks =
  517. ((G_ClockWidth (g) > (Dimension) (2 * SIZE_DEFAULT)) &&
  518. (G_ClockHeight (g) > (Dimension) (2 * SIZE_DEFAULT)));
  519. int i;
  520. int delta =
  521. (int)(g->clock.radius - g->clock.tick_spacing) / 3;
  522. if (! XtIsManaged ((Widget)g))
  523. return;
  524. g->clock.segbuffptr = g->clock.segbuff;
  525. g->clock.numseg = 0;
  526. /* Set segments.
  527. */
  528. for (i = 0; i < 60; i++)
  529. {
  530. if (draw_minute_ticks)
  531. {
  532. if ((i % 5) == 0)
  533. DrawLine (g, g->clock.tick_spacing,
  534. g->clock.radius, ((double) i)/60.);
  535. else
  536. DrawLine (g, g->clock.radius - delta,
  537. g->clock.radius, ((double) i)/60.);
  538. }
  539. else
  540. if ((i % 15) == 0)
  541. DrawLine (g, g->clock.radius - 1,
  542. g->clock.radius, ((double) i)/60.);
  543. }
  544. /* Draw clock face.
  545. */
  546. XDrawSegments (XtDisplay (g), XtWindow (g), G_ClockHandGC (g),
  547. (XSegment *) & (g->clock.segbuff[0]),
  548. g->clock.numseg/2);
  549. g->clock.segbuffptr = g->clock.segbuff;
  550. g->clock.numseg = 0;
  551. }
  552. /*-------------------------------------------------------------
  553. ** Action Procs
  554. **-------------------------------------------------------------
  555. */
  556. /*-------------------------------------------------------------
  557. ** Core Procs
  558. **-------------------------------------------------------------
  559. */
  560. /*-------------------------------------------------------------
  561. ** Initialize
  562. ** Initialize a new gadget instance.
  563. */
  564. /* ARGSUSED */
  565. static void
  566. Initialize(
  567. Widget request_w,
  568. Widget new_w )
  569. {
  570. DtClockGadget request = (DtClockGadget) request_w,
  571. new = (DtClockGadget) new_w;
  572. Dimension w, h,
  573. h_t = G_HighlightThickness (new),
  574. s_t = G_ShadowThickness (new);
  575. XmManagerWidget mw = (XmManagerWidget) XtParent (new);
  576. EventMask mask;
  577. String name = NULL;
  578. /* Set width and height.
  579. */
  580. if ((G_Width (request) == 0) ||
  581. (G_Height (request) == 0))
  582. {
  583. G_ClockWidth (new) = SIZE_DEFAULT;
  584. G_ClockHeight (new) = SIZE_DEFAULT;
  585. G_GetSize ((DtIconGadget)new, &w, &h);
  586. if (G_Width (request) == 0)
  587. G_Width (new) = w;
  588. if (G_Height (request) == 0)
  589. G_Height (new) = h;
  590. }
  591. Resize ((Widget)new);
  592. if (G_ClockInterval (new) <= 0)
  593. G_ClockInterval (new) = 60; /* make invalid update's use a default */
  594. new->clock.interval_id = 0;
  595. new->clock.numseg = 0;
  596. }
  597. /*-------------------------------------------------------------
  598. ** Destroy
  599. ** Release resources allocated for gadget.
  600. */
  601. static void
  602. Destroy(
  603. Widget w )
  604. {
  605. DtClockGadget g = (DtClockGadget) w;
  606. XmManagerWidget mw = (XmManagerWidget) XtParent (g);
  607. if (g->clock.interval_id) XtRemoveTimeOut (g->clock.interval_id);
  608. XtReleaseGC ((Widget) mw, G_ClockHandGC (g));
  609. }
  610. /*-------------------------------------------------------------
  611. ** Resize
  612. ** Set positions of string and pixmap.
  613. */
  614. static void
  615. Resize(
  616. Widget widget )
  617. {
  618. DtClockGadget g = (DtClockGadget) widget;
  619. Position pix_x, pix_y, str_x, str_y;
  620. Dimension s_t = G_ShadowThickness (g),
  621. h_t = G_HighlightThickness (g),
  622. p_w = G_PixmapWidth (g),
  623. p_h = G_PixmapHeight (g),
  624. m_w = G_MarginWidth (g),
  625. m_h = G_MarginHeight (g),
  626. s_w = G_StringWidth (g),
  627. s_h = G_StringHeight (g),
  628. v_pad = 2 * (s_t + h_t + m_h),
  629. h_pad = 2 * (s_t + h_t + m_w),
  630. spacing = G_Spacing (g),
  631. w = G_Width (g),
  632. h = G_Height (g);
  633. int radius;
  634. G_ClockWidth (g) = p_w - G_LeftInset (g) - G_RightInset (g);
  635. G_ClockHeight (g) = p_h - G_TopInset (g) - G_BottomInset (g);
  636. G_ClockWidth (g) = min (G_ClockWidth (g), G_ClockHeight (g));
  637. G_ClockHeight (g) = G_ClockWidth (g);
  638. G_GetPositions ((DtIconGadget)g, w, h, h_t, s_t,
  639. &pix_x, &pix_y, &str_x, &str_y);
  640. /* Compute clock size factors.
  641. * (need signed radius value since Dimension is unsigned)
  642. */
  643. radius = ((int) min (G_ClockWidth (g), G_ClockHeight (g))/2);
  644. g->clock.radius = (Dimension) max (radius, 1);
  645. if (G_ClockWidth (g) < (Dimension)(SIZE_DEFAULT / 2))
  646. {
  647. g->clock.tick_spacing =
  648. ((Dimension)(TICK_FRACT * g->clock.radius)/100);
  649. g->clock.minute_hand_length =
  650. ((Dimension)(MINUTE_HAND_FRACT * g->clock.radius)/100);
  651. g->clock.hour_hand_length =
  652. ((Dimension)(HOUR_HAND_FRACT * g->clock.radius)/100);
  653. g->clock.hand_width =
  654. ((Dimension)(HAND_WIDTH_FRACT * g->clock.radius)/100);
  655. }
  656. else
  657. {
  658. g->clock.tick_spacing =
  659. ((Dimension)(SMALL_TICK_FRACT * g->clock.radius)/100);
  660. g->clock.minute_hand_length =
  661. ((Dimension)(SMALL_MINUTE_HAND_FRACT * g->clock.radius)/100);
  662. g->clock.hour_hand_length =
  663. ((Dimension)(SMALL_HOUR_HAND_FRACT * g->clock.radius)/100);
  664. g->clock.hand_width =
  665. ((Dimension)(SMALL_HAND_WIDTH_FRACT * g->clock.radius)/100);
  666. }
  667. /* Compute clock position factors.
  668. */
  669. g->clock.centerX = pix_x + (p_w / 2);
  670. g->clock.centerY = pix_y + (p_h / 2);
  671. }
  672. /*-------------------------------------------------------------
  673. ** SetValues
  674. **
  675. */
  676. #if 0
  677. /* ARGSUSED */
  678. static Boolean
  679. SetValues(
  680. Widget current_w,
  681. Widget request_w,
  682. Widget new_w )
  683. {
  684. DtClockGadget request = (DtClockGadget) request_w,
  685. current = (DtClockGadget) current_w,
  686. new = (DtClockGadget) new_w;
  687. Boolean redraw_flag = False;
  688. if (G_ClockInterval (new) != current->clock.update)
  689. {
  690. if (current->clock.interval_id)
  691. XtRemoveTimeOut (current->clock.interval_id);
  692. if (XtIsRealized (new))
  693. new->clock.interval_id =
  694. XtAppAddTimeOut (
  695. XtWidgetToApplicationContext (new_w),
  696. G_ClockInterval (new)*1000,
  697. (XtTimerCallbackProc) ClockTick,
  698. (XtPointer)new_w);
  699. }
  700. /* Update clock face and hand color.
  701. */
  702. if ((G_ClockBackground (new) != G_ClockBackground (current)) ||
  703. (G_ClockHandPixel (new) != G_ClockHandPixel (current)))
  704. {
  705. G_UpdateGCs ((DtIconGadget)new);
  706. redraw_flag = True;
  707. }
  708. /* Update size factors if no resize.
  709. */
  710. if ((G_Width (new) == G_Width (current) &&
  711. G_Height (new) == G_Height (current)) &&
  712. (G_MarginWidth (new) != G_MarginWidth (current) ||
  713. G_MarginHeight (new) != G_MarginHeight (current) ||
  714. G_Spacing (new) != G_Spacing (current) ||
  715. G_ShadowThickness (new) != G_ShadowThickness (current) ||
  716. G_HighlightThickness (new) != G_HighlightThickness (current)))
  717. Resize (new_w);
  718. return (redraw_flag);
  719. }
  720. #endif /* 0 */
  721. /*-------------------------------------------------------------
  722. ** Gadget Procs
  723. **-------------------------------------------------------------
  724. */
  725. /*-------------------------------------------------------------
  726. ** Icon Procs
  727. **-------------------------------------------------------------
  728. */
  729. /*-------------------------------------------------------------
  730. ** Draw
  731. ** Draw gadget to drawable.
  732. */
  733. static void
  734. Draw(
  735. DtClockGadget g,
  736. Drawable drawable,
  737. Position x,
  738. Position y,
  739. Dimension w,
  740. Dimension h,
  741. Dimension h_t,
  742. Dimension s_t,
  743. unsigned char s_type,
  744. unsigned char fill_mode )
  745. {
  746. XmManagerWidget mgr = (XmManagerWidget) XtParent (g);
  747. Display * d = XtDisplay (g);
  748. GC gc;
  749. XRectangle clip;
  750. Position p_x, p_y, s_x, s_y;
  751. unsigned char behavior = G_Behavior (g);
  752. Dimension m_w = G_MarginWidth (g);
  753. Dimension m_h = G_MarginHeight (g);
  754. Dimension h_pad = h_t + s_t + m_w;
  755. Dimension v_pad = h_t + s_t + m_h;
  756. Dimension width, height;
  757. Pixmap pix;
  758. Pixmap mask;
  759. Boolean bMono;
  760. bMono = ( ((G_Foreground (g) == BlackPixelOfScreen (XtScreen (g))) ||
  761. (G_Foreground (g) == WhitePixelOfScreen (XtScreen (g)))) &&
  762. ((G_Background (g) == BlackPixelOfScreen (XtScreen (g))) ||
  763. (G_Background (g) == WhitePixelOfScreen (XtScreen (g)))) );
  764. if ((G_Armed (g)) && (fill_mode != XmFILL_PARENT))
  765. gc = G_ArmedBackgroundGC (g);
  766. else
  767. gc = M_BackgroundGC (mgr);
  768. if ((fill_mode != XmFILL_NONE) && (fill_mode != XmFILL_TRANSPARENT))
  769. XFillRectangle (d, drawable, gc, x + h_t, y + h_t,
  770. w - 2 * h_t, h - 2 * h_t);
  771. G_GetPositions ((DtIconGadget)g, w, h, h_t, s_t, &p_x, &p_y, &s_x, &s_y);
  772. if (G_Pixmap (g))
  773. {
  774. width = ((Dimension)(p_x + s_t + h_t) >= G_Width (g))
  775. ? 0 : min (G_PixmapWidth (g),
  776. (Dimension)(G_Width (g) - p_x - s_t - h_t));
  777. height = ((Dimension)(p_y + s_t + h_t) >= G_Height (g))
  778. ? 0 : min (G_PixmapHeight (g),
  779. (Dimension)(G_Height (g) - p_y - s_t - h_t));
  780. /* Use normal image.
  781. */
  782. pix = G_Pixmap (g);
  783. mask = G_Mask (g);
  784. /* Update clip gc.
  785. */
  786. if (mask != XmUNSPECIFIED_PIXMAP)
  787. {
  788. gc = G_ClipGC (g);
  789. XSetClipMask (XtDisplay(g), gc, mask);
  790. XSetClipOrigin (XtDisplay(g), gc, x + p_x, y + p_y);
  791. }
  792. else
  793. gc = G_NormalGC (g);
  794. /* Paint pixmap.
  795. */
  796. if ((gc != NULL) && (pix != XmUNSPECIFIED_PIXMAP))
  797. XCopyArea (d, pix, drawable, gc, 0, 0,
  798. width, height, x + p_x, y + p_y);
  799. }
  800. /* Fill clock face region and draw clock.
  801. */
  802. if (g->clock.numseg != 0)
  803. EraseHands (g, (struct tm *) 0);
  804. ClockTick ((XtPointer)g, (XtIntervalId*)NULL);
  805. /* Draw shadow.
  806. */
  807. if ((behavior == XmICON_BUTTON || behavior == XmICON_DRAG) &&
  808. G_FillOnArm (g) && G_Armed (g))
  809. gc = G_ArmedGC (g);
  810. else if (behavior == XmICON_TOGGLE && G_FillOnArm (g) &&
  811. ((G_Armed (g) && !G_Set (g)) ||
  812. (!G_Armed (g) && G_Set (g))))
  813. gc = G_ArmedGC (g);
  814. else
  815. gc = G_NormalGC (g);
  816. /* Draw string.
  817. */
  818. if (G_String (g))
  819. {
  820. clip.x = x + h_t + s_x;
  821. clip.y = y + h_t + s_y;
  822. clip.width = G_Width (g) - (2 * (h_t + s_t));
  823. clip.height = G_Height (g) - (2 * (h_t + s_t));
  824. if (clip.width > 0 && clip.height > 0)
  825. {
  826. if (bMono)
  827. {
  828. if ((s_x - 2) >= (Position)(h_t + s_t))
  829. XFillRectangle (d, drawable,
  830. G_ArmedBackgroundGC (g),
  831. x + s_x - 2, y + s_y,
  832. 2, G_StringHeight (g));
  833. XmStringDrawImage (d, drawable, G_FontList (g),
  834. G_String (g), G_NormalGC (g),
  835. x + s_x, y + s_y,
  836. clip.width, XmALIGNMENT_BEGINNING,
  837. XmSTRING_DIRECTION_L_TO_R, &clip);
  838. if ((s_x + (Position)(G_StringWidth (g) + 2))
  839. <= (Position)(G_Width (g) - h_t - s_t))
  840. XFillRectangle (d, drawable,
  841. G_ArmedBackgroundGC (g),
  842. x + s_x + G_StringWidth (g),
  843. y + s_y, 2, G_StringHeight (g));
  844. }
  845. else
  846. {
  847. if (G_UseEmbossedText (g))
  848. XmStringDraw (d, drawable, G_FontList (g),
  849. G_String (g), G_BottomShadowGC (g),
  850. x + s_x + 1, y + s_y + 1,
  851. clip.width, XmALIGNMENT_BEGINNING,
  852. XmSTRING_DIRECTION_L_TO_R, &clip);
  853. XmStringDraw (d, drawable, G_FontList (g),
  854. G_String (g), G_NormalGC (g),
  855. x + s_x, y + s_y,
  856. clip.width, XmALIGNMENT_BEGINNING,
  857. XmSTRING_DIRECTION_L_TO_R, &clip);
  858. }
  859. }
  860. }
  861. }
  862. /*-------------------------------------------------------------
  863. ** UpdateGCs
  864. ** Get normal and background graphics contexts.
  865. ** Use standard mask to maximize caching opportunities.
  866. */
  867. static void
  868. UpdateGCs(
  869. DtClockGadget g )
  870. {
  871. XGCValues values;
  872. XtGCMask value_mask;
  873. XmManagerWidget mw = (XmManagerWidget) XtParent(g);
  874. XFontStruct * font;
  875. Boolean font_rtn;
  876. DtIconGadgetClass
  877. super = (DtIconGadgetClass) XtSuperclass (g);
  878. static Boolean first = True;
  879. /* Let superclass do most of the work.
  880. */
  881. (* C_UpdateGCs (super)) ((DtIconGadget)g);
  882. if (first)
  883. first = False;
  884. else if (G_ClockHandGC (g))
  885. XtReleaseGC ((Widget)mw, G_ClockHandGC (g));
  886. /* Get clock hand GC.
  887. */
  888. value_mask = GCForeground | GCFillStyle;
  889. if (XmeRenderTableGetDefaultFont (G_FontList (g), &font)) {
  890. value_mask |= GCFont;
  891. values.font = font->fid;
  892. }
  893. if (((G_PixmapForeground (g) == WhitePixelOfScreen (XtScreen (g))) &&
  894. (G_PixmapBackground (g) == BlackPixelOfScreen (XtScreen (g)))) ||
  895. ((G_PixmapForeground (g) == BlackPixelOfScreen (XtScreen (g))) &&
  896. (G_PixmapBackground (g) == WhitePixelOfScreen (XtScreen (g)))))
  897. values.foreground = G_PixmapBackground (g);
  898. else
  899. values.foreground = mw->manager.top_shadow_color;
  900. values.fill_style = FillSolid;
  901. G_ClockHandGC (g) = XtGetGC ((Widget) mw, value_mask, &values);
  902. /* Get clock background GC
  903. */
  904. value_mask |= GCBackground;
  905. if (((G_PixmapForeground (g) == WhitePixelOfScreen (XtScreen (g))) &&
  906. (G_PixmapBackground (g) == BlackPixelOfScreen (XtScreen (g)))) ||
  907. ((G_PixmapForeground (g) == BlackPixelOfScreen (XtScreen (g))) &&
  908. (G_PixmapBackground (g) == WhitePixelOfScreen (XtScreen (g)))))
  909. values.foreground = G_PixmapForeground (g);
  910. else
  911. values.foreground = G_ArmColor (g);
  912. values.background = G_PixmapBackground (g);
  913. G_ClockBackgroundGC (g) = XtGetGC ((Widget) mw, value_mask, &values);
  914. }
  915. /*-------------------------------------------------------------
  916. ** Public Entry Points
  917. **-------------------------------------------------------------
  918. */
  919. /*-------------------------------------------------------------
  920. ** DtCreateClock
  921. ** Create a new gadget instance.
  922. **-------------------------------------------------------------
  923. */
  924. Widget
  925. DtCreateClock(
  926. Widget parent,
  927. String name,
  928. ArgList arglist,
  929. Cardinal argcount )
  930. {
  931. return (XtCreateWidget (name, dtClockGadgetClass,
  932. parent, arglist, argcount));
  933. }