AmendHub

Download

ftech

/

Logger

/

logger.c

 

(View History)

Francois Techene   Updating license from GPLv3 to MIT. Latest amendment: 8 on 2026-03-30

1 /* logger.c
2 *
3 * Copyright 2026 Francois Techene
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Except as contained in this notice, the name(s) of the above copyright
25 * holders shall not be used in advertising or otherwise to promote the sale,
26 * use or other dealings in this Software without prior written
27 * authorization.
28 *
29 * ----------------------------------------------------------------
30 * Utility library to log to a file or to the console.
31 *
32 * Before using the logger, you must initialize it by calling:
33 *
34 * initLogger(DEBUG_LEVEL, LOG_METHOD, LOG_FILE);
35 *
36 * Where those variables are defined in logger.h.
37 *
38 * You may put all logging code inbetween the USE_LOGGER condition
39 * so that loggin logic can be easily fully disabled.
40 *
41 * #ifdef USE_LOGGER
42 * initLogger(DEBUG_LEVEL, LOG_METHOD, LOG_FILE);
43 * #endif
44 *
45 * #ifdef USE_LOGGER
46 * logger.debug("message");
47 * #endif
48 *
49 * If you are logging to the console, you need to forward the
50 * application's events to the logger and ignore the event if it
51 * has been handled by the console:
52 *
53 * if(logger.onEvent(event)) {
54 * return;
55 * }
56 * ----------------------------------------------------------------
57 */
58
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <stdarg.h>
62 #include <string.h>
63
64 #include "logger.h"
65
66
67 void LogToNone(char *format, ...);
68 Boolean DoNotIntercept(EventRecord event);
69
70 #ifdef USE_LOGGER
71
72 typedef struct _LogTextState {
73 int font;
74 int size;
75 int mode;
76 int face;
77
78 } LogTextState;
79
80 #define CONSOLE_BAR_SIZE 12
81 #define CONSOLE_TEXT_FONT monaco
82 #define CONSOLE_TEXT_SIZE 9
83 #define CONSOLE_MIN_HEIGHT 67
84 #define CONSOLE_MIN_WIDTH 150
85
86 LogTextState logSavedTextState;
87 PenState logSavedPentState;
88
89 void UseLogger(LogLevel level, LogOutputMethod out, char *filePath);
90 void LogConsoleInit(void);
91 void LogConsoleDraw(void);
92 void LogConsoleUpdate(void);
93 void LogConsoleInitScrollbar(void);
94 void LogConsoleResetTE(void);
95 void LogConsoleResetScroll(void);
96 void LogConsoleScrollToBottom(void);
97 void LogConsoleSetLayout();
98 void LogConsoleResize(Rect* newBounds);
99 void LogConsoleZoom(void);
100 void LogConsoleClear(void);
101 void LogToConsole(char *format, ...);
102 void LogToFile(char *format, ...);
103 void LogDefault(char *format, ...);
104 void LogDebug(char *format, ...);
105 void LogInfo(char *format, ...);
106 void LogWarn(char *format, ...);
107 void LogError(char *format, ...);
108 int DoLogGrow(Point p);
109 pascal void DoLogScroll(ControlHandle ctl, short ctlEventIn);
110 Boolean DoLogEvent(EventRecord event);
111
112 void LogSaveTextState(void);
113 void LogRestoreTextState(void);
114
115 #endif
116
117 Logger logger;
118
119 void
120 LogToNone(char* format, ...)
121 {
122 (void) format; // unused.
123 return;
124 }
125
126 Boolean
127 DoNotIntercept(EventRecord event)
128 {
129 return false;
130 }
131
132 void
133 InitLogger(LogLevel level,
134 LogOutputMethod out,
135 char* filePath)
136 {
137 logger.print = LogToNone;
138 logger.debug = LogToNone;
139 logger.info = LogToNone;
140 logger.warn = LogToNone;
141 logger.error = LogToNone;
142
143 logger.onEvent = DoNotIntercept;
144
145
146 #ifdef USE_LOGGER
147 UseLogger(level,out, filePath);
148 #endif
149 }
150
151 #ifdef USE_LOGGER // Only load if required.
152
153 void
154 UseLogger(LogLevel level,
155 LogOutputMethod out,
156 char* filePath)
157 {
158 logger.log = LogDefault;
159 logger.debug = LogDebug;
160 logger.info = LogInfo;
161 logger.warn = LogWarn;
162 logger.error = LogError;
163
164 logger.logLevel = level;
165 logger.outputMethod = out;
166 logger.filePath = filePath;
167
168 logger.console.textArea = NULL;
169
170 if (out == CONSOLE_OUT) {
171 logger.onEvent = DoLogEvent;
172 LogConsoleInit();
173 }
174 else if (out == FILE_OUT) {
175 FILE* file;
176
177 // Using Unix New Line character for tail to
178 // read correctly on Linux.
179 //
180 logger.newLine = "\x0A\r";
181
182 logger.print = LogToFile;
183
184 // Empty log file. If the file cannot be created, the log output
185 // is set to NONE_OUT;
186 //
187 file = fopen(logger.filePath, "w");
188 if(!file) {
189 logger.outputMethod = NONE_OUT;
190 logger.print = LogToNone;
191 return;
192 }
193 fprintf(file, "");
194 fclose(file);
195 }
196 else {
197 logger.print = LogToNone;
198 }
199 }
200
201
202 void
203 LogConsoleInit(void)
204 {
205 GrafPtr oldPort;
206 Rect winBounds;
207 Rect viewRect;
208 Rect textRect;
209
210 logger.console.lineHeight = CONSOLE_TEXT_SIZE + 2;
211 logger.console.width = screenBits.bounds.right - 2;
212 logger.console.scrollPos = 0;
213 logger.console.maxScrollPos = 0;
214 logger.console.nbLines = 0;
215 logger.console.contentHeight = 0;
216 logger.console.nbOutputLines = CONSOLE_LINES;
217 logger.console.height = (logger.console.lineHeight * CONSOLE_LINES)
218 + (CONSOLE_BAR_SIZE * 2) - 1;
219
220
221 // Make prevBounds to the zoomed in position for zoom toggle
222 //
223 logger.console.growBounds.left = screenBits.bounds.left + 5;
224 logger.console.growBounds.right = screenBits.bounds.right - 5;
225 logger.console.growBounds.top = screenBits.bounds.top + 25;
226 logger.console.growBounds.bottom = screenBits.bounds.bottom - 5;
227
228 logger.console.prevBounds = logger.console.growBounds;
229
230 logger.newLine = "\r";
231 logger.print = LogToConsole;
232
233 winBounds.left = screenBits.bounds.left + 1;
234 winBounds.right = screenBits.bounds.right - 1;
235 winBounds.bottom = screenBits.bounds.bottom - 1;
236 winBounds.top = winBounds.bottom - logger.console.height;
237
238
239 logger.console.window = NewWindow(0L, &winBounds, "\pConsole", TRUE,
240 plainDBox, (WindowPtr)-1L, TRUE, 0);
241
242 if (!logger.console.window) {
243 logger.print = LogToNone;
244 return;
245 }
246
247 logger.console.origBounds = winBounds;
248
249 GetPort(&oldPort);
250 SetPort(logger.console.window);
251
252 SendBehind(logger.console.window, NULL);
253
254 LogConsoleSetLayout();
255
256
257 // Tex Edit
258 //
259 viewRect = logger.console.view;
260 //InsetRect(&viewRect, 2, 2);
261
262 textRect = viewRect;
263 InsetRect(&textRect, 2, 0);
264
265 logger.console.textArea = TENew(&textRect, &viewRect);
266
267 (*(logger.console.textArea))->txFont = CONSOLE_TEXT_FONT;
268 (*(logger.console.textArea))->txSize = CONSOLE_TEXT_SIZE;
269 (*(logger.console.textArea))->lineHeight = logger.console.lineHeight;
270 (*(logger.console.textArea))->fontAscent = logger.console.lineHeight - 2;
271 (*(logger.console.textArea))->txFace = 0;
272
273 //TEActivate(logger.console.textArea);
274
275 LogConsoleInitScrollbar();
276
277 LogConsoleDraw();
278
279 SetPort(oldPort);
280 }
281
282 void LogConsoleDraw(void)
283 {
284 Rect r;
285 Pattern tbarPattern;
286 GrafPtr oldPort;
287
288 GetPort(&oldPort);
289 SetPort(logger.console.window);
290
291 LogSaveTextState();
292 GetPenState(&logSavedPentState);
293 PenNormal();
294
295 EraseRect(&logger.console.view);
296
297 GetIndPattern(&tbarPattern, sysPatListID, 24);
298 FillRect(&logger.console.titleBar, tbarPattern);
299 FrameRect(&logger.console.titleBar);
300
301 FillRect(&logger.console.bottomBar, white);
302 FrameRect(&logger.console.bottomBar);
303
304 FillRect(&logger.console.growBtn, white);
305 FrameRect(&logger.console.growBtn);
306 r = logger.console.growBtn;
307 InsetRect(&r, 5, 3);
308 OffsetRect(&r, 1, 1);
309 FrameRect(&r);
310
311 r.right -= 1;
312 r.bottom -= 1;
313 OffsetRect(&r, -2, -2);
314 FillRect(&r, white);
315 FrameRect(&r);
316
317 // Lower button
318 //
319 FillRect(&logger.console.lowerBtn, white);
320 FrameRect(&logger.console.lowerBtn);
321 MoveTo(logger.console.lowerBtn.left + 4,
322 logger.console.lowerBtn.bottom - 2);
323
324 TextFont(geneva);
325 TextFace(0);
326 TextSize(12);
327
328 DrawString("\p_");
329
330
331 // Clear button
332 //
333 FillRect(&logger.console.clearBtn, white);
334 FrameRect(&logger.console.clearBtn);
335 MoveTo(logger.console.clearBtn.left + 4,
336 logger.console.clearBtn.bottom - 2);
337
338 TextFont(geneva);
339 TextFace(0);
340 TextSize(8);
341
342 DrawString("\pclear");
343
344 // Close button
345 //
346 FillRect(&logger.console.closeBtn, white);
347 FrameRect(&logger.console.closeBtn);
348
349 // Expand button
350 //
351 FillRect(&logger.console.zoomBtn, white);
352 FrameRect(&logger.console.zoomBtn);
353
354
355 LogConsoleUpdate();
356
357
358 LogRestoreTextState();
359 SetPenState(&logSavedPentState);
360
361 SetPort(oldPort);
362 }
363
364 void LogConsoleUpdate(void)
365 {
366 TEUpdate(&logger.console.view, logger.console.textArea);
367 DrawControls(logger.console.window);
368 }
369
370 void
371 LogConsoleInitScrollbar(void)
372 {
373 GrafPtr oldPort;
374 Rect scrollbarRect;
375 int value;
376
377 GetPort(&oldPort);
378 SetPort(logger.console.window);
379
380 scrollbarRect.left = logger.console.window->portRect.right - 15;
381 scrollbarRect.right = logger.console.window->portRect.right + 1;
382 scrollbarRect.top = logger.console.titleBar.bottom - 1;
383 scrollbarRect.bottom = logger.console.bottomBar.top + 1;
384
385 value = logger.console.contentHeight - logger.console.height;
386
387 logger.console.vScroll = NewControl(logger.console.window,
388 &scrollbarRect,
389 "\p",
390 TRUE,
391 0, // intinial value;
392 0, // min
393 value, // max
394 scrollBarProc,
395 0);
396
397 SetCtlMax(logger.console.vScroll,
398 logger.console.contentHeight - logger.console.height);
399
400 SetCtlValue(logger.console.vScroll, logger.console.scrollPos);
401
402 HiliteControl(logger.console.vScroll, 255);
403
404 SetPort(oldPort);
405 }
406
407 void
408 LogConsoleResetTE(void)
409 {
410 Rect viewRect = logger.console.view;
411
412 //InsetRect(&viewRect, 2, 2);
413
414 // Resize the size of the text area
415 //
416 (*(logger.console.textArea))->viewRect = viewRect;
417 (*(logger.console.textArea))->destRect.right = viewRect.right - 1;
418 }
419
420 void
421 LogConsoleResetScroll(void)
422 {
423 int oldMaxScrollPos = logger.console.maxScrollPos;
424
425 logger.console.maxScrollPos = (logger.console.nbLines
426 - logger.console.nbOutputLines)
427 * logger.console.lineHeight;
428
429 if (logger.console.maxScrollPos <= 0) {
430
431 // If there is nothing to scroll,
432 // put everything back at the top
433 //
434 TEScroll(0, logger.console.scrollPos, logger.console.textArea);
435
436 logger.console.scrollPos = 0;
437 logger.console.maxScrollPos = 0;
438 }
439 else if (logger.console.scrollPos > logger.console.maxScrollPos) {
440
441 // Window is growing
442 //
443 if (logger.console.maxScrollPos < oldMaxScrollPos) {
444
445 int delta = logger.console.scrollPos - logger.console.maxScrollPos;
446 TEScroll(0, delta, logger.console.textArea);
447 }
448
449 logger.console.scrollPos = logger.console.maxScrollPos;
450 }
451 else {
452 HiliteControl(logger.console.vScroll, 0);
453 }
454
455 MoveControl(logger.console.vScroll,
456 logger.console.bounds.right - 15,
457 logger.console.titleBar.bottom - 1);
458
459 SizeControl(logger.console.vScroll,
460 16,
461 logger.console.bottomBar.top
462 - logger.console.titleBar.bottom + 2);
463
464 SetCtlMax(logger.console.vScroll, logger.console.maxScrollPos);
465 SetCtlValue(logger.console.vScroll, logger.console.scrollPos);
466 }
467
468 void
469 LogConsoleScrollToBottom(void)
470 {
471 int delta = logger.console.maxScrollPos - logger.console.scrollPos;
472
473 logger.console.scrollPos = logger.console.maxScrollPos;
474 SetCtlValue(logger.console.vScroll, logger.console.scrollPos);
475
476 TEScroll(0, -delta, logger.console.textArea);
477
478 LogConsoleUpdate();
479 }
480
481 void
482 LogConsoleSetLayout(void)
483 {
484 logger.console.bounds = logger.console.window->portRect;
485
486 logger.console.view = logger.console.bounds;
487 logger.console.view.right -= 15;
488 logger.console.view.top += CONSOLE_BAR_SIZE;
489 logger.console.view.bottom -= CONSOLE_BAR_SIZE - 1;
490
491 // Title bar & buttons
492 //
493 logger.console.titleBar.left = logger.console.bounds.left - 1;
494 logger.console.titleBar.right = logger.console.bounds.right + 1;
495 logger.console.titleBar.top = logger.console.bounds.top - 1;
496 logger.console.titleBar.bottom = logger.console.titleBar.top
497 + CONSOLE_BAR_SIZE + 1;
498
499 logger.console.bottomBar.left = logger.console.bounds.left - 1;
500 logger.console.bottomBar.right = logger.console.bounds.right + 1;
501 logger.console.bottomBar.top = logger.console.bounds.bottom
502 - CONSOLE_BAR_SIZE +1;
503 logger.console.bottomBar.bottom = logger.console.bounds.bottom + 1;
504
505
506 logger.console.zoomBtn.right = logger.console.bounds.right - 5;
507 logger.console.zoomBtn.left = logger.console.zoomBtn.right - 9;
508 logger.console.zoomBtn.top = logger.console.bounds.top + 1;
509 logger.console.zoomBtn.bottom = logger.console.zoomBtn.top + 9;
510
511 logger.console.growBtn.right = logger.console.bounds.right + 1;
512 logger.console.growBtn.left = logger.console.growBtn.right - 16;
513 logger.console.growBtn.bottom = logger.console.bounds.bottom + 1;
514 logger.console.growBtn.top = logger.console.growBtn.bottom
515 - CONSOLE_BAR_SIZE;
516
517
518 logger.console.lowerBtn.right = logger.console.zoomBtn.left - 10;
519 logger.console.lowerBtn.left = logger.console.lowerBtn.right - 16;
520 logger.console.lowerBtn.top = logger.console.bounds.top + 1;
521 logger.console.lowerBtn.bottom = logger.console.lowerBtn.top + 9;
522
523 logger.console.clearBtn.right = logger.console.lowerBtn.left -4;
524 logger.console.clearBtn.left = logger.console.clearBtn.right - 26;
525 logger.console.clearBtn.top = logger.console.bounds.top + 1;
526 logger.console.clearBtn.bottom = logger.console.clearBtn.top + 9;
527
528 logger.console.closeBtn.left = logger.console.bounds.left + 5;
529 logger.console.closeBtn.right = logger.console.closeBtn.left + 9;
530 logger.console.closeBtn.top = logger.console.bounds.top + 1;
531 logger.console.closeBtn.bottom = logger.console.closeBtn.top + 9;
532 }
533
534 void
535 LogConsoleResize(Rect* newBounds)
536 {
537 int width = newBounds->right - newBounds->left;
538 int height = newBounds->bottom - newBounds->top;
539
540 int nbLines = (int)((height - (CONSOLE_BAR_SIZE * 2) + 1)
541 / logger.console.lineHeight);
542
543 // Adjust the hieight of the window to match the number of
544 // lines and line height of the TE
545 //
546 logger.console.nbOutputLines = nbLines;
547 logger.console.width = width;
548 logger.console.height = (logger.console.lineHeight * nbLines)
549 + (CONSOLE_BAR_SIZE * 2) - 1;
550
551 newBounds->bottom = newBounds->top + logger.console.height;
552
553 MoveWindow(logger.console.window,
554 newBounds->left,
555 newBounds->top,
556 TRUE);
557
558 SizeWindow(logger.console.window,
559 logger.console.width,
560 logger.console.height,
561 FALSE);
562
563 EraseRect(newBounds);
564 LogConsoleSetLayout();
565 LogConsoleResetTE();
566 LogConsoleResetScroll();
567 LogConsoleDraw();
568
569 //LogConsoleScrollToBottom();
570 }
571
572 void
573 LogConsoleZoom(void)
574 {
575 Point topLeft;
576 Point bottomRight;
577
578 topLeft.h = logger.console.window->portRect.left;
579 topLeft.v = logger.console.window->portRect.top;
580
581 bottomRight.h = logger.console.window->portRect.right;
582 bottomRight.v = logger.console.window->portRect.bottom;
583
584 LocalToGlobal(&topLeft);
585 LocalToGlobal(&bottomRight);
586
587 LogConsoleResize(&logger.console.prevBounds);
588
589 logger.console.prevBounds.left = topLeft.h;
590 logger.console.prevBounds.top = topLeft.v;
591 logger.console.prevBounds.right = bottomRight.h;
592 logger.console.prevBounds.bottom = bottomRight.v;
593 }
594
595 void
596 LogConsoleClear(void)
597 {
598 GrafPtr oldPort;
599 Rect scrollbarRect;
600 int value;
601
602 GetPort(&oldPort);
603 SetPort(logger.console.window);
604
605 // Move back to the top of the text area
606 //
607 TEScroll(0, logger.console.scrollPos, logger.console.textArea);
608
609 // Select all and erase
610 //
611 TESetSelect(0,32767,logger.console.textArea);
612 TEDelete(logger.console.textArea);
613
614 logger.console.scrollPos = 0;
615 logger.console.maxScrollPos = 0;
616 logger.console.nbLines = 0;
617 logger.console.contentHeight = 0;
618
619 SetCtlMax(logger.console.vScroll, 0);
620 SetCtlValue(logger.console.vScroll, 0);
621
622 HiliteControl(logger.console.vScroll, 255);
623
624 LogConsoleUpdate();
625
626 SetPort(oldPort);
627 }
628
629 void
630 LogToConsole(char* format, ...)
631 {
632 va_list ap;
633 char log[256] = "";
634 int oldMaxScroll = logger.console.maxScrollPos;
635
636 GrafPtr oldPort;
637
638 GetPort(&oldPort);
639 SetPort(logger.console.window);
640
641 va_start(ap, format);
642 vsprintf(log, format, ap);
643 va_end(ap);
644
645
646 TEInsert(log, strlen(log), logger.console.textArea);
647
648
649 // Update scroll data
650 //
651 logger.console.nbLines = (*(logger.console.textArea))->nLines;
652 logger.console.contentHeight = logger.console.nbLines * logger.console.lineHeight;
653
654 logger.console.maxScrollPos = (logger.console.nbLines
655 - logger.console.nbOutputLines)
656 * logger.console.lineHeight;
657
658 SetCtlMax(logger.console.vScroll, logger.console.maxScrollPos);
659
660
661 // Auto-scroll to bottom (do this only once)
662 //
663 if (logger.console.nbLines == logger.console.nbOutputLines + 1) {
664 // Enable the scrollbar once it is needed
665 //
666 HiliteControl(logger.console.vScroll, 0);
667 }
668
669 if (logger.console.nbLines > logger.console.nbOutputLines &&
670 logger.console.scrollPos == oldMaxScroll) {
671
672 LogConsoleScrollToBottom();
673 }
674
675 SetPort(oldPort);
676
677 ShowHide(logger.console.window, TRUE);
678 }
679 void
680 LogToFile(char* format, ...)
681 {
682 FILE* file;
683 va_list ap;
684
685 // Open file in Append Binary mode so the
686 // new line character is not converted.
687 //
688 file = fopen(logger.filePath, "ab");
689 if(!file) {
690 return;
691 }
692
693 va_start(ap, format);
694 vfprintf(file, format, ap);
695 va_end(ap);
696
697 fclose(file);
698 }
699
700 void
701 LogDefault(char* format, ...)
702 {
703 va_list ap;
704 char log[256] = "";
705
706 va_start(ap, format);
707 vsprintf(log, format, ap);
708 va_end(ap);
709
710 logger.print("%s %s", log, logger.newLine);
711 }
712
713 void
714 LogDebug(char* format, ...)
715 {
716 va_list ap;
717 char log[256] = "";
718
719 if (logger.logLevel < DEBUG_LEVEL) {
720 return;
721 }
722
723 va_start(ap, format);
724 vsprintf(log, format, ap);
725 va_end(ap);
726
727
728 logger.print("DEBUG: %s %s", log, logger.newLine);
729 }
730
731 void
732 LogInfo(char* format, ...)
733 {
734 va_list ap;
735 char log[256] = "";
736
737 if (logger.logLevel < INFO_LEVEL) {
738 return;
739 }
740
741 va_start(ap, format);
742 vsprintf(log, format, ap);
743 va_end(ap);
744
745 logger.print("INFO: %s %s", log, logger.newLine);
746 }
747
748 void
749 LogWarn(char* format, ...)
750 {
751 va_list ap;
752 char log[256] = "";
753
754 if (logger.logLevel < WARNING_LEVEL) {
755 return;
756 }
757
758 va_start(ap, format);
759 vsprintf(log, format, ap);
760 va_end(ap);
761
762 logger.print("WARNING: %s %s", log, logger.newLine);
763 }
764
765 void
766 LogError(char* format, ...)
767 {
768 va_list ap;
769 char log[256] = "";
770
771 if (logger.logLevel < ERROR_LEVEL) {
772 return;
773 }
774
775 va_start(ap, format);
776 vsprintf(log, format, ap);
777 va_end(ap);
778
779 logger.print("ERROR: %s %s", log, logger.newLine);
780 }
781
782
783 int
784 DoLogGrow(Point p)
785 {
786 Rect newBounds;
787 GrafPtr savePort;
788 Rect limits;
789 long theResult;
790 Point orig = {0, 0};
791
792 GetPort(&savePort);
793 SetPort(logger.console.window);
794
795 SetRect(&limits, CONSOLE_MIN_WIDTH, // Min horizontal size
796 CONSOLE_MIN_HEIGHT, // Min vertical size
797 screenBits.bounds.right, // Max horizontal size
798 screenBits.bounds.bottom); // Max vertical size
799
800 theResult = GrowWindow(logger.console.window, p, &limits);
801 if (theResult == 0) {
802 return 0;
803 }
804
805 LocalToGlobal(&orig);
806 newBounds.left = orig.h;
807 newBounds.right = newBounds.left + LoWord(theResult);
808 newBounds.top = orig.v;
809 newBounds.bottom = newBounds.top + HiWord(theResult);
810
811 LogConsoleResize(&newBounds);
812
813 logger.console.prevBounds = logger.console.growBounds;
814
815 return 1;
816 }
817
818 pascal void DoLogScroll(ControlHandle ctl, short ctlEventIn)
819 {
820 int value = logger.console.scrollPos;
821 int orig = value;
822
823 (void) ctl; // unused
824
825 switch (ctlEventIn) {
826
827 case inUpButton:
828 value -= logger.console.lineHeight;
829 break;
830
831 case inDownButton:
832 value += logger.console.lineHeight;
833 break;
834
835 case inPageUp:
836 value -= logger.console.lineHeight * (logger.console.nbOutputLines - 1);
837 break;
838
839 case inPageDown:
840 value += logger.console.lineHeight * (logger.console.nbOutputLines - 1);
841 break;
842 }
843
844 // Clamp
845 //
846 if (value < 0) {
847 value = 0;
848 }
849 else if (value > logger.console.maxScrollPos) {
850 value = logger.console.maxScrollPos;
851 }
852
853 if (value != orig) {
854 logger.console.scrollPos = value;
855 SetCtlValue(logger.console.vScroll, logger.console.scrollPos);
856
857 TEScroll(0, -(value - orig), logger.console.textArea);
858
859 LogConsoleUpdate();
860 }
861 }
862
863 Boolean DoLogEvent(EventRecord event)
864 {
865 Boolean interceped = FALSE;
866
867 GrafPtr oldPort;
868 WindowPtr eventWin;
869 ControlHandle ctl;
870 int eventIn, ctlEventIn;
871 Point localPt;
872
873 if (logger.outputMethod != CONSOLE_OUT) {
874 return FALSE;
875 }
876
877 GetPort(&oldPort);
878 SetPort(logger.console.window);
879
880 localPt = event.where;
881 GlobalToLocal(&localPt);
882
883
884 switch (event.what) {
885
886 case nullEvent:
887 break;
888
889 case mouseDown:
890 eventIn = FindWindow(event.where, &eventWin);
891
892 if (eventWin != logger.console.window) {
893 interceped = FALSE;
894 break;
895 }
896
897 SelectWindow(eventWin);
898
899 switch (eventIn) {
900
901 case inContent:
902
903 ctlEventIn = FindControl(localPt, eventWin, &ctl);
904
905 if (PtInRect(localPt, &logger.console.closeBtn)) {
906 HideWindow(logger.console.window);
907 interceped = TRUE;
908 }
909 else if (PtInRect(localPt, &logger.console.lowerBtn)) {
910 Rect origBounds = logger.console.origBounds;
911
912 logger.console.prevBounds = logger.console.growBounds;
913 LogConsoleResize(&origBounds);
914 LogConsoleScrollToBottom();
915 }
916 else if (PtInRect(localPt, &logger.console.clearBtn)) {
917 LogConsoleClear();
918 }
919 else if (PtInRect(localPt, &logger.console.zoomBtn)) {
920 LogConsoleZoom();
921 LogConsoleScrollToBottom();
922 }
923 else if (PtInRect(localPt, &logger.console.titleBar)) {
924 DragWindow(eventWin, event.where, &screenBits.bounds);
925 InvalRect(&screenBits.bounds);
926 }
927 else if (PtInRect(localPt, &logger.console.growBtn)) {
928 DoLogGrow(event.where);
929 }
930 else if (ctl == logger.console.vScroll) {
931
932 if (ctlEventIn == inThumb) {
933 int ctlValue;
934 int delta;
935
936 // Dragging the thumb
937 //
938 TrackControl(ctl, localPt, NULL);
939
940 ctlValue = GetCtlValue(ctl);
941 delta = ctlValue - logger.console.scrollPos;
942
943 logger.console.scrollPos = ctlValue;
944
945 TEScroll(0, -delta, logger.console.textArea);
946
947 LogConsoleUpdate();
948
949 }
950 else {
951 // Buttons + page scroll
952 //
953 TrackControl(ctl, localPt, DoLogScroll);
954 }
955 }
956
957 interceped = TRUE;
958 break;
959 case inGrow:
960 logger.debug("In grow");
961 interceped = TRUE;
962 break;
963 case inGoAway:
964 if (TrackGoAway(eventWin, event.where)) {
965 HideWindow(logger.console.window);
966 interceped = TRUE;
967 }
968 break;
969 }
970 break;
971
972 case updateEvt:
973 eventWin = (WindowPtr)event.message;
974
975 if (eventWin && eventWin == logger.console.window) {
976 BeginUpdate(eventWin);
977
978 LogConsoleDraw();
979
980 EndUpdate(eventWin);
981 }
982 break;
983
984 case activateEvt:
985 break;
986 }
987
988 SetPort(oldPort);
989
990 return interceped;
991 }
992
993 void
994 LogSaveTextState(void)
995 {
996 logSavedTextState.font = thePort->txFont;
997 logSavedTextState.size = thePort->txSize;
998 logSavedTextState.mode = thePort->txMode;
999 logSavedTextState.face = thePort->txFace;
1000 }
1001
1002 void
1003 LogRestoreTextState(void)
1004 {
1005 TextFont(logSavedTextState.font);
1006 TextSize(logSavedTextState.size);
1007 TextMode(logSavedTextState.mode);
1008 TextFace(logSavedTextState.face);
1009 }
1010
1011 #endif