| 1 | 
      /* | 
    
    
      | 2 | 
       * Copyright (c) 2021-2022 joshua stein <jcs@jcs.org> | 
    
    
      | 3 | 
       * | 
    
    
      | 4 | 
       * Permission to use, copy, modify, and distribute this software for any | 
    
    
      | 5 | 
       * purpose with or without fee is hereby granted, provided that the above | 
    
    
      | 6 | 
       * copyright notice and this permission notice appear in all copies. | 
    
    
      | 7 | 
       * | 
    
    
      | 8 | 
       * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 
    
    
      | 9 | 
       * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 
    
    
      | 10 | 
       * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 
    
    
      | 11 | 
       * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 
    
    
      | 12 | 
       * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 
    
    
      | 13 | 
       * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 
    
    
      | 14 | 
       * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
    
    
      | 15 | 
       */ | 
    
    
      | 16 | 
       | 
    
    
      | 17 | 
      #include <string.h> | 
    
    
      | 18 | 
       | 
    
    
      | 19 | 
      #include "focusable.h" | 
    
    
      | 20 | 
      #include "util.h" | 
    
    
      | 21 | 
       | 
    
    
      | 22 | 
      struct focusable **focusables = NULL; | 
    
    
      | 23 | 
      short nfocusables = 0; | 
    
    
      | 24 | 
       | 
    
    
      | 25 | 
      struct focusable * | 
    
    
      | 26 | 
      focusable_find(GrafPtr win) | 
    
    
      | 27 | 
      { | 
    
    
      | 28 | 
      	short n; | 
    
    
      | 29 | 
      	 | 
    
    
      | 30 | 
      	for (n = 0; n < nfocusables; n++) { | 
    
    
      | 31 | 
      		if (focusables[n]->win == win) | 
    
    
      | 32 | 
      			return focusables[n]; | 
    
    
      | 33 | 
      	} | 
    
    
      | 34 | 
      	 | 
    
    
      | 35 | 
      	return NULL; | 
    
    
      | 36 | 
      } | 
    
    
      | 37 | 
       | 
    
    
      | 38 | 
      struct focusable * | 
    
    
      | 39 | 
      focusable_focused(void) | 
    
    
      | 40 | 
      { | 
    
    
      | 41 | 
      	if (nfocusables && focusables[0]->visible) | 
    
    
      | 42 | 
      		return focusables[0]; | 
    
    
      | 43 | 
      	 | 
    
    
      | 44 | 
      	return NULL; | 
    
    
      | 45 | 
      } | 
    
    
      | 46 | 
       | 
    
    
      | 47 | 
      void | 
    
    
      | 48 | 
      focusable_add(struct focusable *focusable) | 
    
    
      | 49 | 
      { | 
    
    
      | 50 | 
      	short n; | 
    
    
      | 51 | 
      	 | 
    
    
      | 52 | 
      	nfocusables++; | 
    
    
      | 53 | 
      	focusables = xreallocarray(focusables, sizeof(struct focusable *), | 
    
    
      | 54 | 
      	  nfocusables); | 
    
    
      | 55 | 
       | 
    
    
      | 56 | 
      	if (nfocusables > 1) | 
    
    
      | 57 | 
      		for (n = nfocusables - 1; n > 0; n--) | 
    
    
      | 58 | 
      			focusables[n] = focusables[n - 1]; | 
    
    
      | 59 | 
       | 
    
    
      | 60 | 
      	focusables[0] = focusable; | 
    
    
      | 61 | 
      	 | 
    
    
      | 62 | 
      	focusable_show(focusable); | 
    
    
      | 63 | 
      } | 
    
    
      | 64 | 
       | 
    
    
      | 65 | 
      bool | 
    
    
      | 66 | 
      focusable_show(struct focusable *focusable) | 
    
    
      | 67 | 
      { | 
    
    
      | 68 | 
      	struct focusable *last, *tmp; | 
    
    
      | 69 | 
      	short n; | 
    
    
      | 70 | 
      	 | 
    
    
      | 71 | 
      	if (nfocusables > 1 && focusables[0] != focusable) { | 
    
    
      | 72 | 
      		last = focusables[0]; | 
    
    
      | 73 | 
      		 | 
    
    
      | 74 | 
      		if (last->modal) | 
    
    
      | 75 | 
      			/* other focusables cannot steal focus from modals */ | 
    
    
      | 76 | 
      			return false; | 
    
    
      | 77 | 
      			 | 
    
    
      | 78 | 
      		focusables[0] = focusable; | 
    
    
      | 79 | 
      		for (n = 1; n < nfocusables; n++) { | 
    
    
      | 80 | 
      			tmp = focusables[n]; | 
    
    
      | 81 | 
      			focusables[n] = last; | 
    
    
      | 82 | 
      			last = tmp; | 
    
    
      | 83 | 
      			if (last == focusable) | 
    
    
      | 84 | 
      				break; | 
    
    
      | 85 | 
      		} | 
    
    
      | 86 | 
      	} | 
    
    
      | 87 | 
      	 | 
    
    
      | 88 | 
      	if (!focusable->visible) { | 
    
    
      | 89 | 
      		focusable->visible = true; | 
    
    
      | 90 | 
      		ShowWindow(focusable->win); | 
    
    
      | 91 | 
      	} | 
    
    
      | 92 | 
      	 | 
    
    
      | 93 | 
      	SelectWindow(focusable->win); | 
    
    
      | 94 | 
      	SetPort(focusable->win); | 
    
    
      | 95 | 
      	 | 
    
    
      | 96 | 
      	return true; | 
    
    
      | 97 | 
      } | 
    
    
      | 98 | 
       | 
    
    
      | 99 | 
      bool | 
    
    
      | 100 | 
      focusable_close(struct focusable *focusable) | 
    
    
      | 101 | 
      { | 
    
    
      | 102 | 
      	short n; | 
    
    
      | 103 | 
      	 | 
    
    
      | 104 | 
      	if (focusable->close) { | 
    
    
      | 105 | 
      		if (!focusable->close(focusable)) | 
    
    
      | 106 | 
      			return false; | 
    
    
      | 107 | 
      	} else | 
    
    
      | 108 | 
      		DisposeWindow(focusable->win); | 
    
    
      | 109 | 
      	 | 
    
    
      | 110 | 
      	for (n = 0; n < nfocusables; n++) { | 
    
    
      | 111 | 
      		if (focusables[n] == focusable) { | 
    
    
      | 112 | 
      			for (; n < nfocusables - 1; n++) | 
    
    
      | 113 | 
      				focusables[n] = focusables[n + 1]; | 
    
    
      | 114 | 
      			break; | 
    
    
      | 115 | 
      		} | 
    
    
      | 116 | 
      	} | 
    
    
      | 117 | 
       | 
    
    
      | 118 | 
      	nfocusables--; | 
    
    
      | 119 | 
      	if (nfocusables) | 
    
    
      | 120 | 
      		focusables = xreallocarray(focusables, sizeof(Ptr), nfocusables); | 
    
    
      | 121 | 
      	else { | 
    
    
      | 122 | 
      		free(focusables); | 
    
    
      | 123 | 
      		focusables = NULL; | 
    
    
      | 124 | 
      	} | 
    
    
      | 125 | 
      	 | 
    
    
      | 126 | 
      	if (nfocusables && focusables[0]->visible) | 
    
    
      | 127 | 
      		focusable_show(focusables[0]); | 
    
    
      | 128 | 
       | 
    
    
      | 129 | 
      	return true; | 
    
    
      | 130 | 
      } | 
    
    
      | 131 | 
       | 
    
    
      | 132 | 
      void | 
    
    
      | 133 | 
      focusable_hide(struct focusable *focusable) | 
    
    
      | 134 | 
      { | 
    
    
      | 135 | 
      	short n; | 
    
    
      | 136 | 
      	 | 
    
    
      | 137 | 
      	HideWindow(focusable->win); | 
    
    
      | 138 | 
      	focusable->visible = false; | 
    
    
      | 139 | 
      	 | 
    
    
      | 140 | 
      	for (n = 0; n < nfocusables; n++) { | 
    
    
      | 141 | 
      		if (focusables[n] == focusable) { | 
    
    
      | 142 | 
      			for (; n < nfocusables - 1; n++) | 
    
    
      | 143 | 
      				focusables[n] = focusables[n + 1]; | 
    
    
      | 144 | 
      			break; | 
    
    
      | 145 | 
      		} | 
    
    
      | 146 | 
      	} | 
    
    
      | 147 | 
      	focusables[nfocusables - 1] = focusable; | 
    
    
      | 148 | 
      } | 
    
    
      | 149 | 
       | 
    
    
      | 150 | 
      bool | 
    
    
      | 151 | 
      focusables_quit(void) | 
    
    
      | 152 | 
      { | 
    
    
      | 153 | 
      	short tnfocusables = nfocusables; | 
    
    
      | 154 | 
      	short n; | 
    
    
      | 155 | 
      	struct focusable **tfocusables; | 
    
    
      | 156 | 
      	bool quit = true; | 
    
    
      | 157 | 
      	 | 
    
    
      | 158 | 
      	if (nfocusables) { | 
    
    
      | 159 | 
      		/* | 
    
    
      | 160 | 
      		 * nfocusables and focusables array will probably be | 
    
    
      | 161 | 
      		 * modified as each focusable quits | 
    
    
      | 162 | 
      		 */ | 
    
    
      | 163 | 
      		tfocusables = xcalloc(sizeof(Ptr), tnfocusables); | 
    
    
      | 164 | 
      		if (tfocusables == NULL) | 
    
    
      | 165 | 
      			panic("Out of memory!"); | 
    
    
      | 166 | 
      		memcpy(tfocusables, focusables, sizeof(Ptr) * tnfocusables); | 
    
    
      | 167 | 
      	 | 
    
    
      | 168 | 
      		for (n = 0; n < tnfocusables; n++) { | 
    
    
      | 169 | 
      			if (tfocusables[n] && !focusable_close(tfocusables[n])) { | 
    
    
      | 170 | 
      				quit = false; | 
    
    
      | 171 | 
      				break; | 
    
    
      | 172 | 
      			} | 
    
    
      | 173 | 
      		} | 
    
    
      | 174 | 
      		 | 
    
    
      | 175 | 
      		free(tfocusables); | 
    
    
      | 176 | 
      	} | 
    
    
      | 177 | 
       | 
    
    
      | 178 | 
      	return quit; | 
    
    
      | 179 | 
      } | 
    
    
      | 180 | 
       | 
    
    
      | 181 | 
      void | 
    
    
      | 182 | 
      focusables_atexit(void) | 
    
    
      | 183 | 
      { | 
    
    
      | 184 | 
      	short n; | 
    
    
      | 185 | 
      	short tnfocusables = nfocusables; | 
    
    
      | 186 | 
      	struct focusable **tfocusables; | 
    
    
      | 187 | 
       | 
    
    
      | 188 | 
      	if (!nfocusables) | 
    
    
      | 189 | 
      		return; | 
    
    
      | 190 | 
      		 | 
    
    
      | 191 | 
      	tfocusables = xcalloc(sizeof(Ptr), tnfocusables); | 
    
    
      | 192 | 
      	if (tfocusables == NULL) | 
    
    
      | 193 | 
      		panic("Out of memory!"); | 
    
    
      | 194 | 
      	memcpy(tfocusables, focusables, sizeof(Ptr) * tnfocusables); | 
    
    
      | 195 | 
      	 | 
    
    
      | 196 | 
      	for (n = 0; n < tnfocusables; n++) { | 
    
    
      | 197 | 
      		if (tfocusables[n] && tfocusables[n]->atexit) | 
    
    
      | 198 | 
      			tfocusables[n]->atexit(tfocusables[n]); | 
    
    
      | 199 | 
      	} | 
    
    
      | 200 | 
      	 | 
    
    
      | 201 | 
      	free(tfocusables); | 
    
    
      | 202 | 
      } |