aboutsummaryrefslogtreecommitdiff
path: root/src/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/clock.c')
-rw-r--r--src/clock.c332
1 files changed, 332 insertions, 0 deletions
diff --git a/src/clock.c b/src/clock.c
new file mode 100644
index 0000000..147c1f6
--- /dev/null
+++ b/src/clock.c
@@ -0,0 +1,332 @@
+/**
+ * @file clock.c
+ * @author Joe Wingbermuehle
+ * @date 2005-2006
+ *
+ * @brief Clock tray component.
+ *
+ */
+
+#include "jwm.h"
+#include "clock.h"
+#include "tray.h"
+#include "color.h"
+#include "font.h"
+#include "timing.h"
+#include "main.h"
+#include "root.h"
+#include "cursor.h"
+#include "popup.h"
+#include "misc.h"
+
+/** Structure to respresent a clock tray component. */
+typedef struct ClockType {
+
+ TrayComponentType *cp; /**< Common component data. */
+
+ char *format; /**< The time format to use. */
+ char *command; /**< A command to run when clicked. */
+ char shortTime[80]; /**< Currently displayed time. */
+
+ /* The following are used to control popups. */
+ int mousex; /**< Last mouse x-coordinate. */
+ int mousey; /**< Last mouse y-coordinate. */
+ TimeType mouseTime; /**< Time of the last mouse motion. */
+
+ int userWidth; /**< User-specified clock width (or 0). */
+
+ struct ClockType *next; /**< Next clock in the list. */
+
+} ClockType;
+
+/** The default time format to use. */
+static const char *DEFAULT_FORMAT = "%I:%M %p";
+
+static ClockType *clocks;
+static TimeType lastUpdate = ZERO_TIME;
+
+static void Create(TrayComponentType *cp);
+static void Resize(TrayComponentType *cp);
+static void Destroy(TrayComponentType *cp);
+static void ProcessClockButtonEvent(TrayComponentType *cp,
+ int x, int y, int mask);
+static void ProcessClockMotionEvent(TrayComponentType *cp,
+ int x, int y, int mask);
+
+static void DrawClock(ClockType *clk, const TimeType *now, int x, int y);
+
+/** Initialize clocks. */
+void InitializeClock() {
+ clocks = NULL;
+}
+
+/** Start clock(s). */
+void StartupClock() {
+
+ ClockType *clk;
+
+ for(clk = clocks; clk; clk = clk->next) {
+ if(clk->cp->requestedWidth == 0) {
+ clk->cp->requestedWidth = GetStringWidth(FONT_CLOCK, clk->format) + 4;
+ }
+ if(clk->cp->requestedHeight == 0) {
+ clk->cp->requestedHeight = GetStringHeight(FONT_CLOCK) + 4;
+ }
+ }
+
+}
+
+/** Stop clock(s). */
+void ShutdownClock() {
+}
+
+/** Destroy clock(s). */
+void DestroyClock() {
+
+ ClockType *cp;
+
+ while(clocks) {
+ cp = clocks->next;
+
+ if(clocks->format) {
+ Release(clocks->format);
+ }
+ if(clocks->command) {
+ Release(clocks->command);
+ }
+
+ Release(clocks);
+ clocks = cp;
+ }
+
+}
+
+/** Create a clock tray component. */
+TrayComponentType *CreateClock(const char *format, const char *command,
+ int width, int height) {
+
+ TrayComponentType *cp;
+ ClockType *clk;
+
+ clk = Allocate(sizeof(ClockType));
+ clk->next = clocks;
+ clocks = clk;
+
+ clk->mousex = 0;
+ clk->mousey = 0;
+ clk->mouseTime.seconds = 0;
+ clk->mouseTime.ms = 0;
+ clk->userWidth = 0;
+
+ if(!format) {
+ format = DEFAULT_FORMAT;
+ }
+ clk->format = CopyString(format);
+
+ clk->command = CopyString(command);
+
+ clk->shortTime[0] = 0;
+
+ cp = CreateTrayComponent();
+ cp->object = clk;
+ clk->cp = cp;
+ if(width > 0) {
+ cp->requestedWidth = width;
+ clk->userWidth = 1;
+ } else {
+ cp->requestedWidth = 0;
+ clk->userWidth = 0;
+ }
+ cp->requestedHeight = height;
+
+ cp->Create = Create;
+ cp->Resize = Resize;
+ cp->Destroy = Destroy;
+ cp->ProcessButtonEvent = ProcessClockButtonEvent;
+ cp->ProcessMotionEvent = ProcessClockMotionEvent;
+
+ return cp;
+
+}
+
+/** Initialize a clock tray component. */
+void Create(TrayComponentType *cp) {
+
+ ClockType *clk;
+
+ Assert(cp);
+
+ clk = (ClockType*)cp->object;
+
+ Assert(clk);
+
+ cp->pixmap = JXCreatePixmap(display, rootWindow, cp->width, cp->height,
+ rootDepth);
+
+ JXSetForeground(display, rootGC, colors[COLOR_CLOCK_BG]);
+ JXFillRectangle(display, cp->pixmap, rootGC, 0, 0, cp->width, cp->height);
+
+}
+
+/** Resize a clock tray component. */
+void Resize(TrayComponentType *cp) {
+
+ ClockType *clk;
+ TimeType now;
+ int x, y;
+
+ Assert(cp);
+
+ clk = (ClockType*)cp->object;
+
+ Assert(clk);
+
+ if(cp->pixmap != None) {
+ JXFreePixmap(display, cp->pixmap);
+ }
+
+ cp->pixmap = JXCreatePixmap(display, rootWindow, cp->width, cp->height,
+ rootDepth);
+
+ clk->shortTime[0] = 0;
+
+ GetCurrentTime(&now);
+ GetMousePosition(&x, &y);
+ DrawClock(clk, &now, x, y);
+
+}
+
+/** Destroy a clock tray component. */
+void Destroy(TrayComponentType *cp) {
+
+ ClockType *clk;
+
+ Assert(cp);
+
+ clk = (ClockType*)cp->object;
+
+ Assert(clk);
+
+ if(cp->pixmap != None) {
+ JXFreePixmap(display, cp->pixmap);
+ }
+}
+
+/** Process a click event on a clock tray component. */
+void ProcessClockButtonEvent(TrayComponentType *cp, int x, int y, int mask) {
+
+ ClockType *clk;
+
+ Assert(cp);
+
+ clk = (ClockType*)cp->object;
+
+ Assert(clk);
+
+ if(clk->command) {
+ RunCommand(clk->command);
+ }
+
+}
+
+/** Process a motion event on a clock tray component. */
+void ProcessClockMotionEvent(TrayComponentType *cp,
+ int x, int y, int mask) {
+
+ Assert(cp);
+
+ ClockType *clk = (ClockType*)cp->object;
+ clk->mousex = cp->screenx + x;
+ clk->mousey = cp->screeny + y;
+ GetCurrentTime(&clk->mouseTime);
+
+}
+
+/** Update a clock tray component. */
+void SignalClock(const TimeType *now, int x, int y) {
+
+ ClockType *cp;
+ int shouldDraw;
+ char *longTime;
+ time_t t;
+
+ Assert(now);
+
+ /* Determine if we should update the clock(s). */
+ if(GetTimeDifference(&lastUpdate, now) > 900) {
+ shouldDraw = 1;
+ lastUpdate = *now;
+ } else {
+ shouldDraw = 0;
+ }
+
+ /* Update each clock. */
+ for(cp = clocks; cp; cp = cp->next) {
+
+ if(shouldDraw) {
+ DrawClock(cp, now, x, y);
+ }
+
+ if(abs(cp->mousex - x) < POPUP_DELTA
+ && abs(cp->mousey - y) < POPUP_DELTA) {
+ if(GetTimeDifference(now, &cp->mouseTime) >= popupDelay) {
+ time(&t);
+ longTime = asctime(localtime(&t));
+ Trim(longTime);
+ ShowPopup(x, y, longTime);
+ }
+ }
+
+ }
+
+}
+
+/** Draw a clock tray component. */
+void DrawClock(ClockType *clk, const TimeType *now, int x, int y) {
+
+ TrayComponentType *cp;
+ const char *shortTime;
+ int width;
+ int rwidth;
+
+ Assert(clk);
+ Assert(now);
+
+ /* Only draw if the label changed. */
+ shortTime = GetTimeString(clk->format);
+ if(!strcmp(clk->shortTime, shortTime)) {
+ return;
+ }
+ strcpy(clk->shortTime, shortTime);
+
+ cp = clk->cp;
+
+ /* Clear the area. */
+ JXSetForeground(display, rootGC, colors[COLOR_CLOCK_BG]);
+ JXFillRectangle(display, cp->pixmap, rootGC, 0, 0,
+ cp->width, cp->height);
+
+ /* Determine if the clock is the right size. */
+ width = GetStringWidth(FONT_CLOCK, shortTime);
+ rwidth = width + 4;
+ if(rwidth == clk->cp->requestedWidth || clk->userWidth) {
+
+ /* Draw the clock. */
+ RenderString(cp->pixmap, FONT_CLOCK, COLOR_CLOCK_FG,
+ cp->width / 2 - width / 2,
+ cp->height / 2 - GetStringHeight(FONT_CLOCK) / 2,
+ cp->width, NULL, shortTime);
+
+ UpdateSpecificTray(clk->cp->tray, clk->cp);
+
+ } else {
+
+ /* Wrong size. Resize. */
+ clk->cp->requestedWidth = rwidth;
+ ResizeTray(clk->cp->tray);
+
+ }
+
+}
+
+