Fix position of hidden panel, placed at screen edge with upper coordinate (usually...
[window-docker.git] / panel-int-mod.h
blobaadb52017b0880d37c7342fec5d06995f9a9e3b1
1 /** WARNING: This file is intended to be part of panel module only ;) */
3 #include <X11/Xlib.h>
4 #include <gdk/gdkx.h>
6 /**
7 * Internal helpers
8 */
9 /* {{{ */
11 static void panel_window_focus (PanelWindow * panel);
12 static void update_window_pos (PanelWindow * panel);
13 static int fix_border (PanelWindow * panel);
14 static void update_pos (PanelWindow * panel);
15 static gboolean show (PanelWindow * panel);
16 static gboolean hide (PanelWindow * panel);
17 static gboolean present (PanelWindow * panel);
18 static void set_Gravity (PanelWindow * panel);
20 static
21 void panel_window_focus (PanelWindow * panel)
23 #ifdef GDK_WINDOWING_X11
24 XClientMessageEvent event;
26 event.type = ClientMessage;
27 event.window = GDK_WINDOW_XID (GTK_WIDGET (panel->win)->window);
28 event.message_type = gdk_x11_get_xatom_by_name ("_NET_ACTIVE_WINDOW");
29 event.format = 32;
30 event.data.l[0] = 0;
32 gdk_error_trap_push ();
34 XSendEvent (GDK_DISPLAY (), GDK_ROOT_WINDOW (), False,
35 StructureNotifyMask, (XEvent *) &event);
37 gdk_flush ();
39 if (gdk_error_trap_pop () != 0)
40 g_critical ("Failed to focus panel window");
41 #endif
43 gtk_window_present (GTK_WINDOW (panel->win));
46 static
47 void update_window_pos (PanelWindow * panel)
49 if (panel->docking.visible)
50 gtk_window_move (GTK_WINDOW (panel->win), panel->pos.x, panel->pos.y);
51 else gtk_window_move (GTK_WINDOW (panel->win), panel->pos.hidden.x, panel->pos.hidden.y);
54 static
55 int fix_border (PanelWindow * panel)
57 switch (panel->docking.side) {
58 case SIDE_LEFT: return (panel->docking.border < panel->size.w) ? panel->docking.border : panel->size.w;
59 case SIDE_RIGHT: return (panel->docking.border < panel->size.w) ? panel->docking.border : panel->size.w;
60 case SIDE_TOP: return (panel->docking.border < panel->size.h) ? panel->docking.border : panel->size.h;
61 case SIDE_BOTTOM: return (panel->docking.border < panel->size.h) ? panel->docking.border : panel->size.h;
65 static inline
66 int docked_pos_to_pixels (int range, int len, double pos)
67 { return (range < len) ? 0 : (range - len) * pos; }
69 static
70 void update_pos (PanelWindow * panel)
72 g_print ("update_pos: ");
73 switch (panel->docking.side) {
74 case SIDE_NONE:
75 g_print ("side = NONE, ");
76 break;
78 case SIDE_LEFT:
79 panel->pos.x = 0;
80 panel->pos.y = docked_pos_to_pixels (panel->scr.h, panel->size.h, panel->docking.pos);
81 panel->pos.hidden.x = fix_border(panel) - panel->size.w;
82 panel->pos.hidden.y = panel->pos.y;
83 g_print ("side = LEFT, ");
84 break;
86 case SIDE_RIGHT:
87 panel->pos.x = panel->scr.w - panel->size.w;
88 panel->pos.y = docked_pos_to_pixels (panel->scr.h, panel->size.h, panel->docking.pos);
89 panel->pos.hidden.x = panel->scr.w - fix_border(panel);
90 panel->pos.hidden.y = panel->pos.y;
91 g_print ("side = RIGHT, ");
92 break;
94 case SIDE_TOP:
95 panel->pos.y = 0;
96 panel->pos.x = docked_pos_to_pixels (panel->scr.w, panel->size.w, panel->docking.pos);
97 panel->pos.hidden.y = fix_border(panel) - panel->size.h;
98 panel->pos.hidden.x = panel->pos.x;
99 g_print ("side = TOP, ");
100 break;
102 case SIDE_BOTTOM:
103 panel->pos.y = panel->scr.h - panel->size.h;
104 panel->pos.x = docked_pos_to_pixels (panel->scr.w, panel->size.w, panel->docking.pos);
105 panel->pos.hidden.y = panel->scr.h - fix_border(panel);
106 panel->pos.hidden.x = panel->pos.x;
107 g_print ("side = BOTTOM, ");
108 break;
110 default: g_print ("Unknown side, ");
112 g_print ("scr.W = %i, scr.H = %i, size = %i, pos = %f, X = %i, Y = %i, hidden_X = %i, hidden_Y = %i, border = %i\n",
113 panel->scr.w, panel->scr.h,
114 panel->size.w, panel->docking.pos,
115 panel->pos.x, panel->pos.y,
116 panel->pos.hidden.x, panel->pos.hidden.y,
117 fix_border (panel));
120 static
121 gboolean show (PanelWindow * panel)
123 panel->docking.visible = TRUE;
124 update_window_pos (panel);
125 return FALSE;
128 static
129 gboolean hide (PanelWindow * panel)
131 panel->docking.visible = FALSE;
132 update_window_pos (panel);
133 return FALSE;
136 static
137 gboolean present (PanelWindow * panel)
139 show (panel);
140 panel_window_focus (panel);
141 if (! gtk_window_is_active (GTK_WINDOW (panel->win)) )
142 g_print ("Failed to get focus\n");
143 return FALSE;
146 static
147 void set_Gravity (PanelWindow * panel)
149 switch (panel->docking.side)
151 case SIDE_NONE: break;
152 case SIDE_LEFT: gtk_window_set_gravity (GTK_WINDOW (panel->win), GDK_GRAVITY_WEST); break;
153 case SIDE_RIGHT: gtk_window_set_gravity (GTK_WINDOW (panel->win), GDK_GRAVITY_EAST); break;
154 case SIDE_TOP: gtk_window_set_gravity (GTK_WINDOW (panel->win), GDK_GRAVITY_NORTH); break;
155 case SIDE_BOTTOM: gtk_window_set_gravity (GTK_WINDOW (panel->win), GDK_GRAVITY_SOUTH); break;
159 /* Internal helpers */
160 /* }}} */
163 * Callbacks
165 /* {{{ */
167 static
168 void on_resize (GtkWidget * w, GtkAllocation * size, gpointer data)
170 if (PANEL_WINDOW (data)->size.request) {
171 PANEL_WINDOW (data)->size.request = FALSE;
172 g_signal_handler_unblock (G_OBJECT (PANEL_WINDOW (data)->win), PANEL_WINDOW (data)->enter_cb_id);
173 g_signal_handler_unblock (G_OBJECT (PANEL_WINDOW (data)->win), PANEL_WINDOW (data)->leave_cb_id);
176 PANEL_WINDOW (data)->size.w = size->width;
177 PANEL_WINDOW (data)->size.h = size->height;
179 if (PANEL_WINDOW (data)->docking.side != SIDE_NONE)
181 update_pos (PANEL_WINDOW (data));
182 update_window_pos (PANEL_WINDOW (data));
186 static
187 void on_size_request (GtkWidget * w, GtkRequisition * size, gpointer data)
189 if (! PANEL_WINDOW (data)->size.request) {
190 PANEL_WINDOW (data)->size.request = TRUE;
191 g_signal_handler_block (G_OBJECT (PANEL_WINDOW (data)->win), PANEL_WINDOW (data)->enter_cb_id);
192 g_signal_handler_block (G_OBJECT (PANEL_WINDOW (data)->win), PANEL_WINDOW (data)->leave_cb_id);
197 * Auto-hiding
199 /* {{{ */
201 static
202 void slide_canceled (gpointer data)
203 { PANEL_WINDOW (data)->docking.timeout.id = 0; }
205 static
206 gboolean on_enter (GtkWidget * w, GdkEventCrossing * ev, gpointer data)
208 //if (PANEL_WINDOW (data)->size.request) return FALSE;
210 /* Filter dublicate crossing for the same direction */
211 if (! PANEL_WINDOW (data)->docking.visible) {
213 /* If panel is already in necessary state, but has to change from it,... */
214 if (PANEL_WINDOW (data)->docking.timeout.id)
215 /* just stop timer */
216 g_source_remove (PANEL_WINDOW (data)->docking.timeout.id);
218 else {
219 gpointer func;
220 if (PANEL_WINDOW (data)->docking.autohiding)
221 func = present;
222 else func = panel_window_focus, PANEL_WINDOW (data)->docking.visible = TRUE;
224 PANEL_WINDOW (data)->docking.timeout.id = g_timeout_add_full (
225 G_PRIORITY_DEFAULT,
226 PANEL_WINDOW (data)->docking.timeout.show,
227 (GSourceFunc) func, data, slide_canceled );
232 static
233 gboolean on_leave (GtkWidget * w, GdkEventCrossing * ev, gpointer data)
235 /* Prevent misoperation on internal crossments */
236 if (ev->detail == GDK_NOTIFY_INFERIOR) return FALSE;
238 /* And on mis-crossing, possible on resizing */
239 //if (PANEL_WINDOW (data)->size.request) return FALSE;
241 /* Like in 'on_enter_slide ()' */
242 if (PANEL_WINDOW (data)->docking.visible) {
243 if (PANEL_WINDOW (data)->docking.timeout.id)
244 g_source_remove (PANEL_WINDOW (data)->docking.timeout.id);
245 else {
246 if (PANEL_WINDOW (data)->docking.autohiding)
247 PANEL_WINDOW (data)->docking.timeout.id = g_timeout_add_full (
248 G_PRIORITY_DEFAULT,
249 PANEL_WINDOW (data)->docking.timeout.hide,
250 (GSourceFunc) hide, data, slide_canceled );
251 else
252 PANEL_WINDOW (data)->docking.visible = FALSE;
257 /* Auto-hiding */
258 /* }}} */
260 /* Callbacks */
261 /* }}} */