Internal.c 27 KB

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