Internal.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. /* Copyright Massachusetts Institute of Technology 1985 */
  2. #include "copyright.h"
  3. /*
  4. Copyright (C) 1993, 1996, 2001-2016 Free Software Foundation, Inc.
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or (at
  8. your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. /*
  16. * XMenu: MIT Project Athena, X Window system menu package
  17. *
  18. * XMenuInternal.c - XMenu internal (not user visible) routines.
  19. *
  20. * Author: Tony Della Fera, DEC
  21. * November, 1985
  22. *
  23. */
  24. #include "XMenuInt.h"
  25. /*
  26. * Internal Window creation queue sizes.
  27. */
  28. #define S_QUE_SIZE 300
  29. #define P_QUE_SIZE 20
  30. /*
  31. * XMWinQue - Internal window creation queue datatype.
  32. */
  33. typedef struct _xmwinquedef {
  34. int sq_size;
  35. XMSelect *sq[S_QUE_SIZE];
  36. XMSelect **sq_ptr;
  37. int pq_size;
  38. XMPane *pq[P_QUE_SIZE];
  39. XMPane **pq_ptr;
  40. } XMWinQue;
  41. /*
  42. * _XMWinQue - Internal static window creation queue.
  43. */
  44. static Bool _XMWinQueIsInit = False;
  45. static XMWinQue _XMWinQue;
  46. /*
  47. * _XMErrorCode - Global XMenu error code.
  48. */
  49. int _XMErrorCode = XME_NO_ERROR;
  50. /*
  51. * _XMErrorList - Global XMenu error code description strings.
  52. */
  53. char const *const
  54. _XMErrorList[XME_CODE_COUNT] = {
  55. "No error", /* XME_NO_ERROR */
  56. "Menu not initialized", /* XME_NOT_INIT */
  57. "Argument out of bounds", /* XME_ARG_BOUNDS */
  58. "Pane not found", /* XME_P_NOT_FOUND */
  59. "Selection not found", /* XME_S_NOT_FOUND */
  60. "Invalid menu style parameter", /* XME_STYLE_PARAM */
  61. "Unable to grab mouse", /* XME_GRAB_MOUSE */
  62. "Unable to interpret locator", /* XME_INTERP_LOC */
  63. "Unable to calloc memory", /* XME_CALLOC */
  64. "Unable to create XAssocTable", /* XME_CREATE_ASSOC */
  65. "Unable to store bitmap", /* XME_STORE_BITMAP */
  66. "Unable to make tile pixmaps", /* XME_MAKE_TILES */
  67. "Unable to make pixmap", /* XME_MAKE_PIXMAP */
  68. "Unable to create cursor", /* XME_CREATE_CURSOR */
  69. "Unable to open font", /* XME_OPEN_FONT */
  70. "Unable to create windows", /* XME_CREATE_WINDOW */
  71. "Unable to create transparencies", /* XME_CREATE_TRANSP */
  72. };
  73. /*
  74. * _XMEventHandler - Internal event handler variable.
  75. */
  76. int (*_XMEventHandler)(XEvent*) = NULL;
  77. /*
  78. * _XMWinQueInit - Internal routine to initialize the window
  79. * queue.
  80. */
  81. void
  82. _XMWinQueInit(void)
  83. {
  84. /*
  85. * If the queue is not initialized initialize it.
  86. */
  87. if (!_XMWinQueIsInit) {
  88. /*
  89. * Blank the queue structure.
  90. */
  91. register int i;
  92. for (i = 0; i < S_QUE_SIZE; i++)
  93. _XMWinQue.sq[i] = 0;
  94. for (i = 0; i < P_QUE_SIZE; i++)
  95. _XMWinQue.pq[i] = 0;
  96. _XMWinQue.sq_size = _XMWinQue.pq_size = 0;
  97. /*
  98. * Initialize the next free location pointers.
  99. */
  100. _XMWinQue.sq_ptr = _XMWinQue.sq;
  101. _XMWinQue.pq_ptr = _XMWinQue.pq;
  102. }
  103. }
  104. /*
  105. * _XMWinQueAddPane - Internal routine to add a pane to the pane
  106. * window queue.
  107. */
  108. int
  109. _XMWinQueAddPane(register Display *display, register XMenu *menu, register XMPane *p_ptr)
  110. /* Menu being manipulated. */
  111. /* XMPane being queued. */
  112. {
  113. /*
  114. * If the queue is currently full then flush it.
  115. */
  116. if (_XMWinQue.pq_size == P_QUE_SIZE) {
  117. if (_XMWinQueFlush(display, menu, 0, 0) == _FAILURE) return(_FAILURE);
  118. }
  119. /*
  120. * Insert the new XMPane pointer and increment the queue pointer
  121. * and the queue size.
  122. */
  123. *_XMWinQue.pq_ptr = p_ptr;
  124. _XMWinQue.pq_ptr++;
  125. _XMWinQue.pq_size++;
  126. /*
  127. * All went well, return successfully.
  128. */
  129. _XMErrorCode = XME_NO_ERROR;
  130. return(_SUCCESS);
  131. }
  132. /*
  133. * _XMWinQueAddSelection - Internal routine to add a selection to
  134. * the selection window queue.
  135. */
  136. int
  137. _XMWinQueAddSelection(register Display *display, register XMenu *menu, register XMSelect *s_ptr)
  138. /* Menu being manipulated. */
  139. /* XMSelection being queued. */
  140. {
  141. /*
  142. * If this entry will overflow the queue then flush it.
  143. */
  144. if (_XMWinQue.sq_size == S_QUE_SIZE) {
  145. if (_XMWinQueFlush(display, menu, 0, 0) == _FAILURE) return(_FAILURE);
  146. }
  147. /*
  148. * Insert the new XMSelect pointer and increment the queue pointer
  149. * and the queue size.
  150. */
  151. *_XMWinQue.sq_ptr = s_ptr;
  152. _XMWinQue.sq_ptr++;
  153. _XMWinQue.sq_size++;
  154. /*
  155. * All went well, return successfully.
  156. */
  157. _XMErrorCode = XME_NO_ERROR;
  158. return(_SUCCESS);
  159. }
  160. /*
  161. * _XMWinQueFlush - Internal routine to flush the pane and
  162. * selection window queues.
  163. */
  164. int
  165. _XMWinQueFlush(register Display *display, register XMenu *menu, register XMPane *pane, XMSelect *sel)
  166. /* Menu being manipulated. */
  167. /* Current pane. */
  168. {
  169. register int pq_index; /* Pane queue index. */
  170. register int sq_index; /* Selection queue index. */
  171. register XMPane *p_ptr; /* XMPane pointer. */
  172. register XMSelect *s_ptr; /* XMSelect pointer. */
  173. unsigned long valuemask; /* Which attributes to set. */
  174. XSetWindowAttributes attributes_buf; /* Attributes to be set. */
  175. XSetWindowAttributes *attributes = &attributes_buf;
  176. /*
  177. * If the pane window queue is not empty...
  178. */
  179. if (_XMWinQue.pq_size > 0) {
  180. /*
  181. * set up attributes for pane window to be created.
  182. */
  183. valuemask = (CWBackPixmap | CWBorderPixel | CWOverrideRedirect);
  184. attributes->border_pixel = menu->p_bdr_color;
  185. attributes->background_pixmap = menu->inact_pixmap;
  186. attributes->override_redirect = True;
  187. /*
  188. * Create all the pending panes in order, so that the
  189. * current pane will be on top, with the others
  190. * stacked appropriately under it.
  191. */
  192. for (pq_index = _XMWinQue.pq_size - 1;
  193. pq_index >= 0;
  194. pq_index--)
  195. {
  196. p_ptr = _XMWinQue.pq[pq_index]; /* Retrieve next pane. */
  197. if (p_ptr == pane) break;
  198. p_ptr->window = XCreateWindow(display,
  199. menu->parent,
  200. p_ptr->window_x,
  201. p_ptr->window_y,
  202. p_ptr->window_w,
  203. p_ptr->window_h,
  204. menu->p_bdr_width,
  205. CopyFromParent,
  206. InputOutput,
  207. CopyFromParent,
  208. valuemask,
  209. attributes);
  210. XMakeAssoc(display, menu->assoc_tab, p_ptr->window, p_ptr);
  211. XSelectInput(display, p_ptr->window, menu->p_events);
  212. }
  213. for (pq_index = 0;
  214. pq_index < _XMWinQue.pq_size;
  215. pq_index++)
  216. {
  217. p_ptr = _XMWinQue.pq[pq_index]; /* Retrieve next pane. */
  218. p_ptr->window = XCreateWindow(display,
  219. menu->parent,
  220. p_ptr->window_x,
  221. p_ptr->window_y,
  222. p_ptr->window_w,
  223. p_ptr->window_h,
  224. menu->p_bdr_width,
  225. CopyFromParent,
  226. InputOutput,
  227. CopyFromParent,
  228. valuemask,
  229. attributes);
  230. XMakeAssoc(display, menu->assoc_tab, p_ptr->window, p_ptr);
  231. XSelectInput(display, p_ptr->window, menu->p_events);
  232. if (p_ptr == pane) break;
  233. }
  234. /*
  235. * Reset the pane queue pointer and size.
  236. */
  237. _XMWinQue.pq_size = 0;
  238. _XMWinQue.pq_ptr = _XMWinQue.pq;
  239. }
  240. /*
  241. * If the selection window queue is not empty...
  242. */
  243. if (_XMWinQue.sq_size > 0) {
  244. for (sq_index = 0; sq_index < _XMWinQue.sq_size; sq_index++) {
  245. /*
  246. * Retrieve the XMSelect pointer.
  247. */
  248. s_ptr = _XMWinQue.sq[sq_index];
  249. s_ptr->window = XCreateWindow(display,
  250. s_ptr->parent_p->window,
  251. s_ptr->window_x,
  252. s_ptr->window_y,
  253. s_ptr->window_w,
  254. s_ptr->window_h,
  255. 0, /* border width*/
  256. CopyFromParent,
  257. InputOnly,
  258. CopyFromParent,
  259. 0,
  260. attributes);
  261. /*
  262. * Insert the new window id and its
  263. * associated XMSelect structure into the
  264. * association table.
  265. */
  266. XMakeAssoc(display, menu->assoc_tab, s_ptr->window, s_ptr);
  267. XSelectInput(display, s_ptr->window, menu->s_events);
  268. }
  269. /*
  270. * Reset the selection queue pointer and size.
  271. */
  272. _XMWinQue.sq_size = 0;
  273. _XMWinQue.sq_ptr = _XMWinQue.sq;
  274. }
  275. /*
  276. * Flush X's internal queues.
  277. */
  278. XFlush(display);
  279. /*
  280. * All went well, return successfully.
  281. */
  282. _XMErrorCode = XME_NO_ERROR;
  283. return(_SUCCESS);
  284. }
  285. /*
  286. * _XMGetPanePtr - Given a menu pointer and a pane index number, return
  287. * a pane pointer that points to the indexed pane.
  288. */
  289. XMPane *
  290. _XMGetPanePtr(register XMenu *menu, register int p_num)
  291. /* Menu to find the pane in. */
  292. /* Index number of pane to find. */
  293. {
  294. register XMPane *p_ptr; /* Pane pointer to be returned. */
  295. register int i; /* Loop counter. */
  296. /*
  297. * Is the pane number out of range?
  298. */
  299. if ((p_num < 0) || (p_num > (menu->p_count - 1))) {
  300. _XMErrorCode = XME_P_NOT_FOUND;
  301. return(NULL);
  302. }
  303. /*
  304. * Find the right pane.
  305. */
  306. p_ptr = menu->p_list->next;
  307. for (i = 0; i < p_num; i++) p_ptr = p_ptr->next;
  308. /*
  309. * Return successfully.
  310. */
  311. _XMErrorCode = XME_NO_ERROR;
  312. return(p_ptr);
  313. }
  314. /*
  315. * _XMGetSelectionPtr - Given pane pointer and a selection index number,
  316. * return a selection pointer that points to the
  317. * indexed selection.
  318. */
  319. XMSelect *
  320. _XMGetSelectionPtr(register XMPane *p_ptr, register int s_num)
  321. /* Pane to find the selection in. */
  322. /* Index number of the selection to find. */
  323. {
  324. register XMSelect *s_ptr; /* Selection pointer to be returned. */
  325. register int i; /* Loop counter. */
  326. /*
  327. * Is the selection number out of range?
  328. */
  329. if ((s_num < 0) || (s_num > (p_ptr->s_count - 1))) {
  330. _XMErrorCode = XME_S_NOT_FOUND;
  331. return(NULL);
  332. }
  333. /*
  334. * Find the right selection.
  335. */
  336. s_ptr = p_ptr->s_list->next;
  337. for (i = 0; i < s_num; i++) s_ptr = s_ptr->next;
  338. /*
  339. * Return successfully.
  340. */
  341. _XMErrorCode = XME_NO_ERROR;
  342. return(s_ptr);
  343. }
  344. /*
  345. * _XMRecomputeGlobals - Internal subroutine to recompute menu wide
  346. * global values.
  347. */
  348. void
  349. _XMRecomputeGlobals(register Display *display, register XMenu *menu)
  350. /*X11 display variable. */
  351. /* Menu object to compute from. */
  352. {
  353. register XMPane *p_ptr; /* Pane pointer. */
  354. register XMSelect *s_ptr; /* Selection pointer. */
  355. register int max_p_label = 0; /* Maximum pane label width. */
  356. register int max_s_label = 0; /* Maximum selection label width. */
  357. register int s_count = 0; /* Maximum selection count. */
  358. int p_s_pad; /* Pane <-> selection padding. */
  359. int p_s_diff; /* Pane <-> selection separation. */
  360. int p_height; /* Pane window height. */
  361. int p_width; /* Pane window width. */
  362. int s_width; /* Selection window width. */
  363. int screen; /* DefaultScreen holder. */
  364. /*
  365. * For each pane...
  366. */
  367. for (
  368. p_ptr = menu->p_list->next;
  369. p_ptr != menu->p_list;
  370. p_ptr = p_ptr->next
  371. ){
  372. /*
  373. * Recompute maximum pane label width.
  374. */
  375. max_p_label = max(max_p_label, p_ptr->label_width);
  376. /*
  377. * Recompute maximum selection count.
  378. */
  379. s_count = max(s_count, p_ptr->s_count);
  380. /*
  381. * For each selection in the current pane...
  382. */
  383. for (
  384. s_ptr = p_ptr->s_list->next;
  385. s_ptr != p_ptr->s_list;
  386. s_ptr = s_ptr->next
  387. ){
  388. /*
  389. * Recompute maximum selection label width.
  390. */
  391. max_s_label = max(max_s_label, s_ptr->label_width);
  392. }
  393. }
  394. /*
  395. * Recompute pane height.
  396. */
  397. p_height = (menu->flag_height << 1) + (menu->s_y_off * s_count);
  398. /*
  399. * Recompute horizontal padding between the pane window and the
  400. * selection windows.
  401. */
  402. p_s_pad = menu->p_x_off << 1;
  403. /*
  404. * Recompute pane and selection window widths.
  405. * This is done by first computing the window sizes from the maximum
  406. * label widths. If the spacing between the selection window and the
  407. * containing pane window is less than the pane selection padding value
  408. * (twice the pane X offset) then change the size of the pane to be
  409. * the size of the selection window plus the padding. If, however the
  410. * spacing between the selection window and the containing pane window
  411. * is more than the pane selection padding value increase the size of
  412. * the selection to its maximum possible value (the pane width minus
  413. * the pane selection padding value).
  414. */
  415. p_width = max_p_label + p_s_pad;
  416. s_width = max_s_label + (menu->s_fnt_pad << 1) + (menu->s_bdr_width << 1);
  417. p_s_diff = p_width - s_width;
  418. if (p_s_diff < p_s_pad) {
  419. p_width = s_width + p_s_pad;
  420. }
  421. else if (p_s_diff > p_s_pad) {
  422. s_width = p_width - p_s_pad;
  423. }
  424. /*
  425. * Reset menu wide global values.
  426. */
  427. menu->s_count = s_count;
  428. menu->p_height = p_height;
  429. menu->p_width = p_width;
  430. menu->s_width = s_width;
  431. /*
  432. * Ensure that the origin of the menu is placed so that
  433. * None of the panes ore selections are off the screen.
  434. */
  435. screen = DefaultScreen(display);
  436. if (menu->x_pos + menu->width > DisplayWidth(display, screen))
  437. menu->x_pos = DisplayWidth(display, screen) - menu->width;
  438. else if (menu->x_pos < 0) menu->x_pos = 0;
  439. if(menu->y_pos + menu->height > DisplayHeight(display, screen))
  440. menu->y_pos = DisplayHeight(display, screen) - menu->height;
  441. else if (menu->y_pos < 0) menu->y_pos = 0;
  442. }
  443. /*
  444. * _XMRecomputePane - Internal subroutine to recompute pane
  445. * window dependencies.
  446. */
  447. int
  448. _XMRecomputePane(register Display *display, register XMenu *menu, register XMPane *p_ptr, register int p_num)
  449. /* Standard X display variable. */
  450. /* Menu object being recomputed. */
  451. /* Pane pointer. */
  452. /* Pane sequence number. */
  453. {
  454. register int window_x; /* Recomputed window X coordinate. */
  455. register int window_y; /* Recomputed window Y coordinate. */
  456. unsigned long change_mask; /* Value mask to reconfigure window. */
  457. XWindowChanges *changes; /* Values to use in configure window. */
  458. register Bool config_p = False; /* Reconfigure pane window? */
  459. /*
  460. * Update the pane serial number.
  461. */
  462. p_ptr->serial = p_num;
  463. /*
  464. * Recompute window X and Y coordinates.
  465. */
  466. switch (menu->menu_style) {
  467. case LEFT:
  468. window_x = menu->p_x_off * ((menu->p_count - 1) - p_num);
  469. window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
  470. break;
  471. case RIGHT:
  472. window_x = menu->p_x_off * p_num;
  473. window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
  474. break;
  475. case CENTER:
  476. window_x = 0;
  477. window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
  478. break;
  479. default:
  480. /* Error! Invalid style parameter. */
  481. _XMErrorCode = XME_STYLE_PARAM;
  482. return(_FAILURE);
  483. }
  484. window_x += menu->x_pos;
  485. window_y += menu->y_pos;
  486. /*
  487. * If the newly compute pane coordinates differ from the
  488. * current coordinates, reset the current coordinates and
  489. * reconfigure the pane.
  490. */
  491. if (
  492. (window_x != p_ptr->window_x) ||
  493. (window_y != p_ptr->window_y)
  494. ){
  495. /*
  496. * Reset the coordinates and schedule
  497. * the pane for reconfiguration.
  498. */
  499. p_ptr->window_x = window_x;
  500. p_ptr->window_y = window_y;
  501. config_p = True;
  502. }
  503. /*
  504. * If the local pane width and height differs from the
  505. * menu pane width and height, reset the local values.
  506. */
  507. if (
  508. (p_ptr->window_w != menu->p_width) ||
  509. (p_ptr->window_h != menu->p_height)
  510. ){
  511. /*
  512. * Reset window width and height and schedule
  513. * the pane for reconfiguration.
  514. */
  515. p_ptr->window_w = menu->p_width;
  516. p_ptr->window_h = menu->p_height;
  517. config_p = True;
  518. }
  519. /*
  520. * If we need to reconfigure the pane window do it now.
  521. */
  522. if (config_p == True) {
  523. /*
  524. * If the pane window has already been created then
  525. * reconfigure the existing window, otherwise queue
  526. * it for creation with the new configuration.
  527. */
  528. if (p_ptr->window) {
  529. change_mask = (CWX | CWY | CWWidth | CWHeight);
  530. changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
  531. changes->x = p_ptr->window_x;
  532. changes->y = p_ptr->window_y;
  533. changes->width = p_ptr->window_w;
  534. changes->height = p_ptr->window_h;
  535. XConfigureWindow(
  536. display,
  537. p_ptr->window,
  538. change_mask,
  539. changes
  540. );
  541. free(changes);
  542. }
  543. else {
  544. if (_XMWinQueAddPane(display, menu, p_ptr) == _FAILURE) {
  545. return(_FAILURE);
  546. }
  547. }
  548. }
  549. /*
  550. * Recompute label X position.
  551. */
  552. switch (menu->p_style) {
  553. case LEFT:
  554. p_ptr->label_x = menu->p_x_off + menu->p_fnt_pad;
  555. break;
  556. case RIGHT:
  557. p_ptr->label_x = menu->p_width -
  558. (p_ptr->label_width + menu->p_x_off + menu->p_fnt_pad);
  559. break;
  560. case CENTER:
  561. p_ptr->label_x = (menu->p_width - p_ptr->label_width) >> 1;
  562. break;
  563. default:
  564. /* Error! Invalid style parameter. */
  565. _XMErrorCode = XME_STYLE_PARAM;
  566. return(_FAILURE);
  567. }
  568. /*
  569. * Recompute label Y positions.
  570. */
  571. p_ptr->label_uy = menu->p_fnt_pad + menu->p_fnt_info->max_bounds.ascent;
  572. p_ptr->label_ly = (menu->p_height - menu->p_fnt_pad - menu->p_fnt_info->max_bounds.descent);
  573. /*
  574. * All went well, return successfully.
  575. */
  576. _XMErrorCode = XME_NO_ERROR;
  577. return(_SUCCESS);
  578. }
  579. /*
  580. * _XMRecomputeSelection - Internal subroutine to recompute
  581. * selection window dependencies.
  582. */
  583. int
  584. _XMRecomputeSelection(register Display *display, register XMenu *menu, register XMSelect *s_ptr, register int s_num)
  585. /* Menu object being recomputed. */
  586. /* Selection pointer. */
  587. /* Selection sequence number. */
  588. {
  589. register Bool config_s = False; /* Reconfigure selection window? */
  590. XWindowChanges *changes; /* Values to change in configure. */
  591. unsigned long change_mask; /* Value mask for XConfigureWindow. */
  592. /*
  593. * If the selection serial numbers are out of order, begin
  594. * resequencing selections. Recompute selection window coordinates
  595. * and serial number.
  596. *
  597. * When selections are created they are given a serial number of
  598. * -1, this causes this routine to give a new selection
  599. * its initial coordinates and serial number.
  600. */
  601. if (s_ptr->serial != s_num) {
  602. /*
  603. * Fix the sequence number.
  604. */
  605. s_ptr->serial = s_num;
  606. /*
  607. * Recompute window X and Y coordinates.
  608. */
  609. s_ptr->window_x = menu->s_x_off;
  610. s_ptr->window_y = menu->flag_height + (menu->s_y_off * s_num);
  611. /*
  612. * We must reconfigure the window.
  613. */
  614. config_s = True;
  615. }
  616. /*
  617. * If the local selection width and height differs from the
  618. * menu selection width and height, reset the local values.
  619. */
  620. if (
  621. (s_ptr->window_w != menu->s_width) ||
  622. (s_ptr->window_h != menu->s_height)
  623. ){
  624. /*
  625. * We must reconfigure the window.
  626. */
  627. config_s = True;
  628. /*
  629. * Reset window width and height.
  630. */
  631. s_ptr->window_w = menu->s_width;
  632. s_ptr->window_h = menu->s_height;
  633. }
  634. /*
  635. * If we need to reconfigure the selection window do it now.
  636. */
  637. if (config_s == True) {
  638. /*
  639. * If the selection window has already been created then
  640. * reconfigure the existing window, otherwise queue it
  641. * for creation with the new configuration.
  642. */
  643. if (s_ptr->window) {
  644. changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
  645. change_mask = (CWX | CWY | CWWidth | CWHeight);
  646. changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
  647. changes->x = s_ptr->window_x;
  648. changes->y = s_ptr->window_y;
  649. changes->width = s_ptr->window_w;
  650. changes->height = s_ptr->window_h;
  651. XConfigureWindow(
  652. display,
  653. s_ptr->window,
  654. change_mask,
  655. changes
  656. );
  657. free(changes);
  658. }
  659. else {
  660. if (_XMWinQueAddSelection(display, menu, s_ptr) == _FAILURE) {
  661. return(_FAILURE);
  662. }
  663. }
  664. }
  665. /*
  666. * Recompute label X position.
  667. */
  668. switch (menu->s_style) {
  669. case LEFT:
  670. s_ptr->label_x = menu->s_bdr_width + menu->s_fnt_pad + s_ptr->window_x;
  671. break;
  672. case RIGHT:
  673. s_ptr->label_x = s_ptr->window_x + menu->s_width -
  674. (s_ptr->label_width + menu->s_bdr_width + menu->s_fnt_pad);
  675. break;
  676. case CENTER:
  677. s_ptr->label_x = s_ptr->window_x + ((menu->s_width - s_ptr->label_width) >> 1);
  678. break;
  679. default:
  680. /* Error! Invalid style parameter. */
  681. _XMErrorCode = XME_STYLE_PARAM;
  682. return(_FAILURE);
  683. }
  684. /*
  685. * Recompute label Y position.
  686. */
  687. s_ptr->label_y = s_ptr->window_y + menu->s_fnt_info->max_bounds.ascent + menu->s_fnt_pad + menu->s_bdr_width;
  688. /*
  689. * All went well, return successfully.
  690. */
  691. _XMErrorCode = XME_NO_ERROR;
  692. return(_SUCCESS);
  693. }
  694. /*
  695. * _XMTransToOrigin - Internal subroutine to translate the point at
  696. * the center of the current pane and selection to the
  697. * the menu origin.
  698. *
  699. * WARNING! ****** Be certain that all menu dependencies have been
  700. * recomputed before calling this routine or
  701. * unpredictable results will follow.
  702. */
  703. void
  704. _XMTransToOrigin(Display *display, register XMenu *menu, register XMPane *p_ptr, register XMSelect *s_ptr, int x_pos, int y_pos, int *orig_x, int *orig_y)
  705. /* Not used. Included for consistency. */
  706. /* Menu being computed against. */
  707. /* Current pane pointer. */
  708. /* Current selection pointer. */
  709. /* X coordinate of point to translate. */
  710. /* Y coordinate of point to translate. */
  711. /* Return value X coord. of the menu origin. */
  712. /* Return value Y coord. of the menu origin. */
  713. {
  714. register int l_orig_x; /* Local X coordinate of the menu origin. */
  715. register int l_orig_y; /* Local Y coordinate of the menu origin. */
  716. /*
  717. * Translate the menu origin such that the cursor hot point will be in the
  718. * center of the desired current selection and pane.
  719. * If the current selection pointer is NULL then assume that the hot point
  720. * will be in the center of the current pane flag.
  721. */
  722. if (s_ptr == NULL) {
  723. /*
  724. * Translate from the center of the pane flag to the upper left
  725. * of the current pane window.
  726. */
  727. l_orig_x = x_pos - (menu->p_width >> 1) - menu->p_bdr_width;
  728. l_orig_y = y_pos - (menu->flag_height >> 1) - menu->p_bdr_width;
  729. }
  730. else {
  731. /*
  732. * First translate from the center of the current selection
  733. * to the upper left of the current selection window.
  734. */
  735. l_orig_x = x_pos - (menu->s_width >> 1);
  736. l_orig_y = y_pos - (menu->s_height >> 1);
  737. /*
  738. * Then translate to the upper left of the current pane window.
  739. */
  740. l_orig_x -= (s_ptr->window_x + menu->p_bdr_width);
  741. l_orig_y -= (s_ptr->window_y + menu->p_bdr_width);
  742. }
  743. /*
  744. * Finally translate to the upper left of the menu.
  745. */
  746. l_orig_x -= (p_ptr->window_x - menu->x_pos);
  747. l_orig_y -= (p_ptr->window_y - menu->y_pos);
  748. /*
  749. * Set the return values.
  750. */
  751. *orig_x = l_orig_x;
  752. *orig_y = l_orig_y;
  753. }
  754. /*
  755. * _XMRefreshPane - Internal subroutine to completely refresh
  756. * the contents of a pane.
  757. */
  758. void
  759. _XMRefreshPane(register Display *display, register XMenu *menu, register XMPane *pane)
  760. {
  761. register XMSelect *s_list = pane->s_list;
  762. register XMSelect *s_ptr;
  763. /*
  764. * First clear the pane.
  765. */
  766. XClearWindow(display, pane->window);
  767. if (!pane->activated) {
  768. XFillRectangle(display,
  769. pane->window,
  770. menu->inverse_select_GC,
  771. pane->label_x - menu->p_fnt_pad,
  772. pane->label_uy - menu->p_fnt_info->max_bounds.ascent - menu->p_fnt_pad,
  773. pane->label_width + (menu->p_fnt_pad << 1),
  774. menu->flag_height);
  775. XFillRectangle(display,
  776. pane->window,
  777. menu->inverse_select_GC,
  778. pane->label_x - menu->p_fnt_pad,
  779. pane->label_ly - menu->p_fnt_info->max_bounds.ascent - menu->p_fnt_pad,
  780. pane->label_width + (menu->p_fnt_pad << 1),
  781. menu->flag_height);
  782. }
  783. if (!pane->active) {
  784. XDrawString(display,
  785. pane->window,
  786. menu->inact_GC,
  787. pane->label_x, pane->label_uy,
  788. pane->label, pane->label_length);
  789. XDrawString(display,
  790. pane->window,
  791. menu->inact_GC,
  792. pane->label_x, pane->label_ly,
  793. pane->label, pane->label_length);
  794. }
  795. else {
  796. XDrawString(display,
  797. pane->window,
  798. menu->pane_GC,
  799. pane->label_x, pane->label_uy,
  800. pane->label, pane->label_length);
  801. XDrawString(display,
  802. pane->window,
  803. menu->pane_GC,
  804. pane->label_x, pane->label_ly,
  805. pane->label, pane->label_length);
  806. /*
  807. * Finally refresh each selection if the pane is activated.
  808. */
  809. if (pane->activated) {
  810. for (s_ptr = s_list->next; s_ptr != s_list; s_ptr = s_ptr->next)
  811. _XMRefreshSelection(display, menu, s_ptr);
  812. }
  813. }
  814. }
  815. /*
  816. * _XMRefreshSelection - Internal subroutine that refreshes
  817. * a single selection window.
  818. */
  819. void
  820. _XMRefreshSelection(register Display *display, register XMenu *menu, register XMSelect *sel)
  821. {
  822. register int width = sel->window_w;
  823. register int height = sel->window_h;
  824. register int bdr_width = menu->s_bdr_width;
  825. if (sel->type == SEPARATOR) {
  826. XDrawLine(display,
  827. sel->parent_p->window,
  828. menu->normal_select_GC,
  829. sel->window_x,
  830. sel->window_y + height / 2,
  831. sel->window_x + width,
  832. sel->window_y + height / 2);
  833. }
  834. else if (sel->activated) {
  835. if (menu->menu_mode == INVERT) {
  836. XFillRectangle(display,
  837. sel->parent_p->window,
  838. menu->normal_select_GC,
  839. sel->window_x, sel->window_y,
  840. width, height);
  841. XDrawString(display,
  842. sel->parent_p->window,
  843. menu->inverse_select_GC,
  844. sel->label_x,
  845. sel->label_y,
  846. sel->label, sel->label_length);
  847. }
  848. else {
  849. /*
  850. * Using BOX mode.
  851. * Since most drawing routines with arbitrary width lines
  852. * are slow compared to raster-ops let's use a raster-op to
  853. * draw the boxes.
  854. */
  855. XDrawRectangle(display,
  856. sel->parent_p->window,
  857. menu->normal_select_GC,
  858. sel->window_x + (bdr_width >> 1),
  859. sel->window_y + (bdr_width >> 1 ),
  860. width - bdr_width,
  861. height - bdr_width);
  862. XDrawString(display,
  863. sel->parent_p->window,
  864. menu->normal_select_GC,
  865. sel->label_x,
  866. sel->label_y,
  867. sel->label, sel->label_length);
  868. }
  869. }
  870. else {
  871. XClearArea(display,
  872. sel->parent_p->window,
  873. sel->window_x, sel->window_y,
  874. width, height,
  875. False);
  876. if (sel->active) {
  877. XDrawString(display,
  878. sel->parent_p->window,
  879. menu->normal_select_GC,
  880. sel->label_x,
  881. sel->label_y,
  882. sel->label, sel->label_length);
  883. }
  884. else {
  885. XDrawString(display,
  886. sel->parent_p->window,
  887. menu->inact_GC,
  888. sel->label_x,
  889. sel->label_y,
  890. sel->label, sel->label_length);
  891. }
  892. }
  893. }