WmKeyFocus.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*
  24. * (c) Copyright 1989, 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC.
  25. * ALL RIGHTS RESERVED
  26. */
  27. /*
  28. * Motif Release 1.2.3
  29. */
  30. /*
  31. * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
  32. /*
  33. * Included Files:
  34. */
  35. #include "WmGlobal.h"
  36. /*
  37. * include extern functions
  38. */
  39. #include "WmKeyFocus.h"
  40. #include "WmCDecor.h"
  41. #include "WmColormap.h"
  42. #include "WmEvent.h"
  43. #include "WmCEvent.h"
  44. #include "WmFunction.h"
  45. #include "WmIDecor.h"
  46. #include "WmProtocol.h"
  47. #include "WmWinInfo.h"
  48. #include "WmWinList.h"
  49. /*
  50. * Global Variables:
  51. */
  52. static Boolean removeSelectGrab = True;
  53. /*************************************<->*************************************
  54. *
  55. * InitKeyboardFocus ()
  56. *
  57. *
  58. * Description:
  59. * -----------
  60. * This function sets the keyboard input focus to a client window or icon
  61. * when the window manager starts up.
  62. *
  63. *
  64. * Inputs:
  65. * ------
  66. * wmGD = (keyboardFocusPolicy, colormapFocusPolicy)
  67. *
  68. *************************************<->***********************************/
  69. void InitKeyboardFocus (void)
  70. {
  71. ClientData *pCD;
  72. Boolean sameScreen;
  73. Boolean focusSet = False;
  74. int scr;
  75. int junk;
  76. Window junk_win, root_returned;
  77. int currentX, currentY;
  78. /*
  79. * Set the keyboard focus based on the keyboard focus policy.
  80. */
  81. wmGD.keyboardFocus = NULL;
  82. wmGD.nextKeyboardFocus = NULL;
  83. for (scr = 0; scr < wmGD.numScreens; scr++)
  84. {
  85. if (wmGD.Screens[scr].managed)
  86. {
  87. wmGD.Screens[scr].focusPriority = 0;
  88. if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
  89. {
  90. /*
  91. * Set the keyboard focus to the window that
  92. * currently contains the pointer.
  93. */
  94. pCD = GetClientUnderPointer (&sameScreen);
  95. if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
  96. {
  97. /*
  98. * Do some colormap installation that has been
  99. * deferred from the InitColormapFocus routine.
  100. */
  101. SetColormapFocus (ACTIVE_PSD, pCD);
  102. }
  103. if (pCD)
  104. {
  105. Do_Focus_Key (pCD, GetTimestamp (), ALWAYS_SET_FOCUS);
  106. focusSet = True;
  107. }
  108. }
  109. else
  110. {
  111. ButtonSpec *buttonSpec;
  112. /*
  113. * Prepare to do explicit selection button grabs.
  114. */
  115. buttonSpec = wmGD.Screens[scr].buttonSpecs;
  116. while (buttonSpec)
  117. {
  118. if ((buttonSpec->button == FOCUS_SELECT_BUTTON) &&
  119. (buttonSpec->context & F_CONTEXT_WINDOW) &&
  120. (buttonSpec->subContext & F_SUBCONTEXT_W_CLIENT))
  121. {
  122. if (buttonSpec->state == 0)
  123. {
  124. removeSelectGrab = False;
  125. }
  126. }
  127. buttonSpec = buttonSpec->nextButtonSpec;
  128. }
  129. }
  130. }
  131. }
  132. if (!focusSet)
  133. {
  134. /*
  135. * This is keyboard focus policy is either "explicit" or it it
  136. * "pointer"
  137. * and there is no window under the pointer. No window currently has
  138. * the keyboard input focus. Set the keyboard focus to the window
  139. * manager default (non-client) OR to the last client with focus.
  140. *
  141. * In Mwm 1.1.4 and later, calling Do_Focus_Key with NULL will try
  142. * to find a 'reasonable' window to put focus. This means that on
  143. * startup and restarts, a Mwm window will have focus! Yeah!
  144. */
  145. /*
  146. * Set Active Screen First
  147. */
  148. if (XQueryPointer(DISPLAY, DefaultRootWindow(DISPLAY),
  149. &root_returned, &junk_win,
  150. &currentX, &currentY,
  151. &junk, &junk, (unsigned int *)&junk))
  152. {
  153. for (scr = 0; scr < wmGD.numScreens; scr++)
  154. {
  155. if (wmGD.Screens[scr].managed &&
  156. wmGD.Screens[scr].rootWindow == root_returned)
  157. {
  158. SetActiveScreen(&(wmGD.Screens[scr]));
  159. break;
  160. }
  161. }
  162. }
  163. Do_Focus_Key ((ClientData *)NULL, CurrentTime, ALWAYS_SET_FOCUS);
  164. }
  165. } /* END OF FUNCTION InitKeyboardFocus */
  166. /*************************************<->*************************************
  167. *
  168. * SetKeyboardFocus (pCD, focusFlags)
  169. *
  170. *
  171. * Description:
  172. * -----------
  173. * This function is used to handle a client window getting the input
  174. * focus (as the RESULT of an XSetInput call - probably done by
  175. * Do_Focus_Key).
  176. *
  177. *
  178. * Inputs:
  179. * ------
  180. * pCD = pointer to client data for window that is to get the focus
  181. *
  182. * focusFlags = flags that indicate focus change details
  183. * {REFRESH_LAST_FOCUS}
  184. *
  185. *
  186. * Outputs:
  187. * -------
  188. * wmGD = (keyboardFocus)
  189. *
  190. *************************************<->***********************************/
  191. void SetKeyboardFocus (ClientData *pCD, long focusFlags)
  192. {
  193. ClientData *currentFocus;
  194. /*
  195. * Don't set the keyboard input focus if it is already set to
  196. * the client window.
  197. */
  198. if (wmGD.keyboardFocus == pCD)
  199. {
  200. return;
  201. }
  202. currentFocus = wmGD.keyboardFocus;
  203. ACTIVE_PSD->focusPriority++;
  204. /*
  205. * If the keyboard input focus policy is "explicit" then reset the
  206. * selection button event handling.
  207. */
  208. if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
  209. {
  210. /*
  211. * Reset explicit focus selection event tracking on the last focus
  212. * window (reset the passive grab on the focus button).
  213. */
  214. if (currentFocus)
  215. {
  216. ResetExplicitSelectHandling (currentFocus);
  217. wmGD.keyboardFocus = NULL;
  218. }
  219. if (pCD && ((pCD->clientState == NORMAL_STATE) ||
  220. (pCD->clientState == MAXIMIZED_STATE)))
  221. {
  222. /*
  223. * The focus is to be set to a client window (not the root).
  224. * Stop explicit focus selection event tracking on the new focus
  225. * window.
  226. */
  227. if (removeSelectGrab)
  228. {
  229. WmUngrabButton (DISPLAY, FOCUS_SELECT_BUTTON, 0,
  230. pCD->clientBaseWin);
  231. }
  232. }
  233. }
  234. wmGD.keyboardFocus = pCD;
  235. /*
  236. * Do focus auto raise if specified.
  237. */
  238. if (pCD && pCD->focusAutoRaise)
  239. {
  240. if (wmGD.autoRaiseDelay &&
  241. (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER))
  242. {
  243. AddWmTimer (TIMER_RAISE, (unsigned long)wmGD.autoRaiseDelay,
  244. pCD);
  245. }
  246. else
  247. {
  248. Boolean sameScreen;
  249. if (((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
  250. (!pCD->focusAutoRaiseDisabled)) ||
  251. ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) &&
  252. (pCD == GetClientUnderPointer (&sameScreen))))
  253. {
  254. Do_Raise (pCD, (ClientListEntry *)NULL, STACK_NORMAL);
  255. }
  256. }
  257. }
  258. /*
  259. * Clear the focus indication if it is set for a client window or icon.
  260. */
  261. if (currentFocus)
  262. {
  263. ClearFocusIndication (currentFocus,
  264. ((focusFlags & REFRESH_LAST_FOCUS) ? True : False));
  265. }
  266. /*
  267. * Install the client window colormap if the colormap focus policy is
  268. * "keyboard".
  269. */
  270. if ((wmGD.colormapFocusPolicy == CMAP_FOCUS_KEYBOARD) &&
  271. (!(focusFlags & SCREEN_SWITCH_FOCUS)))
  272. {
  273. SetColormapFocus (ACTIVE_PSD, pCD);
  274. }
  275. /*
  276. * Set the focus window or icon visual indication.
  277. */
  278. if (pCD)
  279. {
  280. pCD->focusPriority = ACTIVE_PSD->focusPriority;
  281. SetFocusIndication (pCD);
  282. }
  283. } /* END OF FUNCTION SetKeyboardFocus */
  284. /*************************************<->*************************************
  285. *
  286. * ResetExplicitSelectHandling (pCD)
  287. *
  288. *
  289. * Description:
  290. * -----------
  291. * This function resets the selection button event handling for a client
  292. * window or icon. This applies only if the keyboard focus policy is
  293. * "explicit".
  294. *
  295. *
  296. * Inputs:
  297. * ------
  298. * pCD = pointer to client data for window that has focus handling reset
  299. *
  300. *************************************<->***********************************/
  301. void ResetExplicitSelectHandling (ClientData *pCD)
  302. {
  303. Boolean bUnseen;
  304. bUnseen = (pCD->clientState & UNSEEN_STATE) ? True : False;
  305. if (bUnseen)
  306. pCD->clientState &= ~UNSEEN_STATE;
  307. if ((pCD->clientState == NORMAL_STATE) ||
  308. (pCD->clientState == MAXIMIZED_STATE))
  309. {
  310. /*
  311. * A client window was selected.
  312. */
  313. DoExplicitSelectGrab (pCD->clientBaseWin);
  314. }
  315. else if (pCD->clientState == MINIMIZED_STATE)
  316. {
  317. /*
  318. * An icon was selected.
  319. */
  320. /* !!! grab reset if client icon window? !!! */
  321. }
  322. if (bUnseen)
  323. pCD->clientState |= UNSEEN_STATE;
  324. } /* END OF FUNCTION ResetExplicitSelectHandling */
  325. /*************************************<->*************************************
  326. *
  327. * DoExplicitSelectGrab (window)
  328. *
  329. *
  330. * Description:
  331. * -----------
  332. * This function is used to do a grab button on the specified window. The
  333. * grab is intended to catch the keyboard focus select button.
  334. *
  335. *
  336. * Inputs:
  337. * ------
  338. * widow = grab widow for the select button
  339. *
  340. *************************************<->***********************************/
  341. void DoExplicitSelectGrab (Window window)
  342. {
  343. WmGrabButton (DISPLAY, FOCUS_SELECT_BUTTON, 0, window,
  344. False, ButtonReleaseMask, GrabModeSync, GrabModeSync, None,
  345. None);
  346. } /* END OF FUNCTION DoExplicitSelectGrab */
  347. /*************************************<->*************************************
  348. *
  349. * SetFocusIndication (pCD)
  350. *
  351. *
  352. * Description:
  353. * -----------
  354. * This function changes the client window or icon decoration to have it
  355. * indicate that the window or icon has the keyboard input focus.
  356. *
  357. *
  358. * Inputs:
  359. * ------
  360. * pCD = pointer to client data for window/icon that is getting the focus
  361. *
  362. *
  363. *************************************<->***********************************/
  364. void SetFocusIndication (ClientData *pCD)
  365. {
  366. ClientData *saveCD;
  367. /*
  368. * Set the "focus" to pCD to insure correct display of the frame
  369. * This is necessary because the called routines get GCs based
  370. * on the current keyboard focus.
  371. */
  372. saveCD = wmGD.keyboardFocus;
  373. wmGD.keyboardFocus = pCD;
  374. if ((pCD->clientState == NORMAL_STATE) ||
  375. (pCD->clientState == MAXIMIZED_STATE))
  376. {
  377. /*
  378. * A client window has the input focus.
  379. */
  380. ShowActiveClientFrame (pCD);
  381. }
  382. else if (pCD->clientState == MINIMIZED_STATE)
  383. {
  384. /*
  385. * An icon has the input focus.
  386. */
  387. ShowActiveIcon (pCD);
  388. }
  389. /* restore old keyboard focus */
  390. wmGD.keyboardFocus = saveCD;
  391. } /* END OF FUNCTION SetFocusIndication */
  392. /*************************************<->*************************************
  393. *
  394. * ClearFocusIndication (pCD, refresh)
  395. *
  396. *
  397. * Description:
  398. * -----------
  399. * This function changes the client window or icon decoration to have it
  400. * indicate that the window or icon does not have the keyboard input focus
  401. * (i.e. it is inactive).
  402. *
  403. *
  404. * Inputs:
  405. * ------
  406. * pCD = pointer to client data for window/icon that is losing the focus
  407. *
  408. * refresh = True if window/icon frame is to redrawn
  409. *
  410. *************************************<->***********************************/
  411. void ClearFocusIndication (ClientData *pCD, Boolean refresh)
  412. {
  413. ClientData *saveCD;
  414. Boolean bUnseen;
  415. /*
  416. * Set the "focus" to NULL to insure correct display of the frame
  417. * This is necessary because the called routines get GCs based
  418. * on the current keyboard focus.
  419. */
  420. saveCD = wmGD.keyboardFocus;
  421. wmGD.keyboardFocus = NULL;
  422. bUnseen = (pCD->clientState & UNSEEN_STATE) ? True : False;
  423. if (bUnseen)
  424. pCD->clientState &= ~UNSEEN_STATE;
  425. if ((pCD->clientState == NORMAL_STATE) ||
  426. (pCD->clientState == MAXIMIZED_STATE))
  427. {
  428. /*
  429. * A client window no longer has the input focus.
  430. */
  431. ShowInactiveClientFrame (pCD);
  432. }
  433. else if (pCD->clientState == MINIMIZED_STATE)
  434. {
  435. /*
  436. * An icon no longer has the input focus.
  437. */
  438. ShowInactiveIcon (pCD, refresh);
  439. }
  440. if (bUnseen)
  441. pCD->clientState |= UNSEEN_STATE;
  442. /* restore old keyboard focus */
  443. wmGD.keyboardFocus = saveCD;
  444. } /* END OF FUNCTION ClearFocusIndication */
  445. /*************************************<->*************************************
  446. *
  447. * GetClientUnderPointer (pSameScreen)
  448. *
  449. *
  450. * Description:
  451. * -----------
  452. * This function identifies the managed client window or icon that is under
  453. * the pointer.
  454. *
  455. *
  456. * Outputs:
  457. * -------
  458. * pSameScreen = pointer to flag that indicates if pointer is on the wm screen
  459. *
  460. * Return = client data pointer for the client window / icon under the
  461. * mouse cursor
  462. *
  463. *************************************<->***********************************/
  464. ClientData *GetClientUnderPointer (Boolean *pSameScreen)
  465. {
  466. Window root;
  467. Window child;
  468. int rootX;
  469. int rootY;
  470. int winX;
  471. int winY;
  472. unsigned int mask;
  473. ClientData *pCD;
  474. if ((*pSameScreen = XQueryPointer (DISPLAY, ACTIVE_ROOT, &root, &child,
  475. &rootX, &rootY, &winX, &winY, &mask)) != False)
  476. {
  477. if (child &&
  478. !XFindContext (DISPLAY, child, wmGD.windowContextType,
  479. (caddr_t *)&pCD))
  480. {
  481. /*
  482. * There is a client window or icon under the pointer.
  483. */
  484. return (pCD);
  485. }
  486. }
  487. return (NULL);
  488. } /* END OF FUNCTION GetClientUnderPointer */
  489. /*************************************<->*************************************
  490. *
  491. * FocusNextWindow (type, focusTime)
  492. *
  493. *
  494. * Description:
  495. * -----------
  496. * This function is used to change the focus to the next window in the
  497. * window stacking order. The next focus window must be of the specified
  498. * type(s). If the focus traversal cannot be done because there is not
  499. * an object of the specified type (accepting focus) then don't change the
  500. * focus (!!!should the focus be unset in this case!!!).
  501. *
  502. *
  503. * Inputs:
  504. * ------
  505. * type = type of objects to change the focus to
  506. *
  507. * focusTime = timestamp to be used for setting the input focus
  508. *
  509. *************************************<->***********************************/
  510. Boolean FocusNextWindow (unsigned long type, Time focusTime)
  511. {
  512. ClientListEntry *pCurrentEntry;
  513. ClientListEntry *pNextEntry;
  514. Boolean focused = False;
  515. ClientData *pCD;
  516. /*
  517. * Identify the window or icon that currently has the focus and start
  518. * traversing to the next object.
  519. */
  520. if (type & F_GROUP_TRANSIENT)
  521. {
  522. /*
  523. * Move the keyboard input focus around in a transient tree.
  524. */
  525. focused = FocusNextTransient (wmGD.keyboardFocus, type, False,
  526. focusTime);
  527. }
  528. if (!focused)
  529. {
  530. if (wmGD.systemModalActive)
  531. {
  532. focused = True;
  533. }
  534. else if (wmGD.keyboardFocus)
  535. {
  536. if (wmGD.keyboardFocus->transientLeader)
  537. {
  538. pCD = FindTransientTreeLeader (wmGD.keyboardFocus);
  539. }
  540. else
  541. {
  542. pCD = wmGD.keyboardFocus;
  543. }
  544. if (pCD->clientState == MINIMIZED_STATE)
  545. {
  546. pCurrentEntry = &pCD->iconEntry;
  547. }
  548. else
  549. {
  550. pCurrentEntry = &pCD->clientEntry;
  551. }
  552. pNextEntry = pCurrentEntry->nextSibling;
  553. if (!pNextEntry)
  554. {
  555. pNextEntry = ACTIVE_PSD->clientList;
  556. }
  557. }
  558. else
  559. {
  560. pCurrentEntry = ACTIVE_PSD->clientList;
  561. pNextEntry = pCurrentEntry;
  562. }
  563. }
  564. while (!focused && pNextEntry)
  565. {
  566. focused = CheckForKeyFocus (pNextEntry, type, True /*next*/, focusTime);
  567. if (!focused)
  568. {
  569. pNextEntry = pNextEntry->nextSibling;
  570. }
  571. }
  572. if (!focused)
  573. {
  574. pNextEntry = ACTIVE_PSD->clientList;
  575. while ((pNextEntry != pCurrentEntry) && !focused)
  576. {
  577. focused = CheckForKeyFocus (pNextEntry, type, True/*next*/,
  578. focusTime);
  579. if (!focused)
  580. {
  581. pNextEntry = pNextEntry->nextSibling;
  582. }
  583. }
  584. }
  585. return (focused);
  586. } /* END OF FUNCTION FocusNextWindow */
  587. /*************************************<->*************************************
  588. *
  589. * FocusNextTransient (pCD, type, initiate, focusTime)
  590. *
  591. *
  592. * Description:
  593. * -----------
  594. * This function is used to determine if another window in a transient
  595. * tree should get the input focus.
  596. *
  597. * Inputs:
  598. * ------
  599. * pCD = pointer to the client data for the client window that has the focus
  600. *
  601. * type = type of objects to change the focus to
  602. *
  603. * initiate = set True if transient focus traversal is to be initiated;
  604. * set to False if transient focus traversal is to be continued
  605. *
  606. * focusTime = timestamp to be used to set the input focus
  607. *
  608. *
  609. * Outputs:
  610. * -------
  611. * RETURN = True if the focus window has been identified and the focus
  612. * has been set (or is already set)
  613. *
  614. *************************************<->***********************************/
  615. Boolean FocusNextTransient (ClientData *pCD, unsigned long type, Boolean initiate, Time focusTime)
  616. {
  617. Boolean focused = False;
  618. unsigned long startAt;
  619. ClientData *pcdLeader;
  620. ClientData *pcdLowerLeader;
  621. ClientData *pcdFocus;
  622. if (initiate && !(type & F_GROUP_TRANSIENT))
  623. {
  624. /*
  625. * If in a transient tree focus on the last transient window that
  626. * had the focus.
  627. */
  628. if (pCD->transientChildren)
  629. {
  630. pcdFocus = FindLastTransientTreeFocus (pCD, (ClientData *)NULL);
  631. if (pcdFocus != wmGD.keyboardFocus)
  632. {
  633. pcdLeader = FindTransientTreeLeader (pcdFocus);
  634. if (wmGD.keyboardFocus && wmGD.keyboardFocus->focusAutoRaise &&
  635. (wmGD.keyboardFocus != pcdLeader))
  636. {
  637. pcdLowerLeader =
  638. FindTransientTreeLeader (wmGD.keyboardFocus);
  639. if (pcdLowerLeader == pcdLeader)
  640. {
  641. if (PutTransientBelowSiblings (wmGD.keyboardFocus))
  642. {
  643. RestackTransients (pcdLeader);
  644. }
  645. }
  646. else
  647. {
  648. F_Lower (NULL, wmGD.keyboardFocus, (XEvent *) NULL);
  649. }
  650. }
  651. Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
  652. }
  653. focused = True;
  654. }
  655. else
  656. {
  657. focused = False;
  658. }
  659. }
  660. else if (pCD && (pCD->clientState != MINIMIZED_STATE) &&
  661. (pCD->transientLeader || pCD->transientChildren))
  662. {
  663. startAt = (initiate) ? (ACTIVE_PSD->clientCounter + 1) :
  664. pCD->clientID;
  665. pcdLeader = FindTransientTreeLeader (pCD);
  666. pcdFocus = FindNextTFocusInSeq (pcdLeader, startAt);
  667. if ((pcdFocus == NULL) && (type == F_GROUP_TRANSIENT))
  668. {
  669. /*
  670. * Wrap around and find a focus window.
  671. */
  672. pcdFocus = FindNextTFocusInSeq (pcdLeader,
  673. (unsigned long) (ACTIVE_PSD->clientCounter + 1));
  674. }
  675. if (pcdFocus)
  676. {
  677. if (pcdFocus != wmGD.keyboardFocus)
  678. {
  679. if (wmGD.keyboardFocus && wmGD.keyboardFocus->focusAutoRaise &&
  680. (wmGD.keyboardFocus != pcdLeader))
  681. {
  682. pcdLowerLeader =
  683. FindTransientTreeLeader (wmGD.keyboardFocus);
  684. if (pcdLowerLeader == pcdLeader)
  685. {
  686. if (PutTransientBelowSiblings (wmGD.keyboardFocus))
  687. {
  688. RestackTransients (pcdLeader);
  689. }
  690. }
  691. else
  692. {
  693. F_Lower (NULL, wmGD.keyboardFocus, (XEvent *)NULL);
  694. }
  695. }
  696. Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
  697. }
  698. focused = True;
  699. }
  700. }
  701. else
  702. {
  703. if (type == F_GROUP_TRANSIENT)
  704. {
  705. /*
  706. * Focus only within a transient tree. In this case the current
  707. * or prospective focus is not within a transient tree so leave
  708. * the focus where it is.
  709. */
  710. focused = True;
  711. }
  712. }
  713. return (focused);
  714. } /* END OF FUNCTION FocusNextTransient */
  715. /*************************************<->*************************************
  716. *
  717. * FindLastTransientTreeFocus (pCD, pcdNoFocus)
  718. *
  719. *
  720. * Description:
  721. * -----------
  722. * This function is used to scan a transient tree for the last window in
  723. * the tree that had the focus.
  724. *
  725. * Inputs:
  726. * ------
  727. * pCD = pointer to the client data for the transient tree (or subtree)
  728. * leader.
  729. *
  730. * pcdNoFocus = pointer to the client data for a client window that is not
  731. * to get the input focus (NULL if no client window restriction).
  732. *
  733. * Outputs:
  734. * -------
  735. * RETURN = pointer to the client data of the window that last had the
  736. * focus.
  737. *
  738. *************************************<->***********************************/
  739. ClientData *FindLastTransientTreeFocus (ClientData *pCD, ClientData *pcdNoFocus)
  740. {
  741. ClientData *pcdNext;
  742. ClientData *pcdFocus;
  743. ClientData *pcdLastFocus = NULL;
  744. pcdNext = pCD->transientChildren;
  745. while (pcdNext)
  746. {
  747. pcdFocus = FindLastTransientTreeFocus (pcdNext, pcdNoFocus);
  748. if (pcdFocus &&
  749. (!IS_APP_MODALIZED(pcdFocus)) &&
  750. ((pcdLastFocus == NULL) ||
  751. (pcdFocus->focusPriority > pcdLastFocus->focusPriority)))
  752. {
  753. pcdLastFocus = pcdFocus;
  754. }
  755. pcdNext = pcdNext->transientSiblings;
  756. }
  757. if ((!IS_APP_MODALIZED(pCD)) &&
  758. ((pcdLastFocus == NULL) ||
  759. (pCD->focusPriority > pcdLastFocus->focusPriority)))
  760. {
  761. pcdLastFocus = pCD;
  762. }
  763. return (pcdLastFocus);
  764. } /* END OF FUNCTION FindLastTransientTreeFocus */
  765. /*************************************<->*************************************
  766. *
  767. * FindNextTFocusInSeq (pCD, startAt)
  768. *
  769. *
  770. * Description:
  771. * -----------
  772. * This function is used to scan a transient tree for the next window that
  773. * can accept the focus.
  774. *
  775. * Inputs:
  776. * ------
  777. * pCD = pointer to the client data for the transient tree (or subtree)
  778. * leader.
  779. *
  780. * startAt = focus window should have a lower id then this client id
  781. *
  782. *
  783. * Outputs:
  784. * -------
  785. * RETURN = pointer to the client data of the window that should get the
  786. * focus.
  787. *
  788. *************************************<->***********************************/
  789. ClientData *FindNextTFocusInSeq (ClientData *pCD, unsigned long startAt)
  790. {
  791. ClientData *pcdNextFocus = NULL;
  792. ClientData *pcdNext;
  793. ClientData *pcdFocus;
  794. pcdNext = pCD->transientChildren;
  795. while (pcdNext)
  796. {
  797. pcdFocus = FindNextTFocusInSeq (pcdNext, startAt);
  798. if (pcdFocus)
  799. {
  800. if ((pcdNextFocus == NULL) ||
  801. (pcdFocus->clientID > pcdNextFocus->clientID))
  802. {
  803. pcdNextFocus = pcdFocus;
  804. }
  805. }
  806. pcdNext = pcdNext->transientSiblings;
  807. }
  808. if ((pcdNextFocus == NULL) ||
  809. (pCD->clientID > pcdNextFocus->clientID))
  810. {
  811. if ((!IS_APP_MODALIZED(pCD)) && (pCD->clientID < startAt))
  812. {
  813. pcdNextFocus = pCD;
  814. }
  815. }
  816. return (pcdNextFocus);
  817. } /* END OF FUNCTION FindNextTFocusInSeq */
  818. /*************************************<->*************************************
  819. *
  820. * FocusPrevWindow (type, focusTime)
  821. *
  822. *
  823. * Description:
  824. * -----------
  825. * This function is used to change the focus to the previous window in the
  826. * window stacking order. The next focus window must be of the specified
  827. * type(s). If the focus traversal cannot be done because there is not
  828. * an object of the specified type (accepting focus) then don't change the
  829. * focus (!!!should the focus be unset in this case!!!).
  830. *
  831. *
  832. * Inputs:
  833. * ------
  834. * type = type of objects to change the focus to
  835. *
  836. * focusTime = timestamp to be used to set the input focus
  837. *
  838. *************************************<->***********************************/
  839. Boolean FocusPrevWindow (unsigned long type, Time focusTime)
  840. {
  841. ClientListEntry *pCurrentEntry;
  842. ClientListEntry *pNextEntry;
  843. Boolean focused = False;
  844. ClientData *pCD;
  845. /*
  846. * Identify the window or icon that currently has the focus and start
  847. * traversing to the previous object.
  848. */
  849. if (type & F_GROUP_TRANSIENT)
  850. {
  851. /*
  852. * Move the keyboard input focus around in a transient tree.
  853. */
  854. focused = FocusPrevTransient (wmGD.keyboardFocus, type, False,
  855. focusTime);
  856. }
  857. if (!focused)
  858. {
  859. if (wmGD.systemModalActive)
  860. {
  861. focused = True;
  862. }
  863. else if (wmGD.keyboardFocus)
  864. {
  865. if (wmGD.keyboardFocus->transientLeader)
  866. {
  867. pCD = FindTransientTreeLeader (wmGD.keyboardFocus);
  868. }
  869. else
  870. {
  871. pCD = wmGD.keyboardFocus;
  872. }
  873. if (pCD->clientState == MINIMIZED_STATE)
  874. {
  875. pCurrentEntry = &pCD->iconEntry;
  876. }
  877. else
  878. {
  879. pCurrentEntry = &pCD->clientEntry;
  880. }
  881. pNextEntry = pCurrentEntry->prevSibling;
  882. if (!pNextEntry)
  883. {
  884. pNextEntry = ACTIVE_PSD->lastClient;
  885. }
  886. }
  887. else
  888. {
  889. pCurrentEntry = ACTIVE_PSD->lastClient;
  890. pNextEntry = pCurrentEntry;
  891. }
  892. }
  893. while (!focused && pNextEntry)
  894. {
  895. focused = CheckForKeyFocus (pNextEntry, type, False /*previous*/,
  896. focusTime);
  897. if (!focused)
  898. {
  899. pNextEntry = pNextEntry->prevSibling;
  900. }
  901. }
  902. if (!focused)
  903. {
  904. pNextEntry = ACTIVE_PSD->lastClient;
  905. while ((pNextEntry != pCurrentEntry) && !focused)
  906. {
  907. focused = CheckForKeyFocus (pNextEntry, type, False/*previous*/,
  908. focusTime);
  909. if (!focused)
  910. {
  911. pNextEntry = pNextEntry->prevSibling;
  912. }
  913. }
  914. }
  915. return (focused);
  916. } /* END OF FUNCTION FocusPrevWindow */
  917. /*************************************<->*************************************
  918. *
  919. * FocusPrevTransient (pCD, type, initiate, focusTime)
  920. *
  921. *
  922. * Description:
  923. * -----------
  924. * This function is used to determine if another (previous) window in a
  925. * transient tree should get the input focus.
  926. *
  927. * Inputs:
  928. * ------
  929. * pCD = pointer to the client data for the client window that has the focus
  930. *
  931. * type = type of objects to change the focus to
  932. *
  933. * initiate = set True if transient focus traversal is to be initiated;
  934. * set to False if transient focus traversal is to be continued
  935. *
  936. * focusTime = timestamp to be used to set the input focus
  937. *
  938. *
  939. * Outputs:
  940. * -------
  941. * RETURN = True if the focus window has been identified and the focus
  942. * has been set (or is already set)
  943. *
  944. *************************************<->***********************************/
  945. Boolean FocusPrevTransient (ClientData *pCD, unsigned long type, Boolean initiate, Time focusTime)
  946. {
  947. Boolean focused = False;
  948. unsigned long startAt;
  949. ClientData *pcdLeader;
  950. ClientData *pcdFocus;
  951. if (initiate && !(type & F_GROUP_TRANSIENT))
  952. {
  953. /*
  954. * If in a transient tree focus on the last transient window that
  955. * had the focus.
  956. */
  957. if (pCD->transientChildren)
  958. {
  959. pcdFocus = FindLastTransientTreeFocus (pCD, (ClientData *)NULL);
  960. if (pcdFocus != wmGD.keyboardFocus)
  961. {
  962. Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
  963. }
  964. focused = True;
  965. }
  966. else
  967. {
  968. focused = False;
  969. }
  970. }
  971. else if (pCD && (pCD->clientState != MINIMIZED_STATE) &&
  972. (pCD->transientLeader || pCD->transientChildren))
  973. {
  974. startAt = (initiate) ? 0 : pCD->clientID;
  975. pcdLeader = FindTransientTreeLeader (pCD);
  976. pcdFocus = FindPrevTFocusInSeq (pcdLeader, startAt);
  977. if ((pcdFocus == NULL) && (type == F_GROUP_TRANSIENT))
  978. {
  979. /*
  980. * Wrap around and find a focus window.
  981. */
  982. pcdFocus = FindPrevTFocusInSeq (pcdLeader, 0);
  983. }
  984. if (pcdFocus)
  985. {
  986. if (pcdFocus != wmGD.keyboardFocus)
  987. {
  988. Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
  989. }
  990. focused = True;
  991. }
  992. }
  993. else
  994. {
  995. if (type == F_GROUP_TRANSIENT)
  996. {
  997. /*
  998. * Focus only within a transient tree. In this case the current
  999. * or prospective focus is not within a transient tree so leave
  1000. * the focus where it is.
  1001. */
  1002. focused = True;
  1003. }
  1004. }
  1005. return (focused);
  1006. } /* END OF FUNCTION FocusPrevTransient */
  1007. /*************************************<->*************************************
  1008. *
  1009. * FindPrevTFocusInSeq (pCD, startAt)
  1010. *
  1011. *
  1012. * Description:
  1013. * -----------
  1014. * This function is used to scan a transient tree for the previous window that
  1015. * can accept the focus.
  1016. *
  1017. * Inputs:
  1018. * ------
  1019. * pCD = pointer to the client data for the transient tree (or subtree)
  1020. * leader.
  1021. *
  1022. * startAt = focus window should have a higher id then this client id
  1023. *
  1024. *
  1025. * Outputs:
  1026. * -------
  1027. * RETURN = pointer to the client data of the window that should get the
  1028. * focus.
  1029. *
  1030. *************************************<->***********************************/
  1031. ClientData *FindPrevTFocusInSeq (ClientData *pCD, unsigned long startAt)
  1032. {
  1033. ClientData *pcdNextFocus = NULL;
  1034. ClientData *pcdNext;
  1035. ClientData *pcdFocus;
  1036. pcdNext = pCD->transientChildren;
  1037. while (pcdNext)
  1038. {
  1039. pcdFocus = FindPrevTFocusInSeq (pcdNext, startAt);
  1040. if (pcdFocus)
  1041. {
  1042. if ((pcdNextFocus == NULL) ||
  1043. (pcdFocus->clientID < pcdNextFocus->clientID))
  1044. {
  1045. pcdNextFocus = pcdFocus;
  1046. }
  1047. }
  1048. pcdNext = pcdNext->transientSiblings;
  1049. }
  1050. if ((pcdNextFocus == NULL) ||
  1051. (pCD->clientID < pcdNextFocus->clientID))
  1052. {
  1053. if (!(IS_APP_MODALIZED(pCD)) && (pCD->clientID > startAt))
  1054. {
  1055. pcdNextFocus = pCD;
  1056. }
  1057. }
  1058. return (pcdNextFocus);
  1059. } /* END OF FUNCTION FindPrevTFocusInSeq */
  1060. /*************************************<->*************************************
  1061. *
  1062. * CheckForKeyFocus (pNextEntry, type, focusNext, focusTime)
  1063. *
  1064. *
  1065. * Description:
  1066. * -----------
  1067. * This function is used to determine if a window is a worthy candidate for
  1068. * getting the input focus (it is on-screen and is of the desired type).
  1069. * If it is, the window gets the keyboard input focus.
  1070. *
  1071. *
  1072. * Inputs:
  1073. * ------
  1074. * pNextEntry = the client list entry to be checked
  1075. *
  1076. * type = the desired type of the focus window
  1077. *
  1078. * focusNext = if true then focus the next window in the window stack
  1079. *
  1080. * focusTime = timestamp to be used to set the input focus
  1081. *
  1082. *
  1083. * Outputs:
  1084. * -------
  1085. * Return = True if the window gets the keyboard input focus otherwise False
  1086. *
  1087. *************************************<->***********************************/
  1088. Boolean CheckForKeyFocus (ClientListEntry *pNextEntry, unsigned long type, Boolean focusNext, Time focusTime)
  1089. {
  1090. ClientData *pCD = pNextEntry->pCD;
  1091. unsigned long windowType;
  1092. Boolean focused = False;
  1093. /*
  1094. * First check for focusing within a transient tree.
  1095. */
  1096. /*
  1097. * Make sure the window is being displayed and is of the specified type.
  1098. */
  1099. if (((pNextEntry->type == NORMAL_STATE) &&
  1100. (!(pCD->clientState & UNSEEN_STATE)) &&
  1101. (pCD->clientState != MINIMIZED_STATE)) ||
  1102. ((pNextEntry->type == MINIMIZED_STATE) &&
  1103. (pCD->clientState == MINIMIZED_STATE)))
  1104. {
  1105. if (pCD->clientState == MINIMIZED_STATE)
  1106. {
  1107. windowType = F_GROUP_ICON;
  1108. }
  1109. else
  1110. {
  1111. if (focusNext)
  1112. {
  1113. focused = FocusNextTransient (pCD, type, True, focusTime);
  1114. }
  1115. else
  1116. {
  1117. focused = FocusPrevTransient (pCD, type, True, focusTime);
  1118. }
  1119. windowType = F_GROUP_WINDOW;
  1120. if (pCD->transientLeader || pCD->transientChildren)
  1121. {
  1122. windowType |= F_GROUP_TRANSIENT;
  1123. }
  1124. }
  1125. if (!focused && (type & windowType))
  1126. {
  1127. focused = True;
  1128. if (focusNext && wmGD.keyboardFocus &&
  1129. wmGD.keyboardFocus->focusAutoRaise)
  1130. {
  1131. F_Lower (NULL, wmGD.keyboardFocus, (XEvent *)NULL);
  1132. }
  1133. Do_Focus_Key (pCD, focusTime, ALWAYS_SET_FOCUS);
  1134. }
  1135. }
  1136. return (focused);
  1137. } /* END OF FUNCTION CheckForKeyFocus */
  1138. /*************************************<->*************************************
  1139. *
  1140. * RepairFocus ()
  1141. *
  1142. *
  1143. * Description:
  1144. * -----------
  1145. * This function sets the keyboard and colormap focus to a client
  1146. * window or icon when the window manager is recovering from a
  1147. * configuration action.
  1148. *
  1149. *
  1150. * Inputs:
  1151. * ------
  1152. *
  1153. *
  1154. * Comments:
  1155. * --------
  1156. * o we only need to repair keyboard focus policy is "pointer"
  1157. *
  1158. *************************************<->***********************************/
  1159. void RepairFocus (void)
  1160. {
  1161. ClientData *pCD;
  1162. Boolean sameScreen;
  1163. XEvent event;
  1164. /*
  1165. * Repair the keyboard and colormap focus based on the policies
  1166. */
  1167. if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
  1168. (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER))
  1169. {
  1170. /*
  1171. * Move old enter and leave events and then get the window that
  1172. * the pointer is currently in.
  1173. */
  1174. XSync (DISPLAY, False);
  1175. while (XCheckMaskEvent (DISPLAY, EnterWindowMask | LeaveWindowMask,
  1176. &event))
  1177. {
  1178. }
  1179. pCD = GetClientUnderPointer (&sameScreen);
  1180. /*
  1181. * Set the keyboard focus to the window that currently contains the
  1182. * pointer.
  1183. */
  1184. if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
  1185. {
  1186. /*
  1187. * This will also set colormap focus if it is CMAP_FOCUS_KEYBOARD.
  1188. */
  1189. Do_Focus_Key (pCD, CurrentTime, ALWAYS_SET_FOCUS);
  1190. }
  1191. else if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
  1192. {
  1193. SetColormapFocus (ACTIVE_PSD, pCD);
  1194. }
  1195. }
  1196. } /* END OF FUNCTION RepairFocus */
  1197. /*************************************<->*************************************
  1198. *
  1199. * AutoResetKeyFocus (pcdFocus, focusTime)
  1200. *
  1201. *
  1202. * Description:
  1203. * -----------
  1204. * This function resets the keyboard input focus when a window with the
  1205. * focus is withdrawn or iconified. The focus is set to the last window
  1206. * that had the focus. The focus is not set to an icon.
  1207. *
  1208. *
  1209. * Inputs:
  1210. * ------
  1211. * pcdFocus = pointer to the client data of the window with the focus or
  1212. * the leader of the transient tree that contains the focus window;
  1213. * the focus should not be set to the pcdFocus window or subordinates.
  1214. *
  1215. * focusTime = timestamp to be used in setting the keyboard input focus.
  1216. *
  1217. *************************************<->***********************************/
  1218. void AutoResetKeyFocus (ClientData *pcdNoFocus, Time focusTime)
  1219. {
  1220. ClientListEntry *pNextEntry;
  1221. ClientData *pCD;
  1222. ClientData *pcdLastFocus = NULL;
  1223. ClientData *pcdFocus;
  1224. /*
  1225. * Scan through the list of clients to find a window to get the focus.
  1226. */
  1227. pNextEntry = ACTIVE_PSD->clientList;
  1228. while (pNextEntry)
  1229. {
  1230. pCD = pNextEntry->pCD;
  1231. if (!wmGD.systemModalActive ||
  1232. (wmGD.systemModalClient == pCD))
  1233. {
  1234. if ((pNextEntry->type != MINIMIZED_STATE) &&
  1235. (pCD->clientState != MINIMIZED_STATE) &&
  1236. (!(pCD->clientState & UNSEEN_STATE)) &&
  1237. (pCD != pcdNoFocus))
  1238. {
  1239. if (pCD->transientChildren)
  1240. {
  1241. pcdFocus = FindLastTransientTreeFocus (pCD, pcdNoFocus);
  1242. }
  1243. else
  1244. {
  1245. pcdFocus = pCD;
  1246. }
  1247. if (pcdFocus &&
  1248. ((pcdLastFocus == NULL) ||
  1249. (pcdFocus->focusPriority > pcdLastFocus->focusPriority)))
  1250. {
  1251. pcdLastFocus = pcdFocus;
  1252. }
  1253. }
  1254. }
  1255. pNextEntry = pNextEntry->nextSibling;
  1256. }
  1257. /*
  1258. * Set the focus if there is a window that is a good candidate for
  1259. * getting the focus.
  1260. */
  1261. if (pcdLastFocus)
  1262. {
  1263. Do_Focus_Key (pcdLastFocus, focusTime, ALWAYS_SET_FOCUS);
  1264. }
  1265. else
  1266. {
  1267. /*
  1268. * !!! Immediately set the focus indication !!!
  1269. */
  1270. Do_Focus_Key ((ClientData *)NULL, focusTime, ALWAYS_SET_FOCUS);
  1271. }
  1272. } /* END OF FUNCTION AutoResetKeyFocus */