Internal.c 27 KB

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